summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Norbye <tnorbye@google.com>2014-09-18 13:38:58 -0700
committerTor Norbye <tnorbye@google.com>2014-09-18 13:38:58 -0700
commitb5fb31ef6a38f19404859755dbd2e345215b97bf (patch)
treee8787c45e494dfcc558faf0f75956f8785c39b94
parente222a9e1e66670a56e926a6b0f3e10231eeeb1fb (diff)
parente782c57d74000722f9db4c9426317410520670c6 (diff)
downloadidea-b5fb31ef6a38f19404859755dbd2e345215b97bf.tar.gz
Merge remote-tracking branch 'aosp/upstream-master' into merge
Conflicts: .idea/libraries/asm_tools.xml .idea/libraries/bouncy_castle.xml .idea/libraries/builder_model.xml .idea/libraries/commons_compress.xml .idea/libraries/easymock_tools.xml .idea/libraries/freemarker_2_3_20.xml .idea/libraries/guava_tools.xml .idea/libraries/kxml2.xml .idea/libraries/lombok_ast.xml .idea/libraries/mockito.xml .idea/modules.xml .idea/vcs.xml build/scripts/layouts.gant updater/src/com/intellij/updater/Runner.java Change-Id: I8e1c173e00cd76c855b8a98543b0a0edfdd99d12
-rw-r--r--.gitignore1
-rw-r--r--.idea/libraries/JSch.xml6
-rw-r--r--.idea/libraries/guava_tools.xml4
-rw-r--r--.idea/libraries/javawriter.xml11
-rw-r--r--.idea/libraries/winp.xml5
-rw-r--r--.idea/modules.xml2
-rw-r--r--bin/WinLauncher/WinLauncher.exebin822784 -> 822784 bytes
-rw-r--r--bin/WinLauncher/WinLauncher64.exebin839168 -> 839168 bytes
-rwxr-xr-xbin/scripts/unix/idea.sh2
-rw-r--r--build/conf/mac/Contents/Info.plist2
-rwxr-xr-xbuild/conf/mac/Contents/MacOS/ideabin85564 -> 85588 bytes
-rw-r--r--build/scripts/dist.gant2
-rw-r--r--build/scripts/layouts.gant9
-rw-r--r--build/scripts/libLicenses.gant5
-rw-r--r--community-tests/src/tests/testGroups.properties3
-rw-r--r--getPlugins.bat2
-rwxr-xr-xgetPlugins.sh2
-rw-r--r--images/src/org/intellij/images/editor/impl/ImageEditorUI.java53
-rw-r--r--images/src/org/intellij/images/options/impl/OptionsManagerImpl.java7
-rw-r--r--java/compiler/impl/compiler-impl.iml1
-rw-r--r--java/compiler/impl/src/com/intellij/compiler/actions/CompileAction.java2
-rw-r--r--java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java26
-rw-r--r--java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactFromModulesDialog.form4
-rw-r--r--java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactFromModulesDialog.java2
-rw-r--r--java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactType.java2
-rw-r--r--java/compiler/impl/src/com/intellij/packaging/impl/elements/PackagingElementFactoryImpl.java2
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/DebugUIEnvironment.java3
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/DefaultDebugUIEnvironment.java19
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/actions/AdjustArrayRangeAction.java54
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/actions/DebuggerAction.java20
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/actions/JavaMarkObjectActionHandler.java7
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/actions/JavaReferringObjectsValue.java1
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/actions/ObjectMarkupPropertiesDialog.java5
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/actions/PopFrameAction.java213
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/actions/ViewAsGroup.java11
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java42
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java93
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/engine/JVMNameUtil.java21
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/engine/JavaDebugProcess.java56
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/engine/JavaDebuggerEvaluator.java6
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/engine/JavaStaticGroup.java8
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java13
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/engine/JavaValueModifier.java12
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/engine/evaluation/EvaluationContextImpl.java8
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/EvaluatorBuilderImpl.java78
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/MethodEvaluator.java8
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/NewClassInstanceEvaluator.java6
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/UnsupportedExpressionException.java (renamed from platform/platform-impl/src/com/intellij/openapi/components/impl/stores/RoamingTypeExtensionPointBean.java)19
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/impl/DebuggerContextUtil.java7
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/impl/DebuggerManagerImpl.java3
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/impl/DebuggerSession.java38
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsEx.java23
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/impl/JavaEditorTextProviderImpl.java11
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/impl/PositionUtil.java1
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/settings/DebuggerDataViewsConfigurable.java31
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/settings/DebuggerSettings.java8
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/settings/DebuggerSteppingConfigurable.java51
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/ui/DebuggerEditorImpl.java2
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/ui/DebuggerSessionTab.java28
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/ui/EvaluationDialog.java9
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/ui/JavaDebuggerSupport.java8
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/ui/ValueHint.java3
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ArgumentValueDescriptorImpl.java5
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/CompilingEvaluator.java210
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/EvaluationDescriptor.java92
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/NodeDescriptorFactoryImpl.java9
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/NodeManagerImpl.java8
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/UserExpressionDescriptorImpl.java10
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/WatchItemDescriptor.java7
-rw-r--r--java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ArrayRenderer.java12
-rw-r--r--java/debugger/impl/src/org/jetbrains/java/debugger/JavaDebuggerEditorsProvider.java17
-rw-r--r--java/debugger/openapi/src/com/intellij/debugger/SourcePosition.java4
-rw-r--r--java/debugger/openapi/src/com/intellij/debugger/engine/DebugProcess.java17
-rw-r--r--java/debugger/openapi/src/com/intellij/debugger/engine/JSR45PositionManager.java7
-rw-r--r--java/execution/impl/src/com/intellij/execution/actions/JavaRerunFailedTestsAction.java7
-rw-r--r--java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java46
-rw-r--r--java/execution/impl/src/com/intellij/execution/application/BaseJavaApplicationCommandLineState.java70
-rw-r--r--java/execution/impl/src/com/intellij/execution/impl/DefaultJavaProgramRunner.java12
-rw-r--r--java/execution/impl/src/com/intellij/execution/jar/JarApplicationCommandLineState.java43
-rw-r--r--java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurable.form49
-rw-r--r--java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurable.java93
-rw-r--r--java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfiguration.java223
-rw-r--r--java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurationProducer.java63
-rw-r--r--java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurationType.java54
-rw-r--r--java/execution/impl/src/com/intellij/execution/jar/JarApplicationDebuggerRunner.java37
-rw-r--r--java/execution/impl/src/com/intellij/execution/junit/InheritorChooser.java8
-rw-r--r--java/execution/impl/src/com/intellij/execution/runners/ProcessProxyFactoryImpl.java7
-rw-r--r--java/execution/impl/src/com/intellij/execution/util/JavaParametersUtil.java3
-rw-r--r--java/execution/openapi/src/com/intellij/execution/configurations/CommandLineBuilder.java2
-rw-r--r--java/idea-ui/src/com/intellij/facet/impl/ui/libraries/LibraryOptionsPanel.form2
-rw-r--r--java/idea-ui/src/com/intellij/facet/impl/ui/libraries/LibraryOptionsPanel.java2
-rw-r--r--java/idea-ui/src/com/intellij/ide/RecentProjectsManager.java15
-rw-r--r--java/idea-ui/src/com/intellij/ide/actions/ImportModuleAction.java2
-rw-r--r--java/idea-ui/src/com/intellij/ide/palette/impl/PaletteManager.java229
-rw-r--r--java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.form9
-rw-r--r--java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.java59
-rw-r--r--java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JavaResourceRootEditHandler.java5
-rw-r--r--java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModuleEditor.java4
-rw-r--r--java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectStructureConfigurable.java4
-rw-r--r--java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/libraryEditor/DefaultLibraryRootsComponentDescriptor.java39
-rw-r--r--java/java-analysis-api/src/com/intellij/openapi/roots/LanguageLevelModuleExtension.java3
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInsight/InferredAnnotationsManagerImpl.java10
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java2
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInspection/RedundantLambdaCodeBlockInspection.java31
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Analysis.java8
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisConverter.java27
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisIndex.java2
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/ClassDataIndexer.java129
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Combined.java335
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Contracts.java7
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Data.java200
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/NullableMethodAnalysis.java423
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Parameters.java3
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/ProjectBytecodeAnalysis.java84
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Solver.java6
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/AnalyzerExt.java446
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/FramelessAnalyzer.java46
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/InterpreterExt.java32
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/LeakingParameters.java9
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/LiteAnalyzerExt.java222
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/LiteFramelessAnalyzer.java6
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/Subroutine.java74
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInference.java41
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java4
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java4
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaExpressionFactory.java4
-rw-r--r--java/java-analysis-impl/src/com/intellij/codeInspection/equalsAndHashcode/EqualsAndHashcodeBase.java (renamed from java/java-analysis-impl/src/com/intellij/codeInspection/equalsAndHashcode/EqualsAndHashcode.java)17
-rw-r--r--java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java28
-rw-r--r--java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsLineMarkerProvider.java11
-rw-r--r--java/java-impl/src/com/intellij/codeInsight/TailTypes.java6
-rw-r--r--java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java2
-rw-r--r--java/java-impl/src/com/intellij/codeInsight/completion/JavaDocCompletionContributor.java11
-rw-r--r--java/java-impl/src/com/intellij/codeInsight/completion/PreferByKindWeigher.java6
-rw-r--r--java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ChangeMethodSignatureFromUsageFix.java6
-rw-r--r--java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateMethodFromUsageFix.java2
-rw-r--r--java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateStaticMethodQuickFix.java81
-rw-r--r--java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MoveClassToModuleFix.java4
-rw-r--r--java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithTryFinallySurrounder.java16
-rw-r--r--java/java-impl/src/com/intellij/codeInsight/highlighting/HighlightExceptionsHandlerFactory.java5
-rw-r--r--java/java-impl/src/com/intellij/codeInsight/intention/impl/AddAnnotationIntention.java11
-rw-r--r--java/java-impl/src/com/intellij/codeInspection/equalsAndHashcode/EqualsAndHashcode.java72
-rw-r--r--java/java-impl/src/com/intellij/codeInspection/inferNullity/InferNullityAnnotationsAction.java2
-rw-r--r--java/java-impl/src/com/intellij/find/findUsages/JavaFindUsagesHandler.java207
-rw-r--r--java/java-impl/src/com/intellij/ide/JavaLanguageCodeStyleSettingsProvider.java92
-rw-r--r--java/java-impl/src/com/intellij/ide/actions/CreatePackageInfoAction.java4
-rw-r--r--java/java-impl/src/com/intellij/ide/projectView/impl/ClassesTreeStructureProvider.java5
-rw-r--r--java/java-impl/src/com/intellij/ide/util/scopeChooser/ClassHierarchyScopeDescriptor.java30
-rw-r--r--java/java-impl/src/com/intellij/jarFinder/FindJarFix.java4
-rw-r--r--java/java-impl/src/com/intellij/openapi/projectRoots/impl/JavaAwareProjectJdkTableImpl.java13
-rw-r--r--java/java-impl/src/com/intellij/openapi/roots/impl/LanguageLevelProjectExtensionImpl.java4
-rw-r--r--java/java-impl/src/com/intellij/psi/codeStyle/JavaCodeStyleSettings.java1
-rw-r--r--java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java2
-rw-r--r--java/java-impl/src/com/intellij/psi/formatter/java/wrap/impl/JavaChildWrapArranger.java26
-rw-r--r--java/java-impl/src/com/intellij/psi/impl/file/PsiPackageImplementationHelperImpl.java52
-rw-r--r--java/java-impl/src/com/intellij/refactoring/extractMethod/AbstractExtractDialog.java23
-rw-r--r--java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodDialog.java5
-rw-r--r--java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java69
-rw-r--r--java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractLightMethodObjectHandler.java254
-rw-r--r--java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectDialog.java5
-rw-r--r--java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectHandler.java47
-rw-r--r--java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectProcessor.java66
-rw-r--r--java/java-impl/src/com/intellij/refactoring/inheritanceToDelegation/InheritanceToDelegationDialog.java2
-rw-r--r--java/java-impl/src/com/intellij/refactoring/inheritanceToDelegation/InheritanceToDelegationHandler.java14
-rw-r--r--java/java-impl/src/com/intellij/refactoring/util/RefactoringUtil.java13
-rw-r--r--java/java-indexing-api/src/com/intellij/psi/search/searches/ClassInheritorsSearch.java14
-rw-r--r--java/java-psi-api/src/com/intellij/psi/GenericsUtil.java4
-rw-r--r--java/java-psi-api/src/com/intellij/psi/LambdaUtil.java11
-rw-r--r--java/java-psi-api/src/com/intellij/psi/PsiPackage.java4
-rw-r--r--java/java-psi-api/src/com/intellij/psi/util/ClassUtil.java30
-rw-r--r--java/java-psi-api/src/com/intellij/psi/util/MethodSignatureBase.java1
-rw-r--r--java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java5
-rw-r--r--java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilderBase.java5
-rw-r--r--java/java-psi-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java44
-rw-r--r--java/java-psi-impl/src/com/intellij/core/CorePsiPackageImplementationHelper.java18
-rw-r--r--java/java-psi-impl/src/com/intellij/psi/NonClasspathClassFinder.java2
-rw-r--r--java/java-psi-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java2
-rw-r--r--java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsFileImpl.java27
-rw-r--r--java/java-psi-impl/src/com/intellij/psi/impl/file/PsiPackageImpl.java21
-rw-r--r--java/java-psi-impl/src/com/intellij/psi/impl/file/PsiPackageImplementationHelper.java18
-rw-r--r--java/java-psi-impl/src/com/intellij/psi/impl/source/PsiFieldImpl.java11
-rw-r--r--java/java-psi-impl/src/com/intellij/psi/impl/source/PsiParameterImpl.java20
-rw-r--r--java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/PsiResolveHelperImpl.java13
-rw-r--r--java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java213
-rw-r--r--java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceVariable.java21
-rw-r--r--java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/LambdaExpressionCompatibilityConstraint.java6
-rw-r--r--java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java6
-rw-r--r--java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/StrictSubtypingConstraint.java18
-rw-r--r--java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLambdaExpressionImpl.java58
-rw-r--r--java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java5
-rw-r--r--java/java-tests/testData/codeInsight/completion/smartType/NoSemicolonInsideParentheses-out.java7
-rw-r--r--java/java-tests/testData/codeInsight/completion/smartType/NoSemicolonInsideParentheses.java7
-rw-r--r--java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/CaptureWildcardFromUnboundCaptureWildcard.java9
-rw-r--r--java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA106985.java15
-rw-r--r--java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA114797.java15
-rw-r--r--java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/constraints/IntersectionTypeStrictSubtypingConstraint.java15
-rw-r--r--java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/FreshVariablesCreatedDuringResolveDependingOnAlreadyResolvedVariables.java17
-rw-r--r--java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/IncompatibleBoundsFromAssignment.java15
-rw-r--r--java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/Ambiguity1.java2
-rw-r--r--java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguityRawGenerics.java2
-rw-r--r--java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/EffectiveFinal.java34
-rw-r--r--java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/mostSpecific/NoReturnTypeResolutionForThrownException.java2
-rw-r--r--java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/DeepNestedLambdaExpressionsNoFormalParams.java70
-rw-r--r--java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IDEA126778.java27
-rw-r--r--java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/NestedLambdaExpressions1.java27
-rw-r--r--java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/NestedLambdaExpressionsNoFormalParams.java55
-rw-r--r--java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/NestedLambdaExpressionsNoFormalParams1.java26
-rw-r--r--java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/NestedLambdaExpressionsNoFormalParamsStopAtStandalone.java32
-rw-r--r--java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/ParenthesizedExpressionsDuringConstrainsCollection.java13
-rw-r--r--java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/IDEA127275_.java2
-rw-r--r--java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/overloadResolution/IDEA102800.java31
-rw-r--r--java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/overloadResolution/PertinentToApplicabilityOfExplicitlyTypedLambda.java17
-rw-r--r--java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/overloadResolution/VoidValueCompatibilityOfImplicitlyTypedLambda.java23
-rw-r--r--java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/changeMethodSignatureFromUsage8/afterDisjunctionType.java15
-rw-r--r--java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/changeMethodSignatureFromUsage8/beforeDisjunctionType.java15
-rw-r--r--java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambdaCodeBlock2Expr/afterVoidValueChangedNoConflict.java16
-rw-r--r--java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambdaCodeBlock2Expr/beforeVoidValueChanged.java19
-rw-r--r--java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambdaCodeBlock2Expr/beforeVoidValueChangedNoConflict.java18
-rw-r--r--java/java-tests/testData/codeInsight/generation/surroundWith/java/SurroundWithTryFinallyUsingIndents.java5
-rw-r--r--java/java-tests/testData/codeInsight/generation/surroundWith/java/SurroundWithTryFinallyUsingIndents_after.java9
-rw-r--r--java/java-tests/testData/codeInsight/javadocIG/clickableFieldReference.html3
-rw-r--r--java/java-tests/testData/codeInsight/javadocIG/clickableFieldReference.java7
-rw-r--r--java/java-tests/testData/codeInsight/javadocIG/enumConstantOrdinal.html5
-rw-r--r--java/java-tests/testData/codeInsight/javadocIG/enumConstantOrdinal_quick.html3
-rw-r--r--java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/awt/annotations.xml98
-rw-r--r--java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/beans/beancontext/annotations.xml7
-rw-r--r--java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/io/annotations.xml51
-rw-r--r--java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/lang/annotations.xml102
-rw-r--r--java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/lang/invoke/annotations.xml154
-rw-r--r--java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/net/annotations.xml64
-rw-r--r--java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/security/annotations.xml18
-rw-r--r--java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/sql/annotations.xml9
-rw-r--r--java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/util/annotations.xml86
-rw-r--r--java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/util/concurrent/locks/annotations.xml18
-rw-r--r--java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/javax/swing/annotations.xml88
-rw-r--r--java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/collections/annotations.xml19
-rw-r--r--java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/collections/map/annotations.xml27
-rw-r--r--java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/lang/annotations.xml256
-rw-r--r--java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/lang/enum/annotations.xml12
-rw-r--r--java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/lang/enums/annotations.xml12
-rw-r--r--java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/lang/exception/annotations.xml21
-rw-r--r--java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/lang/math/annotations.xml7
-rw-r--r--java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/lang/text/annotations.xml29
-rw-r--r--java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/lang/time/annotations.xml4
-rw-r--r--java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/annotations.xml3
-rw-r--r--java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/app/annotations.xml3
-rw-r--r--java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/app/event/annotations.xml6
-rw-r--r--java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/app/event/implement/annotations.xml17
-rw-r--r--java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/context/annotations.xml12
-rw-r--r--java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/io/annotations.xml3
-rw-r--r--java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/runtime/annotations.xml22
-rw-r--r--java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/runtime/directive/annotations.xml15
-rw-r--r--java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/runtime/parser/node/annotations.xml45
-rw-r--r--java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/runtime/resource/annotations.xml12
-rw-r--r--java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/runtime/resource/loader/annotations.xml6
-rw-r--r--java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/util/annotations.xml15
-rw-r--r--java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/util/introspection/annotations.xml34
-rw-r--r--java/java-tests/testData/inspection/dataFlow/fixture/RootThrowableCause.java17
-rw-r--r--java/java-tests/testData/refactoring/extractMethodObject4Debugger/AnonymousClassParams.java8
-rw-r--r--java/java-tests/testData/refactoring/extractMethodObject4Debugger/InnerClass.java30
-rw-r--r--java/java-tests/testData/refactoring/extractMethodObject4Debugger/InvokeReturnType.java9
-rw-r--r--java/java-tests/testData/refactoring/extractMethodObject4Debugger/OffsetsAtCallSite.java44
-rw-r--r--java/java-tests/testData/refactoring/extractMethodObject4Debugger/ResultExpr.java25
-rw-r--r--java/java-tests/testData/refactoring/extractMethodObject4Debugger/ResultStatements.java25
-rw-r--r--java/java-tests/testData/refactoring/extractMethodObject4Debugger/SimpleGeneration.java5
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartType18CompletionTest.java18
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java2
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java3
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/ConstraintsInferenceMiscTest.java6
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/Diamond8HighlightingTest.java4
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/ExceptionVariablesInferenceTest.java4
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/FunctionalExpressionIncompleteHighlightingTest.java2
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/FunctionalTypeWildcardParameterizationTest.java2
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GenericsHighlighting8Test.java16
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java12
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaHighlightingTest.java2
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaInferenceTest.java4
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaParamsTest.java4
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaRedundantCastTest.java4
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LightAdvHighlightingJdk8Test.java3
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/MethodRefHighlightingTest.java4
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/MostSpecificResolutionTest.java2
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java32
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewMethodRefHighlightingTest.java6
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/OverloadResolutionTest.java63
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy6
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInsight/generation/surroundWith/JavaSurroundWithTest.java14
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInsight/javadoc/JavaDocInfoGeneratorTest.java32
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInsight/template/LiveTemplateTest.groovy44
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInspection/ContractInferenceFromSourceTest.groovy39
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java3
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisIntegrationTest.java34
-rw-r--r--java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisTest.java5
-rw-r--r--java/java-tests/testSrc/com/intellij/execution/configurations/JavaCommandLineTest.java11
-rw-r--r--java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterWrapTest.java31
-rw-r--r--java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodObject4DebuggerTest.java179
-rw-r--r--java/java-tests/testSrc/com/intellij/refactoring/IntroduceVariableTest.java18
-rw-r--r--java/openapi/src/com/intellij/execution/filters/ExceptionWorker.java23
-rw-r--r--java/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/deployment/debug/JavaDebuggerLauncherImpl.java5
-rw-r--r--java/structuralsearch-java/src/com/intellij/structuralsearch/JavaReplaceHandler.java12
-rw-r--r--java/testFramework/src/com/intellij/codeInsight/daemon/LightDaemonAnalyzerTestCase.java17
-rw-r--r--java/testFramework/src/com/intellij/compiler/CompilerTestUtil.java20
-rw-r--r--java/testFramework/src/com/intellij/debugger/DebuggerTestCase.java33
-rw-r--r--java/testFramework/src/com/intellij/debugger/ExecutionWithDebuggerToolsTestCase.java16
-rw-r--r--java/testFramework/src/com/intellij/testFramework/CompilerTester.java42
-rw-r--r--java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ChangeClassParametersIntention.java4
-rw-r--r--jps/jps-builders/jps-builders.iml2
-rw-r--r--jps/jps-builders/src/org/jetbrains/jps/api/GlobalOptions.java1
-rw-r--r--jps/jps-builders/src/org/jetbrains/jps/cmdline/BuildMain.java3
-rw-r--r--jps/jps-builders/src/org/jetbrains/jps/cmdline/ClasspathBootstrap.java72
-rw-r--r--jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java18
-rw-r--r--jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/impl/JarsBuilder.java2
-rw-r--r--jps/jps-builders/src/org/jetbrains/jps/incremental/java/ExternalJavacDescriptor.java36
-rw-r--r--jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java149
-rw-r--r--jps/jps-builders/src/org/jetbrains/jps/javac/ExternalJavacMessageHandler.java230
-rw-r--r--jps/jps-builders/src/org/jetbrains/jps/javac/ExternalJavacProcess.java (renamed from jps/jps-builders/src/org/jetbrains/jps/javac/JavacServer.java)318
-rw-r--r--jps/jps-builders/src/org/jetbrains/jps/javac/ExternalJavacServer.java310
-rw-r--r--jps/jps-builders/src/org/jetbrains/jps/javac/JavacServerBootstrap.java109
-rw-r--r--jps/jps-builders/src/org/jetbrains/jps/javac/JavacServerClient.java78
-rw-r--r--jps/jps-builders/src/org/jetbrains/jps/javac/JavacServerResponseHandler.java231
-rw-r--r--jps/model-api/src/org/jetbrains/jps/model/java/LanguageLevel.java2
-rw-r--r--lib/jsch-0.1.50.jarbin249317 -> 0 bytes
-rw-r--r--lib/jsch-0.1.51.jarbin0 -> 260010 bytes
-rw-r--r--lib/required_for_dist.txt4
-rw-r--r--lib/src/ecjsrc-4.3.2.jarbin1451984 -> 0 bytes
-rw-r--r--lib/src/jsch-0.1.50.zipbin351616 -> 0 bytes
-rw-r--r--lib/src/jsch-0.1.51.zipbin0 -> 359905 bytes
-rw-r--r--lib/src/winp-1.17-patched-src.zipbin17906 -> 0 bytes
-rw-r--r--lib/src/winp-1.21-patched.zipbin0 -> 44830 bytes
-rw-r--r--lib/src/winp.patch26
-rw-r--r--lib/winp-1.17-patched.jarbin27960 -> 0 bytes
-rw-r--r--lib/winp-1.21-patched.jarbin0 -> 27809 bytes
-rw-r--r--native/MacLauncher/Launcher.m4
-rw-r--r--native/WinLauncher/WinLauncher/WinLauncher.cpp15
-rw-r--r--platform/analysis-api/src/com/intellij/psi/search/scope/packageSet/FilePatternPackageSet.java6
-rw-r--r--platform/analysis-impl/src/com/intellij/codeHighlighting/TextEditorHighlightingPass.java1
-rw-r--r--platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/UpdateHighlightersUtil.java4
-rw-r--r--platform/analysis-impl/src/com/intellij/codeInspection/InspectionEngine.java3
-rw-r--r--platform/analysis-impl/src/com/intellij/codeInspection/ex/InspectionProfileImpl.java13
-rw-r--r--platform/analysis-impl/src/com/intellij/codeInspection/ex/ToolsImpl.java23
-rw-r--r--platform/core-api/src/com/intellij/concurrency/AsyncUtil.java46
-rw-r--r--platform/core-api/src/com/intellij/concurrency/DefaultResultConsumer.java8
-rw-r--r--platform/core-api/src/com/intellij/concurrency/DoWhile.java59
-rw-r--r--platform/core-api/src/com/intellij/concurrency/Iterate.java36
-rw-r--r--platform/core-api/src/com/intellij/concurrency/ResultConsumer.java6
-rw-r--r--platform/core-api/src/com/intellij/lang/folding/CustomFoldingBuilder.java4
-rw-r--r--platform/core-api/src/com/intellij/openapi/components/RoamingType.java9
-rw-r--r--platform/core-api/src/com/intellij/openapi/options/SchemeProcessor.java6
-rw-r--r--platform/core-api/src/com/intellij/openapi/options/SchemesManagerFactory.java5
-rw-r--r--platform/core-api/src/com/intellij/openapi/progress/ProgressManager.java1
-rw-r--r--platform/core-api/src/com/intellij/openapi/vfs/ex/http/HttpFileSystem.java9
-rw-r--r--platform/core-api/src/com/intellij/psi/util/CachedValuesManager.java7
-rw-r--r--platform/core-api/src/com/intellij/util/AbstractQuery.java23
-rw-r--r--platform/core-api/src/com/intellij/util/ArrayQuery.java11
-rw-r--r--platform/core-api/src/com/intellij/util/CollectionQuery.java13
-rw-r--r--platform/core-api/src/com/intellij/util/EmptyQuery.java6
-rw-r--r--platform/core-api/src/com/intellij/util/MergeQuery.java17
-rw-r--r--platform/core-impl/src/com/intellij/core/CoreApplicationEnvironment.java15
-rw-r--r--platform/core-impl/src/com/intellij/ide/plugins/IdeaPluginDescriptorImpl.java172
-rw-r--r--platform/core-impl/src/com/intellij/mock/MockComponentManager.java3
-rw-r--r--platform/core-impl/src/com/intellij/openapi/util/JDOMExternalizableAdapter.java2
-rw-r--r--platform/core-impl/src/com/intellij/openapi/vfs/impl/http/HttpVirtualFile.java2
-rw-r--r--platform/core-impl/src/com/intellij/psi/MultiplePsiFilesPerDocumentFileViewProvider.java3
-rw-r--r--platform/core-impl/src/com/intellij/psi/SingleRootFileViewProvider.java16
-rw-r--r--platform/core-impl/src/com/intellij/psi/impl/file/impl/FileManagerImpl.java1
-rw-r--r--platform/core-impl/src/com/intellij/psi/impl/source/tree/CompositeElement.java4
-rw-r--r--platform/core-impl/src/com/intellij/psi/impl/source/tree/FileElement.java2
-rw-r--r--platform/core-impl/src/com/intellij/refactoring/rename/FragmentaryPsiReference.java21
-rw-r--r--platform/core-impl/src/com/intellij/util/CachedValuesManagerImpl.java4
-rw-r--r--platform/dvcs-api/src/com/intellij/dvcs/push/PushSupport.java26
-rw-r--r--platform/dvcs-api/src/com/intellij/dvcs/push/PushTarget.java6
-rw-r--r--platform/dvcs-api/src/com/intellij/dvcs/push/PushTargetPanel.java (renamed from python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyNewProject.java)28
-rw-r--r--platform/dvcs-api/src/com/intellij/dvcs/push/VcsError.java2
-rw-r--r--platform/dvcs-api/src/com/intellij/dvcs/repo/Repository.java11
-rw-r--r--platform/dvcs-impl/src/com/intellij/dvcs/DvcsCommitAdditionalComponent.java7
-rw-r--r--platform/dvcs-impl/src/com/intellij/dvcs/branch/DvcsBranchPopup.java174
-rw-r--r--platform/dvcs-impl/src/com/intellij/dvcs/branch/DvcsBranchSync.java (renamed from plugins/git4idea/src/git4idea/ui/branch/GitBranchSyncSetting.java)9
-rw-r--r--platform/dvcs-impl/src/com/intellij/dvcs/branch/DvcsMultiRootBranchConfig.java71
-rw-r--r--platform/dvcs-impl/src/com/intellij/dvcs/branch/DvcsSyncBranchSettings.java25
-rw-r--r--platform/dvcs-impl/src/com/intellij/dvcs/push/PushController.java131
-rw-r--r--platform/dvcs-impl/src/com/intellij/dvcs/push/RepositoryNodeListener.java4
-rw-r--r--platform/dvcs-impl/src/com/intellij/dvcs/push/ui/EditableTreeNode.java10
-rw-r--r--platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java87
-rw-r--r--platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryNode.java50
-rw-r--r--platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryWithBranchPanel.java85
-rw-r--r--platform/dvcs-impl/src/com/intellij/dvcs/push/ui/SingleRepositoryNode.java13
-rw-r--r--platform/dvcs-impl/src/com/intellij/dvcs/push/ui/VcsBranchEditorListener.java4
-rw-r--r--platform/dvcs-impl/src/com/intellij/dvcs/repo/RepositoryUtil.java13
-rw-r--r--platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.java1
-rw-r--r--platform/editor-ui-api/src/com/intellij/openapi/actionSystem/AnAction.java4
-rw-r--r--platform/editor-ui-ex/src/com/intellij/psi/impl/cache/impl/id/PlatformIdTableBuilding.java23
-rw-r--r--platform/editor-ui-ex/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java27
-rw-r--r--platform/external-system-api/src/com/intellij/openapi/externalSystem/model/DefaultExternalSourceDirectorySet.java11
-rw-r--r--platform/external-system-api/src/com/intellij/openapi/externalSystem/model/ExternalSourceDirectorySet.java6
-rw-r--r--platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/LibraryDataService.java2
-rw-r--r--platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/AbstractExternalSystemTest.groovy35
-rw-r--r--platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/ExternalSystemImportingTestCase.java8
-rw-r--r--platform/icons/src/debugger/commandLine.pngbin0 -> 210 bytes
-rw-r--r--platform/icons/src/debugger/commandLine@2x.pngbin0 -> 534 bytes
-rw-r--r--platform/indexing-api/src/com/intellij/lang/cacheBuilder/DefaultWordsScanner.java2
-rw-r--r--platform/indexing-api/src/com/intellij/lang/cacheBuilder/SimpleWordsScanner.java2
-rw-r--r--platform/indexing-api/src/com/intellij/lang/cacheBuilder/VersionedWordsScanner.java22
-rw-r--r--platform/indexing-api/src/com/intellij/psi/search/PsiSearchHelper.java3
-rw-r--r--platform/indexing-api/src/com/intellij/psi/search/searches/DefinitionsScopedSearch.java9
-rw-r--r--platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/FileTypeIdIndexer.java3
-rw-r--r--platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndex.java2
-rw-r--r--platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/IdTableBuilding.java5
-rw-r--r--platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/todo/LexerBasedTodoIndexer.java4
-rw-r--r--platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/todo/VersionedTodoIndexer.java25
-rw-r--r--platform/indexing-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java350
-rw-r--r--platform/lang-api/src/com/intellij/diagnostic/logging/AdditionalTabComponent.java4
-rw-r--r--platform/lang-api/src/com/intellij/execution/DefaultExecutionResult.java11
-rw-r--r--platform/lang-api/src/com/intellij/execution/ExecutionResult.java1
-rw-r--r--platform/lang-api/src/com/intellij/execution/configurations/AdditionalTabComponentManager.java9
-rw-r--r--platform/lang-api/src/com/intellij/execution/configurations/LogFileOptions.java65
-rw-r--r--platform/lang-api/src/com/intellij/execution/configurations/ModuleRunProfile.java2
-rw-r--r--platform/lang-api/src/com/intellij/execution/configurations/RunConfigurationBase.java3
-rw-r--r--platform/lang-api/src/com/intellij/execution/configurations/RunConfigurationsSettings.java3
-rw-r--r--platform/lang-api/src/com/intellij/execution/configurations/SearchScopeProvider.java4
-rw-r--r--platform/lang-api/src/com/intellij/execution/configurations/SearchScopeProvidingRunProfile.java34
-rw-r--r--platform/lang-api/src/com/intellij/execution/configurations/SimpleJavaParameters.java10
-rw-r--r--platform/lang-api/src/com/intellij/execution/filters/ConsoleDependentFilterProvider.java32
-rw-r--r--platform/lang-api/src/com/intellij/execution/runners/AsyncGenericProgramRunner.java13
-rw-r--r--platform/lang-api/src/com/intellij/execution/runners/ExecutionUtil.java4
-rw-r--r--platform/lang-api/src/com/intellij/execution/ui/RunContentDescriptor.java21
-rw-r--r--platform/lang-api/src/com/intellij/find/FindModel.java4
-rw-r--r--platform/lang-api/src/com/intellij/ide/util/projectWizard/ModuleBuilder.java67
-rw-r--r--platform/lang-api/src/com/intellij/lang/documentation/DocumentationProviderEx.java1
-rw-r--r--platform/lang-api/src/com/intellij/openapi/projectRoots/JdkUtil.java12
-rw-r--r--platform/lang-api/src/com/intellij/openapi/projectRoots/ui/PathEditor.java8
-rw-r--r--platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettingsCustomizable.java1
-rw-r--r--platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java65
-rw-r--r--platform/lang-api/src/com/intellij/psi/codeStyle/autodetect/IndentOptionsDetector.java106
-rw-r--r--platform/lang-api/src/com/intellij/psi/codeStyle/autodetect/IndentUsageInfo.java39
-rw-r--r--platform/lang-api/src/com/intellij/psi/codeStyle/autodetect/IndentUsageStatistics.java30
-rw-r--r--platform/lang-api/src/com/intellij/psi/codeStyle/autodetect/IndentUsageStatisticsImpl.java149
-rw-r--r--platform/lang-api/src/com/intellij/psi/codeStyle/autodetect/LineIndentInfo.java56
-rw-r--r--platform/lang-api/src/com/intellij/psi/codeStyle/autodetect/LineIndentInfoBuilder.java80
-rw-r--r--platform/lang-api/src/com/intellij/psi/util/PsiUtilBase.java5
-rw-r--r--platform/lang-impl/src/com/intellij/analysis/BaseAnalysisAction.java2
-rw-r--r--platform/lang-impl/src/com/intellij/application/options/CodeStyleSchemesConfigurable.java5
-rw-r--r--platform/lang-impl/src/com/intellij/application/options/ModuleListCellRenderer.java13
-rw-r--r--platform/lang-impl/src/com/intellij/application/options/ModulesComboBox.java10
-rw-r--r--platform/lang-impl/src/com/intellij/application/options/codeStyle/ManageCodeStyleSchemesDialog.java2
-rw-r--r--platform/lang-impl/src/com/intellij/application/options/codeStyle/WrappingAndBracesPanel.java1
-rw-r--r--platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/AbstractArrangementRuleAction.java43
-rw-r--r--platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/AbstractMoveArrangementRuleAction.java12
-rw-r--r--platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/AddArrangementRuleAction.java4
-rw-r--r--platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/EditArrangementRuleAction.java7
-rw-r--r--platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/RemoveArrangementRuleAction.java2
-rw-r--r--platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/group/ArrangementGroupingRulesControl.java19
-rw-r--r--platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/ArrangementMatchingRulesControl.java47
-rw-r--r--platform/lang-impl/src/com/intellij/application/options/editor/EditorTabsConfigurable.form2
-rw-r--r--platform/lang-impl/src/com/intellij/application/options/editor/EditorTabsConfigurable.java25
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/actions/FormatChangedTextUtil.java30
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatCodeProcessor.java18
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java43
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java7
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java6
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PassExecutorService.java15
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java5
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java2
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/documentation/QuickDocUtil.java64
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/hint/actions/ShowImplementationsAction.java25
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/intention/impl/QuickEditHandler.java19
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/template/impl/EditVariableDialog.java9
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateListPanel.java12
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateSettings.java13
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java9
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/ElseExpressionPostfixTemplateBase.java3
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/IfPostfixTemplateBase.java3
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/PostfixLiveTemplate.java7
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/StatementWrapPostfixTemplate.java3
-rw-r--r--platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/SurroundPostfixTemplateBase.java3
-rw-r--r--platform/lang-impl/src/com/intellij/codeInspection/actions/GotoInspectionModel.java55
-rw-r--r--platform/lang-impl/src/com/intellij/codeInspection/actions/InspectionListCellRenderer.java80
-rw-r--r--platform/lang-impl/src/com/intellij/codeInspection/actions/ViewOfflineResultsAction.java2
-rw-r--r--platform/lang-impl/src/com/intellij/diagnostic/logging/DebuggerLogConsoleManager.java1
-rw-r--r--platform/lang-impl/src/com/intellij/diagnostic/logging/LogConfigurationPanel.java37
-rw-r--r--platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleBase.java1
-rw-r--r--platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleImpl.java34
-rw-r--r--platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleManager.java16
-rw-r--r--platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleManagerBase.java96
-rw-r--r--platform/lang-impl/src/com/intellij/diagnostic/logging/LogFilesManager.java133
-rw-r--r--platform/lang-impl/src/com/intellij/execution/actions/RunConfigurationsComboBoxAction.java2
-rw-r--r--platform/lang-impl/src/com/intellij/execution/actions/StopAction.java7
-rw-r--r--platform/lang-impl/src/com/intellij/execution/console/ConsoleExecuteAction.java29
-rw-r--r--platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleBuilder.java23
-rw-r--r--platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java5
-rw-r--r--platform/lang-impl/src/com/intellij/execution/console/UseConsoleInputAction.java56
-rw-r--r--platform/lang-impl/src/com/intellij/execution/impl/BeforeRunStepsPanel.java6
-rw-r--r--platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java13
-rw-r--r--platform/lang-impl/src/com/intellij/execution/impl/RunConfigurable.java12
-rw-r--r--platform/lang-impl/src/com/intellij/execution/runners/RunContentBuilder.java53
-rw-r--r--platform/lang-impl/src/com/intellij/execution/runners/RunTab.java74
-rw-r--r--platform/lang-impl/src/com/intellij/execution/ui/CommonProgramParametersPanel.java7
-rw-r--r--platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java8
-rw-r--r--platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToFind.java6
-rw-r--r--platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToReplace.java4
-rw-r--r--platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleRegex.java6
-rw-r--r--platform/lang-impl/src/com/intellij/find/impl/FindInProjectTask.java15
-rw-r--r--platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java12
-rw-r--r--platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreview.java34
-rw-r--r--platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewController.java7
-rw-r--r--platform/lang-impl/src/com/intellij/ide/RecentDirectoryProjectsManagerEx.java6
-rw-r--r--platform/lang-impl/src/com/intellij/ide/actions/ExternalJavaDocAction.java2
-rw-r--r--platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java2
-rw-r--r--platform/lang-impl/src/com/intellij/ide/actions/GotoActionBase.java10
-rw-r--r--platform/lang-impl/src/com/intellij/ide/hierarchy/actions/BrowseCallHierarchyAction.java2
-rw-r--r--platform/lang-impl/src/com/intellij/ide/hierarchy/actions/BrowseMethodHierarchyAction.java2
-rw-r--r--platform/lang-impl/src/com/intellij/ide/hierarchy/actions/BrowseTypeHierarchyAction.java2
-rw-r--r--platform/lang-impl/src/com/intellij/ide/impl/convert/JDomConvertingUtil.java4
-rw-r--r--platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarListener.java24
-rw-r--r--platform/lang-impl/src/com/intellij/ide/navigationToolbar/ui/AbstractNavBarUI.java4
-rw-r--r--platform/lang-impl/src/com/intellij/ide/scratch/CreateScratchFileAction.java3
-rw-r--r--platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java3
-rw-r--r--platform/lang-impl/src/com/intellij/ide/util/scopeChooser/ScopeChooserCombo.java28
-rw-r--r--platform/lang-impl/src/com/intellij/ide/util/scopeChooser/ScopeChooserConfigurable.java2
-rw-r--r--platform/lang-impl/src/com/intellij/lang/customFolding/CustomFoldingRegionsPopup.java133
-rw-r--r--platform/lang-impl/src/com/intellij/lang/customFolding/GotoCustomRegionAction.java96
-rw-r--r--platform/lang-impl/src/com/intellij/lang/customFolding/GotoCustomRegionDialog.form25
-rw-r--r--platform/lang-impl/src/com/intellij/lang/customFolding/GotoCustomRegionDialog.java169
-rw-r--r--platform/lang-impl/src/com/intellij/openapi/components/impl/stores/ModuleStoreImpl.java36
-rw-r--r--platform/lang-impl/src/com/intellij/openapi/components/impl/stores/ProjectWithModulesStoreImpl.java13
-rw-r--r--platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/PsiAwareFileEditorManagerImpl.java7
-rw-r--r--platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/TestEditorManagerImpl.java14
-rw-r--r--platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/ProjectJdkTableImpl.java8
-rw-r--r--platform/lang-impl/src/com/intellij/openapi/roots/impl/libraries/ExportableApplicationLibraryTable.java5
-rw-r--r--platform/lang-impl/src/com/intellij/openapi/roots/impl/storage/ClasspathStorage.java25
-rw-r--r--platform/lang-impl/src/com/intellij/openapi/roots/libraries/ui/impl/RootDetectionUtil.java8
-rw-r--r--platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ModulesAlphaComparator.java7
-rw-r--r--platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ProjectSdksModel.java16
-rw-r--r--platform/lang-impl/src/com/intellij/openapi/util/registry/RegistryUi.java3
-rw-r--r--platform/lang-impl/src/com/intellij/openapi/wm/impl/status/TogglePopupHintsPanel.java10
-rw-r--r--platform/lang-impl/src/com/intellij/platform/templates/github/DownloadUtil.java3
-rw-r--r--platform/lang-impl/src/com/intellij/profile/codeInspection/InspectionProfileManagerImpl.java8
-rw-r--r--platform/lang-impl/src/com/intellij/profile/codeInspection/ui/LevelChooser.java102
-rw-r--r--platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java3
-rw-r--r--platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/InspectionsConfigTreeTable.java2
-rw-r--r--platform/lang-impl/src/com/intellij/profile/codeInspection/ui/table/ScopesAndSeveritiesTable.java5
-rw-r--r--platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndexImpl.java29
-rw-r--r--platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleSchemeImpl.java5
-rw-r--r--platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleSchemesImpl.java3
-rw-r--r--platform/lang-impl/src/com/intellij/psi/search/scope/packageSet/PackageSetFactoryImpl.java3
-rw-r--r--platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java8
-rw-r--r--platform/lang-impl/src/com/intellij/refactoring/actions/RefactoringQuickListPopupAction.java3
-rw-r--r--platform/lang-impl/src/com/intellij/refactoring/rename/RenameUtil.java13
-rw-r--r--platform/lang-impl/src/com/intellij/tools/BaseExternalToolsGroup.java2
-rw-r--r--platform/lang-impl/src/com/intellij/tools/ToolsProcessor.java5
-rw-r--r--platform/lang-impl/src/com/intellij/ui/ReplacePromptDialog.java1
-rw-r--r--platform/lang-impl/src/com/intellij/ui/tabs/EditorTabColorProviderImpl.java5
-rw-r--r--platform/lang-impl/src/com/intellij/util/download/impl/FileDownloaderImpl.java12
-rw-r--r--platform/lang-impl/src/com/intellij/util/indexing/ValueContainerImpl.java4
-rw-r--r--platform/lang-impl/src/com/intellij/util/indexing/containers/ChangeBufferingList.java78
-rw-r--r--platform/platform-api/src/com/intellij/execution/util/ExecUtil.java60
-rw-r--r--platform/platform-api/src/com/intellij/ide/BrowserUtil.java5
-rw-r--r--platform/platform-api/src/com/intellij/ide/actions/ContextHelpAction.java2
-rw-r--r--platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java4
-rw-r--r--platform/platform-api/src/com/intellij/ide/util/treeView/UpdaterTreeState.java5
-rw-r--r--platform/platform-api/src/com/intellij/notification/Notification.java3
-rw-r--r--platform/platform-api/src/com/intellij/notification/NotificationGroup.java6
-rw-r--r--platform/platform-api/src/com/intellij/notification/NotificationListener.java4
-rw-r--r--platform/platform-api/src/com/intellij/openapi/actionSystem/ActionPlaces.java8
-rw-r--r--platform/platform-api/src/com/intellij/openapi/actionSystem/Separator.java5
-rw-r--r--platform/platform-api/src/com/intellij/openapi/actionSystem/ex/CheckboxAction.java20
-rw-r--r--platform/platform-api/src/com/intellij/openapi/actionSystem/ex/ComboBoxAction.java8
-rw-r--r--platform/platform-api/src/com/intellij/openapi/application/ApplicationStarterEx.java7
-rw-r--r--platform/platform-api/src/com/intellij/openapi/diagnostic/ErrorReportSubmitter.java54
-rw-r--r--platform/platform-api/src/com/intellij/openapi/diagnostic/SubmittedReportInfo.java25
-rw-r--r--platform/platform-api/src/com/intellij/openapi/fileChooser/FileChooser.java2
-rw-r--r--platform/platform-api/src/com/intellij/openapi/fileChooser/FileChooserDialog.java17
-rw-r--r--platform/platform-api/src/com/intellij/openapi/fileEditor/FileEditorManager.java2
-rw-r--r--platform/platform-api/src/com/intellij/openapi/options/ConfigurableEP.java18
-rw-r--r--platform/platform-api/src/com/intellij/openapi/options/ConfigurableProvider.java11
-rw-r--r--platform/platform-api/src/com/intellij/openapi/options/CurrentUserHolder.java1
-rw-r--r--platform/platform-api/src/com/intellij/openapi/options/SearchableConfigurable.java6
-rw-r--r--platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java11
-rw-r--r--platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java20
-rw-r--r--platform/platform-api/src/com/intellij/openapi/ui/Messages.java52
-rw-r--r--platform/platform-api/src/com/intellij/openapi/ui/popup/util/BaseListPopupStep.java30
-rw-r--r--platform/platform-api/src/com/intellij/openapi/vfs/newvfs/FileAttribute.java30
-rw-r--r--platform/platform-api/src/com/intellij/ui/CollectionListModel.java1
-rw-r--r--platform/platform-api/src/com/intellij/ui/SimpleColoredText.java8
-rw-r--r--platform/platform-api/src/com/intellij/ui/components/labels/LinkLabel.java2
-rw-r--r--platform/platform-api/src/com/intellij/ui/table/JBTable.java2
-rw-r--r--platform/platform-api/src/com/intellij/ui/treeStructure/Tree.java14
-rw-r--r--platform/platform-api/src/com/intellij/util/concurrency/QueueProcessor.java4
-rw-r--r--platform/platform-api/src/com/intellij/util/net/HttpConfigurable.java16
-rw-r--r--platform/platform-api/src/com/intellij/util/net/ssl/CertificateUtil.java64
-rw-r--r--platform/platform-api/src/com/intellij/util/ui/Animator.java10
-rw-r--r--platform/platform-impl/platform-impl.iml1
-rw-r--r--platform/platform-impl/src/com/intellij/concurrency/JobLauncherImpl.java12
-rw-r--r--platform/platform-impl/src/com/intellij/designer/DesignerEditorPanelFacade.java29
-rw-r--r--platform/platform-impl/src/com/intellij/designer/LightFillLayout.java122
-rw-r--r--platform/platform-impl/src/com/intellij/designer/LightToolWindow.java (renamed from plugins/ui-designer-core/src/com/intellij/designer/LightToolWindow.java)33
-rw-r--r--platform/platform-impl/src/com/intellij/designer/LightToolWindowContent.java (renamed from plugins/ui-designer-core/src/com/intellij/designer/LightToolWindowContent.java)0
-rw-r--r--platform/platform-impl/src/com/intellij/designer/LightToolWindowManager.java323
-rw-r--r--platform/platform-impl/src/com/intellij/designer/ToggleEditorModeAction.java (renamed from plugins/ui-designer-core/src/com/intellij/designer/ToggleEditorModeAction.java)17
-rw-r--r--platform/platform-impl/src/com/intellij/diagnostic/ITNReporter.java118
-rw-r--r--platform/platform-impl/src/com/intellij/diagnostic/IdeErrorsDialog.java94
-rw-r--r--platform/platform-impl/src/com/intellij/diagnostic/SubmitPerformanceReportAction.java175
-rw-r--r--platform/platform-impl/src/com/intellij/errorreport/ErrorReportSender.java98
-rw-r--r--platform/platform-impl/src/com/intellij/errorreport/bean/ErrorBean.java11
-rw-r--r--platform/platform-impl/src/com/intellij/errorreport/itn/ITNProxy.java326
-rw-r--r--platform/platform-impl/src/com/intellij/featureStatistics/FeatureUsageTrackerImpl.java13
-rw-r--r--platform/platform-impl/src/com/intellij/ide/ApplicationLoadListener.java3
-rw-r--r--platform/platform-impl/src/com/intellij/ide/CommandLineProcessor.java2
-rw-r--r--platform/platform-impl/src/com/intellij/ide/RecentDirectoryProjectsManager.java8
-rw-r--r--platform/platform-impl/src/com/intellij/ide/RecentProjectsManagerBase.java11
-rw-r--r--platform/platform-impl/src/com/intellij/ide/actions/AboutAction.java3
-rw-r--r--platform/platform-impl/src/com/intellij/ide/actions/AssociateFileType.java2
-rw-r--r--platform/platform-impl/src/com/intellij/ide/actions/BaseShowRecentFilesAction.java15
-rw-r--r--platform/platform-impl/src/com/intellij/ide/actions/CreateLauncherScriptAction.java4
-rw-r--r--platform/platform-impl/src/com/intellij/ide/actions/ExitAction.java3
-rw-r--r--platform/platform-impl/src/com/intellij/ide/actions/OccurenceNavigatorActionBase.java4
-rw-r--r--platform/platform-impl/src/com/intellij/ide/actions/PinActiveTabAction.java17
-rw-r--r--platform/platform-impl/src/com/intellij/ide/actions/ShowRecentFilesAction.java5
-rw-r--r--platform/platform-impl/src/com/intellij/ide/actions/ShowSettingsAction.java2
-rw-r--r--platform/platform-impl/src/com/intellij/ide/actions/ShowSettingsUtilImpl.java2
-rw-r--r--platform/platform-impl/src/com/intellij/ide/actions/SplitAction.java3
-rw-r--r--platform/platform-impl/src/com/intellij/ide/actions/Switcher.java83
-rw-r--r--platform/platform-impl/src/com/intellij/ide/customize/CustomizeIDEWizardDialog.java14
-rw-r--r--platform/platform-impl/src/com/intellij/ide/dnd/aware/DnDAwareTree.java3
-rw-r--r--platform/platform-impl/src/com/intellij/ide/passwordSafe/impl/providers/masterKey/MasterKeyPasswordSafe.java2
-rw-r--r--platform/platform-impl/src/com/intellij/ide/plugins/PluginManager.java1
-rw-r--r--platform/platform-impl/src/com/intellij/ide/ui/AppearanceConfigurable.java6
-rw-r--r--platform/platform-impl/src/com/intellij/ide/ui/AppearancePanel.form8
-rw-r--r--platform/platform-impl/src/com/intellij/ide/ui/laf/LafManagerImpl.java5
-rw-r--r--platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.properties1
-rw-r--r--platform/platform-impl/src/com/intellij/ide/ui/search/SearchUtil.java88
-rw-r--r--platform/platform-impl/src/com/intellij/ide/util/ProjectPropertiesComponentImpl.java8
-rw-r--r--platform/platform-impl/src/com/intellij/internal/statistic/UsageTrigger.java9
-rw-r--r--platform/platform-impl/src/com/intellij/internal/statistic/persistence/ApplicationStatisticsPersistenceComponent.java6
-rw-r--r--platform/platform-impl/src/com/intellij/internal/statistic/persistence/UsageStatisticsPersistenceComponent.java6
-rw-r--r--platform/platform-impl/src/com/intellij/notification/impl/ui/NotificationsConfigurablePanel.java3
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/actionSystem/ComputableActionGroup.java7
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/actionSystem/ex/QuickListsManager.java4
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/AbbreviationManagerImpl.java6
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionManagerImpl.java75
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ChameleonAction.java32
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/Utils.java26
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/application/PluginPathManager.java44
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java4
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ApplicationStoreImpl.java8
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/components/impl/stores/BaseFileConfigurableStoreImpl.java12
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ComponentStoreImpl.java36
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/components/impl/stores/CompoundSaveSession.java10
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DefaultProjectStoreImpl.java44
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DefaultsStateStorage.java4
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DirectoryBasedStorage.java95
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/components/impl/stores/FileBasedStorage.java134
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/components/impl/stores/IApplicationStore.java10
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/components/impl/stores/IComponentStore.java12
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/components/impl/stores/OldStreamProviderAdapter.java6
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ProjectStateStorageManager.java13
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ProjectStoreImpl.java126
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManager.java20
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java129
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StorageUtil.java214
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StreamProvider.java6
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java304
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/diff/ApplicationStarterBase.java20
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/diff/DiffApplication.java7
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/diff/MergeApplication.java11
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/editor/actions/ScrollToTheEndToolbarAction.java2
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/editor/colors/impl/EditorColorsManagerImpl.java4
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java7
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/editor/impl/LazyRangeMarkerFactoryImpl.java2
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/editor/impl/SelectionModelImpl.java12
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/fileChooser/ex/FileChooserDialogImpl.java23
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/fileEditor/ex/FileEditorManagerEx.java1
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorComposite.java4
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorEmptyTextPainter.java7
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorHistoryManager.java4
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorTabColorProvider.java5
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorTabbedContainer.java4
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorWindow.java15
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorWindowHolder.java5
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorsSplitters.java57
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java69
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/IdeDocumentHistoryImpl.java32
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/PreviewPanel.java403
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/http/HttpFileEditor.java7
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/http/HttpFileEditorProvider.java2
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/http/RemoteFilePanel.java1
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeManagerImpl.java6
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeKeyEventDispatcher.java17
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/keymap/impl/KeymapManagerImpl.java10
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/options/SchemesManagerFactoryImpl.java63
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/options/SchemesManagerImpl.java78
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/options/ex/ConfigurableExtensionPointUtil.java17
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/options/ex/ConfigurableVisitor.java144
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/options/ex/ConfigurableWrapper.java20
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/options/ex/MixedConfigurableGroup.java178
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/options/ex/NodeConfigurable.java77
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/options/ex/SortedConfigurableGroup.java195
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/options/newEditor/IdeSettingsDialog.java44
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsEditor.java19
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsTree.java12
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsTreeView.java305
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java3
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java5
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java7
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/ui/popup/MultiSelectionListPopupStep.java10
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/CheckForUpdateAction.java3
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/NoUpdatesPanel.form1
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/vfs/ex/dummy/DummyCachingFileSystem.java29
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VfsRootAccess.java4
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecords.java67
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java4
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/wm/impl/CommandProcessor.java5
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/wm/impl/InternalDecorator.java201
-rw-r--r--platform/platform-impl/src/com/intellij/openapi/wm/impl/WindowManagerImpl.java1
-rw-r--r--platform/platform-impl/src/com/intellij/ui/TableExpandableItemsHandler.java6
-rw-r--r--platform/platform-impl/src/com/intellij/ui/content/impl/ContentManagerImpl.java10
-rw-r--r--platform/platform-impl/src/com/intellij/ui/docking/impl/DockManagerImpl.java7
-rw-r--r--platform/platform-impl/src/com/intellij/ui/messages/JBMacMessages.java2
-rw-r--r--platform/platform-impl/src/com/intellij/ui/popup/WizardPopup.java2
-rw-r--r--platform/platform-impl/src/com/intellij/ui/win/RecentProjectApplication.java3
-rw-r--r--platform/platform-impl/src/com/intellij/util/IJSwingUtilities.java3
-rw-r--r--platform/platform-impl/src/org/jetbrains/io/ChannelRegistrar.java4
-rw-r--r--platform/platform-resources-en/src/messages/ApplicationBundle.properties11
-rw-r--r--platform/platform-resources-en/src/messages/ExecutionBundle.properties17
-rw-r--r--platform/platform-resources-en/src/messages/FeatureStatisticsBundle.properties2
-rw-r--r--platform/platform-resources-en/src/messages/IdeBundle.properties16
-rw-r--r--platform/platform-resources-en/src/messages/InspectionsBundle.properties2
-rw-r--r--platform/platform-resources-en/src/messages/OptionsBundle.properties24
-rw-r--r--platform/platform-resources-en/src/messages/RefactoringBundle.properties2
-rw-r--r--platform/platform-resources-en/src/messages/UIBundle.properties1
-rw-r--r--platform/platform-resources/src/META-INF/LangExtensionPoints.xml3
-rw-r--r--platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml2
-rw-r--r--platform/platform-resources/src/META-INF/PlatformExtensions.xml3
-rw-r--r--platform/platform-resources/src/META-INF/VcsExtensions.xml3
-rw-r--r--platform/platform-resources/src/META-INF/XmlPlugin.xml2
-rw-r--r--platform/platform-resources/src/META-INF/xdebugger.xml3
-rw-r--r--platform/platform-resources/src/brokenPlugins.txt2
-rw-r--r--platform/platform-resources/src/componentSets/Platform.xml5
-rw-r--r--platform/platform-resources/src/idea/LangActions.xml5
-rw-r--r--platform/platform-resources/src/launcher.py43
-rw-r--r--platform/platform-tests/testData/codeStyle/autodetect/manyComments.java51
-rw-r--r--platform/platform-tests/testData/codeStyle/autodetect/manyZeroRelativeIndent.java31
-rw-r--r--platform/platform-tests/testData/codeStyle/autodetect/simpleIndent.java14
-rw-r--r--platform/platform-tests/testSrc/com/intellij/formatting/GeneralCodeFormatterTest.java4
-rw-r--r--platform/platform-tests/testSrc/com/intellij/ide/util/treeView/BaseTreeTestCase.java6
-rw-r--r--platform/platform-tests/testSrc/com/intellij/openapi/components/impl/ApplicationStoreTest.java76
-rw-r--r--platform/platform-tests/testSrc/com/intellij/openapi/components/impl/StateStorageManagerImplTest.java13
-rw-r--r--platform/platform-tests/testSrc/com/intellij/openapi/components/impl/XmlElementStorageTest.java56
-rw-r--r--platform/platform-tests/testSrc/com/intellij/openapi/progress/util/ProgressIndicatorTest.java329
-rw-r--r--platform/platform-tests/testSrc/com/intellij/psi/autodetect/IndentAutoDetectionTest.java135
-rw-r--r--platform/projectModel-api/src/com/intellij/openapi/application/PathMacros.java10
-rw-r--r--platform/projectModel-api/src/com/intellij/openapi/components/LastStorageChooserForWrite.java10
-rw-r--r--platform/projectModel-api/src/com/intellij/openapi/components/State.java9
-rw-r--r--platform/projectModel-api/src/com/intellij/openapi/components/StateStorage.java15
-rw-r--r--platform/projectModel-api/src/com/intellij/openapi/components/Storage.java9
-rw-r--r--platform/projectModel-api/src/com/intellij/openapi/components/StorageAnnotationsDefaultValues.java87
-rw-r--r--platform/projectModel-api/src/com/intellij/openapi/components/StoragePathMacros.java8
-rw-r--r--platform/projectModel-api/src/com/intellij/openapi/project/DefaultProjectTypeEP.java (renamed from platform/projectModel-api/src/com/intellij/openapi/project/DefaultProjectTypeProvider.java)13
-rw-r--r--platform/projectModel-api/src/com/intellij/openapi/project/ProjectTypeService.java14
-rw-r--r--platform/projectModel-impl/src/com/intellij/application/options/PathMacrosImpl.java106
-rw-r--r--platform/projectModel-impl/src/com/intellij/core/CoreModuleManager.java5
-rw-r--r--platform/projectModel-impl/src/com/intellij/core/CoreProjectLoader.java14
-rw-r--r--platform/projectModel-impl/src/com/intellij/openapi/components/PathMacroManager.java6
-rw-r--r--platform/projectModel-impl/src/com/intellij/openapi/components/PathMacroSubstitutor.java5
-rw-r--r--platform/projectModel-impl/src/com/intellij/openapi/components/TrackingPathMacroSubstitutor.java13
-rw-r--r--platform/projectModel-impl/src/com/intellij/openapi/components/impl/BasePathMacroManager.java93
-rw-r--r--platform/projectModel-impl/src/com/intellij/openapi/components/impl/ModulePathMacroManager.java9
-rw-r--r--platform/projectModel-impl/src/com/intellij/openapi/components/impl/stores/DefaultStateSerializer.java5
-rw-r--r--platform/projectModel-impl/src/com/intellij/openapi/components/impl/stores/DirectoryStorageData.java54
-rw-r--r--platform/projectModel-impl/src/com/intellij/openapi/components/impl/stores/StorageData.java67
-rw-r--r--platform/projectModel-impl/src/com/intellij/openapi/roots/impl/RootIndex.java13
-rw-r--r--platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/JarDirectories.java2
-rw-r--r--platform/projectModel-impl/src/messages/ProjectBundle.properties4
-rw-r--r--platform/remote-servers/agent-rt/src/com/intellij/remoteServer/agent/util/CloudAgentLoggingHandler.java4
-rw-r--r--platform/remote-servers/api/remote-servers-api.iml1
-rw-r--r--platform/remote-servers/impl/src/com/intellij/remoteServer/util/CloudConfigurableBase.java66
-rw-r--r--platform/remote-servers/impl/src/com/intellij/remoteServer/util/CloudGitApplicationRuntime.java4
-rw-r--r--platform/remote-servers/impl/src/com/intellij/remoteServer/util/CloudLoggingHandlerImpl.java39
-rw-r--r--platform/remote-servers/impl/src/com/intellij/remoteServer/util/CloudSilentLoggingHandlerImpl.java7
-rw-r--r--platform/script-debugger/backend/src/org/jetbrains/debugger/sourcemap/SourceMap.java9
-rw-r--r--platform/script-debugger/backend/src/org/jetbrains/debugger/sourcemap/SourceMapDecoder.java12
-rw-r--r--platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/BasicDebuggerViewSupport.java11
-rw-r--r--platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/LazyVariablesGroup.java2
-rw-r--r--platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/MemberFilter.java5
-rw-r--r--platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/VariableView.java42
-rw-r--r--platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/Variables.java32
-rw-r--r--platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/frame/CallFrameView.java5
-rw-r--r--platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralTestEventsProcessor.java5
-rw-r--r--platform/smRunner/src/com/intellij/execution/testframework/sm/runner/states/TestComparisionFailedState.java12
-rw-r--r--platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralReplaceTest.java8
-rw-r--r--platform/testFramework/src/com/intellij/mock/Mock.java2
-rw-r--r--platform/testFramework/src/com/intellij/mock/MockVirtualFileSystem.java21
-rw-r--r--platform/testFramework/src/com/intellij/testFramework/FlyIdeaTestCase.java35
-rw-r--r--platform/testFramework/src/com/intellij/testFramework/PlatformTestUtil.java3
-rw-r--r--platform/testFramework/src/com/intellij/testFramework/TestActionEvent.java9
-rw-r--r--platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java12
-rw-r--r--platform/testFramework/src/com/intellij/testFramework/fixtures/IdeaTestFixtureFactory.java2
-rw-r--r--platform/testFramework/src/com/intellij/testFramework/fixtures/TestFixtureBuilder.java2
-rw-r--r--platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java12
-rw-r--r--platform/testFramework/src/com/intellij/testFramework/fixtures/impl/HeavyTestFixtureBuilderImpl.java2
-rw-r--r--platform/testFramework/src/com/intellij/testFramework/fixtures/impl/IdeaTestFixtureFactoryImpl.java1
-rw-r--r--platform/testFramework/src/com/intellij/testFramework/fixtures/impl/LightTestFixtureBuilderImpl.java2
-rw-r--r--platform/testFramework/testFramework.iml2
-rw-r--r--platform/testRunner/src/com/intellij/execution/testframework/AbstractTestProxy.java12
-rw-r--r--platform/testRunner/src/com/intellij/execution/testframework/Filter.java10
-rw-r--r--platform/testRunner/src/com/intellij/execution/testframework/TestTreeView.java9
-rw-r--r--platform/testRunner/src/com/intellij/execution/testframework/TestTreeViewAction.java19
-rw-r--r--platform/testRunner/src/com/intellij/execution/testframework/TestTreeViewActionsPromoter.java38
-rw-r--r--platform/testRunner/src/com/intellij/execution/testframework/TestsUIUtil.java6
-rw-r--r--platform/testRunner/src/com/intellij/execution/testframework/actions/AbstractRerunFailedTestsAction.java170
-rw-r--r--platform/testRunner/src/com/intellij/execution/testframework/actions/RerunFailedTestsAction.java12
-rw-r--r--platform/testRunner/src/com/intellij/execution/testframework/actions/ViewAssertEqualsDiffAction.java69
-rw-r--r--platform/testRunner/src/com/intellij/execution/testframework/stacktrace/DiffHyperlink.java88
-rw-r--r--platform/testRunner/src/com/intellij/execution/testframework/ui/TestResultsPanel.java10
-rw-r--r--platform/usageView/src/com/intellij/usages/ChunkExtractor.java2
-rw-r--r--platform/usageView/src/com/intellij/usages/FindUsagesProcessPresentation.java10
-rw-r--r--platform/usageView/src/com/intellij/usages/impl/SearchForUsagesRunnable.java8
-rw-r--r--platform/util-rt/src/com/intellij/openapi/util/Condition.java5
-rw-r--r--platform/util-rt/src/com/intellij/openapi/util/Conditions.java12
-rw-r--r--platform/util-rt/src/com/intellij/openapi/util/text/StringUtilRt.java22
-rw-r--r--platform/util-rt/src/com/intellij/util/ArrayUtilRt.java7
-rw-r--r--platform/util-rt/src/com/intellij/util/containers/ContainerUtilRt.java51
-rw-r--r--platform/util-rt/src/com/intellij/util/containers/HashMap.java8
-rw-r--r--platform/util-rt/src/com/intellij/util/containers/Stack.java5
-rw-r--r--platform/util/resources/misc/registry.properties18
-rw-r--r--platform/util/src/com/intellij/execution/configurations/CommandLineTokenizer.java10
-rw-r--r--platform/util/src/com/intellij/icons/AllIcons.java1
-rw-r--r--platform/util/src/com/intellij/openapi/application/PathManager.java8
-rw-r--r--platform/util/src/com/intellij/openapi/util/JDOMExternalizer.java27
-rw-r--r--platform/util/src/com/intellij/openapi/util/JDOMUtil.java22
-rw-r--r--platform/util/src/com/intellij/openapi/util/io/FileUtil.java9
-rw-r--r--platform/util/src/com/intellij/openapi/util/text/StringUtil.java268
-rw-r--r--platform/util/src/com/intellij/util/ArrayUtil.java63
-rw-r--r--platform/util/src/com/intellij/util/ReflectionUtil.java52
-rw-r--r--platform/util/src/com/intellij/util/Restarter.java13
-rw-r--r--platform/util/src/com/intellij/util/containers/ContainerUtil.java227
-rw-r--r--platform/util/src/com/intellij/util/containers/FactoryMap.java10
-rw-r--r--platform/util/src/com/intellij/util/containers/TransferToEDTQueue.java3
-rw-r--r--platform/util/src/com/intellij/util/io/AppendableStorageBackedByResizableMappedFile.java3
-rw-r--r--platform/util/src/com/intellij/util/io/PersistentEnumeratorBase.java4
-rw-r--r--platform/util/src/com/intellij/util/messages/impl/MessageListenerList.java10
-rw-r--r--platform/util/src/com/intellij/util/ui/JBSwingUtilities.java53
-rw-r--r--platform/util/src/com/intellij/util/ui/UIUtil.java19
-rw-r--r--platform/util/src/com/intellij/util/ui/tree/WideSelectionTreeUI.java3
-rw-r--r--platform/util/testSrc/com/intellij/execution/configurations/CommandLineTokenizerTest.java60
-rw-r--r--platform/util/testSrc/com/intellij/util/text/StringUtilTest.java15
-rw-r--r--platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/FrameDialogWrapper.java135
-rw-r--r--platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateToggleAction.java1
-rw-r--r--platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesFragmentedDiffPanel.java2
-rw-r--r--platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeManagerImpl.java6
-rw-r--r--platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/CommittedChangesCache.java13
-rw-r--r--platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitChangeListDialog.java5
-rw-r--r--platform/vcs-impl/src/com/intellij/openapi/vcs/configurable/VcsManagerConfigurableProvider.java41
-rw-r--r--platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java83
-rw-r--r--platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RollbackLineStatusAction.java20
-rw-r--r--platform/vcs-log/api/src/com/intellij/vcs/log/VcsLogProvider.java47
-rw-r--r--platform/vcs-log/api/src/com/intellij/vcs/log/VcsLogProviderRequirementsEx.java9
-rw-r--r--platform/vcs-log/api/vcs-log-api.iml1
-rw-r--r--platform/vcs-log/graph-api/src/com/intellij/vcs/log/graph/RowInfo.java3
-rw-r--r--platform/vcs-log/graph-api/src/com/intellij/vcs/log/graph/RowType.java27
-rw-r--r--platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/facade/AbstractVisibleGraph.java6
-rw-r--r--platform/vcs-log/impl/src/com/intellij/vcs/log/data/DataPack.java28
-rw-r--r--platform/vcs-log/impl/src/com/intellij/vcs/log/data/EmptyDataPack.java4
-rw-r--r--platform/vcs-log/impl/src/com/intellij/vcs/log/data/EmptyVisibleGraph.java7
-rw-r--r--platform/vcs-log/impl/src/com/intellij/vcs/log/data/RefsModel.java6
-rw-r--r--platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogMultiRepoJoiner.java24
-rw-r--r--platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogRefresherImpl.java354
-rw-r--r--platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogSorter.java3
-rw-r--r--platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsUserRegistryImpl.java6
-rw-r--r--platform/vcs-log/impl/src/com/intellij/vcs/log/impl/LogDataImpl.java74
-rw-r--r--platform/vcs-log/impl/src/com/intellij/vcs/log/impl/RequirementsImpl.java10
-rw-r--r--platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsStructureChooser.java1
-rw-r--r--platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/StructureFilterPopupComponent.java2
-rw-r--r--platform/vcs-log/impl/test/com/intellij/vcs/log/data/VcsLogRefresherTest.java10
-rw-r--r--platform/vcs-log/impl/test/com/intellij/vcs/log/impl/TestVcsLogProvider.java37
-rw-r--r--platform/vcs-log/impl/vcs-log-impl.iml2
-rw-r--r--platform/xdebugger-api/src/com/intellij/xdebugger/XDebugProcess.java18
-rw-r--r--platform/xdebugger-api/src/com/intellij/xdebugger/evaluation/XDebuggerEvaluator.java13
-rw-r--r--platform/xdebugger-api/src/com/intellij/xdebugger/frame/XReferrersProvider.java6
-rw-r--r--platform/xdebugger-api/src/com/intellij/xdebugger/frame/XValue.java6
-rw-r--r--platform/xdebugger-impl/src/com/intellij/xdebugger/impl/DebuggerSupport.java32
-rw-r--r--platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java2
-rw-r--r--platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerManagerImpl.java50
-rw-r--r--platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XMarkObjectActionHandler.java4
-rw-r--r--platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEditorLinePainter.java32
-rw-r--r--platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEvaluationDialog.java2
-rw-r--r--platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/XValueHint.java45
-rw-r--r--platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/common/AbstractValueHint.java6
-rw-r--r--platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/common/DebuggerTreeWithHistoryContainer.java4
-rw-r--r--platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/common/DebuggerTreeWithHistoryPopup.java18
-rw-r--r--platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/WatchInplaceEditor.java6
-rw-r--r--platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XDebugView.java14
-rw-r--r--platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XDebugViewSessionListener.java7
-rw-r--r--platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XDebuggerFramesList.java19
-rw-r--r--platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XFramesView.java45
-rw-r--r--platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XVariablesViewBase.java119
-rw-r--r--platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XWatchesViewImpl.java18
-rw-r--r--platform/xdebugger-impl/src/com/intellij/xdebugger/impl/settings/DebuggerConfigurable.java3
-rw-r--r--platform/xdebugger-impl/src/com/intellij/xdebugger/impl/settings/DebuggerConfigurableProvider.java34
-rw-r--r--platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/DebuggerSessionTabBase.java57
-rw-r--r--platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java62
-rw-r--r--platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/ValueMarkerPresentationDialog.java6
-rw-r--r--platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/ValueMarkerPresentationDialogBase.java4
-rw-r--r--platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/WatchesRootNode.java4
-rw-r--r--platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XValueContainerNode.java4
-rw-r--r--platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XDebuggerTestUtil.java100
-rw-r--r--platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XTestContainer.java2
-rw-r--r--platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XTestEvaluationCallback.java7
-rw-r--r--platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XTestValueNode.java2
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml20
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties26
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/ResultSetIndexZeroInspection.java8
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/StringEqualityInspection.java10
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/ClassWithOnlyPrivateConstructorsInspectionBase.java3
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/controlflow/LoopConditionNotUpdatedInsideLoopInspection.java6
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/initialization/DoubleBraceInitializationInspection.java216
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/initialization/NonThreadSafeLazyInitializationInspection.java246
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/initialization/NonThreadSafeLazyInitializationInspectionBase.java132
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/j2me/AnonymousInnerClassMayBeStaticInspectionBase.java74
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/javadoc/MissingPackageInfoInspectionBase.java (renamed from plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/javadoc/MissingPackageInfoInspection.java)10
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/memory/AnonymousInnerClassMayBeStaticInspectionBase.java110
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/memory/InnerClassMayBeStaticInspection.java (renamed from plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/InnerClassMayBeStaticInspection.java)4
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/memory/InnerClassReferenceVisitor.java126
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/InnerClassReferenceVisitor.java149
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ClassUtils.java3
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ExpressionUtils.java9
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/CStyleArrayDeclarationInspection.java102
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/NestedMethodCallInspectionBase.java19
-rw-r--r--plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/DoubleCheckedLockingInspection.java116
-rw-r--r--plugins/InspectionGadgets/src/com/siyeh/ig/initialization/NonThreadSafeLazyInitializationInspection.java216
-rw-r--r--plugins/InspectionGadgets/src/com/siyeh/ig/javadoc/MissingPackageInfoInspection.java83
-rw-r--r--plugins/InspectionGadgets/src/com/siyeh/ig/memory/AnonymousInnerClassMayBeStaticInspection.java (renamed from plugins/InspectionGadgets/src/com/siyeh/ig/j2me/AnonymousInnerClassMayBeStaticInspection.java)4
-rw-r--r--plugins/InspectionGadgets/src/com/siyeh/ig/style/NestedMethodCallInspection.java11
-rw-r--r--plugins/InspectionGadgets/src/inspectionDescriptions/AmbiguousFieldAccess.html8
-rw-r--r--plugins/InspectionGadgets/src/inspectionDescriptions/AmbiguousMethodCall.html10
-rw-r--r--plugins/InspectionGadgets/src/inspectionDescriptions/AnonymousInnerClassMayBeStatic.html9
-rw-r--r--plugins/InspectionGadgets/src/inspectionDescriptions/CStyleArrayDeclaration.html13
-rw-r--r--plugins/InspectionGadgets/src/inspectionDescriptions/DoubleBraceInitialization.html13
-rw-r--r--plugins/InspectionGadgets/src/inspectionDescriptions/DoubleCheckedLocking.html6
-rw-r--r--plugins/InspectionGadgets/src/inspectionDescriptions/InnerClassMayBeStatic.html8
-rw-r--r--plugins/InspectionGadgets/src/inspectionDescriptions/NonThreadSafeLazyInitialization.html10
-rw-r--r--plugins/InspectionGadgets/src/inspectionDescriptions/PropertyValueSetToItself.html4
-rw-r--r--plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/Argument.java12
-rw-r--r--plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/Field.after.java12
-rw-r--r--plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/Field.java10
-rw-r--r--plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/LocalVariable.after.java13
-rw-r--r--plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/LocalVariable.java14
-rw-r--r--plugins/InspectionGadgets/test/com/siyeh/igfixes/memory/inner_class_static/Simple.after.java (renamed from plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/inner_class_static/Simple.after.java)2
-rw-r--r--plugins/InspectionGadgets/test/com/siyeh/igfixes/memory/inner_class_static/Simple.java (renamed from plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/inner_class_static/Simple.java)2
-rw-r--r--plugins/InspectionGadgets/test/com/siyeh/igfixes/style/cstyle_array_declaration/FieldWithWhitespace.after.java4
-rw-r--r--plugins/InspectionGadgets/test/com/siyeh/igfixes/style/cstyle_array_declaration/FieldWithWhitespace.java4
-rw-r--r--plugins/InspectionGadgets/test/com/siyeh/igfixes/style/cstyle_array_declaration/SimpleMethod.after.java6
-rw-r--r--plugins/InspectionGadgets/test/com/siyeh/igfixes/style/cstyle_array_declaration/SimpleMethod.java6
-rw-r--r--plugins/InspectionGadgets/test/com/siyeh/igfixes/threading/make_field_volatile/Simple.after.java19
-rw-r--r--plugins/InspectionGadgets/test/com/siyeh/igfixes/threading/make_field_volatile/Simple.java19
-rw-r--r--plugins/InspectionGadgets/test/com/siyeh/igfixes/threading/non_thread_safe_lazy_initialization/InstanceVariableReferenced.java16
-rw-r--r--plugins/InspectionGadgets/test/com/siyeh/igfixes/threading/non_thread_safe_lazy_initialization/LocalVariableReferenced.java11
-rw-r--r--plugins/InspectionGadgets/test/com/siyeh/igfixes/threading/non_thread_safe_lazy_initialization/NestedAssignment.java12
-rw-r--r--plugins/InspectionGadgets/test/com/siyeh/igfixes/threading/non_thread_safe_lazy_initialization/Normal.after.java10
-rw-r--r--plugins/InspectionGadgets/test/com/siyeh/igfixes/threading/non_thread_safe_lazy_initialization/Normal.java10
-rw-r--r--plugins/InspectionGadgets/test/com/siyeh/igfixes/threading/non_thread_safe_lazy_initialization/StaticVariableReferenced.after.java16
-rw-r--r--plugins/InspectionGadgets/test/com/siyeh/igfixes/threading/non_thread_safe_lazy_initialization/StaticVariableReferenced.java16
-rw-r--r--plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/ResultSetIndexZeroInspection.java14
-rw-r--r--plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/result_set_index_zero/ResultSetIndexZero.java21
-rw-r--r--plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/string_equality/StringEquality.java8
-rw-r--r--plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/string_equality/expected.xml9
-rw-r--r--plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/NestedMethodCallInspection.java35
-rw-r--r--plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/double_brace_initialization/DoubleBraceInitialization.java32
-rw-r--r--plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/non_thread_safe_lazy_initialization/NonThreadSafeLazyInitialization.java64
-rw-r--r--plugins/InspectionGadgets/test/com/siyeh/igtest/memory/anonymous_inner_class_may_be_static/AnonymousInnerClassMayBeStatic.java93
-rw-r--r--plugins/InspectionGadgets/test/com/siyeh/igtest/memory/inner_class_may_be_static/InnerClassMayBeStatic.java140
-rw-r--r--plugins/InspectionGadgets/test/com/siyeh/igtest/performance/inner_class_may_be_static/InnerClassMayBeStaticInspection.java97
-rw-r--r--plugins/InspectionGadgets/test/com/siyeh/igtest/performance/inner_class_may_be_static/expected.xml44
-rw-r--r--plugins/InspectionGadgets/test/com/siyeh/igtest/style/CStyleArrayDeclarationInspection.java34
-rw-r--r--plugins/InspectionGadgets/test/com/siyeh/igtest/style/cstyle_array_declaration/CStyleArrayDeclaration.java38
-rw-r--r--plugins/InspectionGadgets/test/com/siyeh/igtest/style/nested_method_call/NestedMethodCall.java43
-rw-r--r--plugins/InspectionGadgets/test/com/siyeh/igtest/threading/NonThreadSafeLazyInitializationInspection.java34
-rw-r--r--plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/ambiguous/AmbiguousMethodCall.java2
-rw-r--r--plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/ambiguous/expected.xml10
-rw-r--r--plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/ambiguous_field_access/AmbiguousFieldAccess.java17
-rw-r--r--plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/ambiguous_field_access/expected.xml9
-rw-r--r--plugins/InspectionGadgets/testsrc/com/siyeh/ig/IGQuickFixesTestCase.java45
-rw-r--r--plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/ResultSetIndexZeroInspectionTest.java34
-rw-r--r--plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/StringEqualityInspectionTest.java16
-rw-r--r--plugins/InspectionGadgets/testsrc/com/siyeh/ig/classlayout/ClassWithOnlyPrivateConstructorsInspectionTest.java8
-rw-r--r--plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/initialization/DoubleBraceInitializationFixTest.java38
-rw-r--r--plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/memory/InnerClassMayBeStaticFixTest.java (renamed from plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/performance/InnerClassMayBeStaticFixTest.java)6
-rw-r--r--plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/style/CStyleArrayDeclarationFixTest.java37
-rw-r--r--plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/threading/IntroduceHolderFixTest.java41
-rw-r--r--plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/threading/MakeFieldVolatileFixTest.java37
-rw-r--r--plugins/InspectionGadgets/testsrc/com/siyeh/ig/initialization/DoubleBraceInitializationInspectionTest.java34
-rw-r--r--plugins/InspectionGadgets/testsrc/com/siyeh/ig/initialization/NonThreadSafeLazyInitializationInspectionTest.java34
-rw-r--r--plugins/InspectionGadgets/testsrc/com/siyeh/ig/memory/AnonymousInnerClassMayBeStaticInspectionTest.java34
-rw-r--r--plugins/InspectionGadgets/testsrc/com/siyeh/ig/memory/InnerClassMayBeStaticInspectionTest.java16
-rw-r--r--plugins/InspectionGadgets/testsrc/com/siyeh/ig/performance/InnerClassMayBeStaticInspectionTest.java11
-rw-r--r--plugins/InspectionGadgets/testsrc/com/siyeh/ig/style/CStyleArrayDeclarationInspectionTest.java34
-rw-r--r--plugins/InspectionGadgets/testsrc/com/siyeh/ig/style/NestedMethodCallInspectionTest.java37
-rw-r--r--plugins/InspectionGadgets/testsrc/com/siyeh/ig/visibility/AmbiguousFieldAccessInspectionTest.java14
-rw-r--r--plugins/InspectionGadgets/testsrc/com/siyeh/ig/visibility/AmbiguousMethodCallInspectionTest.java19
-rw-r--r--plugins/IntentionPowerPak/src/META-INF/IntentionPowerPack.xml6
-rw-r--r--plugins/IntentionPowerPak/src/com/siyeh/IntentionPowerPackBundle.properties6
-rw-r--r--plugins/IntentionPowerPak/src/com/siyeh/ipp/base/Intention.java8
-rw-r--r--plugins/IntentionPowerPak/src/com/siyeh/ipp/decls/SimplifyVariableIntention.java12
-rw-r--r--plugins/IntentionPowerPak/src/com/siyeh/ipp/equality/ObjectEqualityPredicate.java36
-rw-r--r--plugins/IntentionPowerPak/src/com/siyeh/ipp/equality/ReplaceEqualityWithEqualsIntention.java31
-rw-r--r--plugins/IntentionPowerPak/src/com/siyeh/ipp/equality/ReplaceEqualityWithSafeEqualsIntention.java63
-rw-r--r--plugins/IntentionPowerPak/src/com/siyeh/ipp/initialization/SplitDeclarationAndInitializationIntention.java9
-rw-r--r--plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/CreateAssertIntention.java133
-rw-r--r--plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/CreateAssertPredicate.java59
-rw-r--r--plugins/IntentionPowerPak/test/com/siyeh/ipp/decls/simplify_variable/FieldWithWhitespace.java4
-rw-r--r--plugins/IntentionPowerPak/test/com/siyeh/ipp/decls/simplify_variable/FieldWithWhitespace_after.java4
-rw-r--r--plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_equals/EnumComparison.java8
-rw-r--r--plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_equals/NegatedObjectComparison.java6
-rw-r--r--plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_equals/NegatedObjectComparison_after.java6
-rw-r--r--plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_equals/NullComparison.java6
-rw-r--r--plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_equals/PrimitiveComparison.java6
-rw-r--r--plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_equals/SimpleObjectComparison.java6
-rw-r--r--plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_equals/SimpleObjectComparison_after.java6
-rw-r--r--plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_safe_equals/EnumComparison.java10
-rw-r--r--plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_safe_equals/NegatedObjectComparison.java8
-rw-r--r--plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_safe_equals/NegatedObjectComparison_after.java8
-rw-r--r--plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_safe_equals/NullComparison.java8
-rw-r--r--plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_safe_equals/PrimitiveComparison.java8
-rw-r--r--plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_safe_equals/SimpleObjectComparison.java8
-rw-r--r--plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_safe_equals/SimpleObjectComparison_after.java8
-rw-r--r--plugins/IntentionPowerPak/test/com/siyeh/ipp/initialization/Array.java3
-rw-r--r--plugins/IntentionPowerPak/test/com/siyeh/ipp/initialization/ArrayInitializer.java2
-rw-r--r--plugins/IntentionPowerPak/test/com/siyeh/ipp/initialization/Array_after.java7
-rw-r--r--plugins/IntentionPowerPak/test/com/siyeh/ipp/junit/create_assert/AnonymousClassJUnit3.java12
-rw-r--r--plugins/IntentionPowerPak/test/com/siyeh/ipp/junit/create_assert/AnonymousClassJUnit3_after.java12
-rw-r--r--plugins/IntentionPowerPak/test/com/siyeh/ipp/junit/create_assert/AnonymousClassJUnit4.java11
-rw-r--r--plugins/IntentionPowerPak/test/com/siyeh/ipp/junit/create_assert/AnonymousClassJUnit4_after.java13
-rw-r--r--plugins/IntentionPowerPak/test/com/siyeh/ipp/junit/create_assert/AssertFalse.java12
-rw-r--r--plugins/IntentionPowerPak/test/com/siyeh/ipp/junit/create_assert/AssertFalse_after.java12
-rw-r--r--plugins/IntentionPowerPak/test/com/siyeh/ipp/junit/create_assert/StaticImportJUnit4.java9
-rw-r--r--plugins/IntentionPowerPak/test/com/siyeh/ipp/junit/create_assert/StaticImportJUnit4_after.java10
-rw-r--r--plugins/IntentionPowerPak/test/com/siyeh/ipp/types/lambda2anonymous/Ambiguity.java6
-rw-r--r--plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/decls/SimplifyVariableIntentionTest.java38
-rw-r--r--plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/equality/ReplaceEqualityWithEqualsIntentionTest.java42
-rw-r--r--plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/equality/ReplaceEqualityWithSafeEqualsIntentionTest.java42
-rw-r--r--plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/initialization/SplitDeclarationAndInitializationIntentionTest.java1
-rw-r--r--plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/junit/CreateAssertIntentionTest.java60
-rw-r--r--plugins/ShortcutPromoter/src/com/intellij/promoter/ShortcutPromoterManager.java10
-rw-r--r--plugins/cvs/cvs-plugin/src/META-INF/plugin.xml8
-rw-r--r--plugins/devkit/resources/org/jetbrains/idea/devkit/DevKitBundle.properties2
-rw-r--r--plugins/devkit/src/dom/Action.java3
-rw-r--r--plugins/devkit/src/dom/impl/ExtensionDomExtender.java155
-rw-r--r--plugins/devkit/src/dom/impl/PluginXmlDomFileDescription.java99
-rw-r--r--plugins/devkit/src/inspections/PluginXmlDomInspection.java126
-rw-r--r--plugins/devkit/src/navigation/DescriptionTypeRelatedItemLineMarkerProvider.java14
-rw-r--r--plugins/devkit/src/navigation/DevkitRelatedLineMarkerProviderBase.java44
-rw-r--r--plugins/devkit/src/navigation/ExtensionPointDeclarationRelatedItemLineMarkerProvider.java3
-rw-r--r--plugins/devkit/src/projectRoots/IdeaJdk.java12
-rw-r--r--plugins/devkit/src/run/PluginRunConfigurationEditor.java20
-rw-r--r--plugins/devkit/src/testAssistant/NavigateToTestDataAction.java3
-rw-r--r--plugins/devkit/src/testAssistant/TestDataLineMarkerProvider.java16
-rw-r--r--plugins/devkit/src/testAssistant/TestLocationDataRule.java3
-rw-r--r--plugins/devkit/src/util/PsiUtil.java5
-rw-r--r--plugins/devkit/testData/codeInsight/ExtensionsHighlighting.xml2
-rw-r--r--plugins/devkit/testData/codeInsight/deprecatedAttributes.xml8
-rw-r--r--plugins/devkit/testData/codeInsight/deprecatedExtensionAttribute.xml2
-rw-r--r--plugins/devkit/testData/pluginXmlDomStubs/pluginWithXInclude-extensionPoints.xml5
-rw-r--r--plugins/devkit/testData/pluginXmlDomStubs/pluginWithXInclude-main.xml10
-rw-r--r--plugins/devkit/testData/pluginXmlDomStubs/pluginWithXInclude.xml15
-rw-r--r--plugins/devkit/testSources/codeInsight/PluginXmlDomStubsTest.java7
-rw-r--r--plugins/devkit/testSources/navigation/DescriptionTypeRelatedItemLineMarkerProviderTest.java3
-rw-r--r--plugins/devkit/testSources/navigation/ExtensionPointDeclarationRelatedItemLineMarkerProviderTest.java7
-rw-r--r--plugins/git4idea/git4idea.iml2
-rw-r--r--plugins/git4idea/src/git4idea/GitUtil.java1
-rw-r--r--plugins/git4idea/src/git4idea/annotate/GitAnnotationProvider.java1
-rw-r--r--plugins/git4idea/src/git4idea/branch/GitBranchUtil.java3
-rw-r--r--plugins/git4idea/src/git4idea/branch/GitBranchWorker.java22
-rw-r--r--plugins/git4idea/src/git4idea/checkin/GitCheckinHandlerFactory.java40
-rw-r--r--plugins/git4idea/src/git4idea/config/GitVcsPanel.form11
-rw-r--r--plugins/git4idea/src/git4idea/config/GitVcsPanel.java15
-rw-r--r--plugins/git4idea/src/git4idea/config/GitVcsSettings.java29
-rw-r--r--plugins/git4idea/src/git4idea/history/GitHistoryUtils.java197
-rw-r--r--plugins/git4idea/src/git4idea/history/GitLogRecord.java33
-rw-r--r--plugins/git4idea/src/git4idea/log/GitLogProvider.java218
-rw-r--r--plugins/git4idea/src/git4idea/log/GitRefManager.java23
-rw-r--r--plugins/git4idea/src/git4idea/repo/GitRepositoryFiles.java19
-rw-r--r--plugins/git4idea/src/git4idea/repo/GitRepositoryImpl.java8
-rw-r--r--plugins/git4idea/src/git4idea/repo/GitRepositoryUpdater.java24
-rw-r--r--plugins/git4idea/src/git4idea/reset/GitResetAction.java11
-rw-r--r--plugins/git4idea/src/git4idea/ui/branch/GitBranchPopup.java163
-rw-r--r--plugins/git4idea/src/git4idea/ui/branch/GitCompareBranchesDialog.java87
-rw-r--r--plugins/git4idea/src/git4idea/ui/branch/GitMultiRootBranchConfig.java49
-rw-r--r--plugins/git4idea/src/git4idea/validators/GitNewBranchNameValidator.java36
-rw-r--r--plugins/git4idea/tests/git4idea/log/GitLogProviderTest.java54
-rw-r--r--plugins/git4idea/tests/git4idea/log/GitRefManagerTest.java6
-rw-r--r--plugins/git4idea/tests/git4idea/log/RefParser.java (renamed from plugins/git4idea/src/git4idea/log/RefParser.java)32
-rw-r--r--plugins/git4idea/tests/git4idea/log/RefParserTest.java125
-rw-r--r--plugins/github/github.iml2
-rw-r--r--plugins/github/src/org/jetbrains/plugins/github/GithubCreateGistAction.java7
-rw-r--r--plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestAction.java6
-rw-r--r--plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java1083
-rw-r--r--plugins/github/src/org/jetbrains/plugins/github/GithubRebaseAction.java7
-rw-r--r--plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java15
-rw-r--r--plugins/github/src/org/jetbrains/plugins/github/api/GithubApiUtil.java632
-rw-r--r--plugins/github/src/org/jetbrains/plugins/github/api/GithubChangeIssueStateRequest.java12
-rw-r--r--plugins/github/src/org/jetbrains/plugins/github/api/GithubConnection.java491
-rw-r--r--plugins/github/src/org/jetbrains/plugins/github/api/GithubFullPath.java9
-rw-r--r--plugins/github/src/org/jetbrains/plugins/github/api/GithubUser.java10
-rw-r--r--plugins/github/src/org/jetbrains/plugins/github/api/GithubUserDetailed.java4
-rw-r--r--plugins/github/src/org/jetbrains/plugins/github/api/GithubUserRaw.java4
-rw-r--r--plugins/github/src/org/jetbrains/plugins/github/extensions/GithubCheckoutProvider.java7
-rw-r--r--plugins/github/src/org/jetbrains/plugins/github/tasks/GithubComment.java12
-rw-r--r--plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepository.java118
-rw-r--r--plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepositoryEditor.java9
-rw-r--r--plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepositoryType.java7
-rw-r--r--plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java249
-rw-r--r--plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.form32
-rw-r--r--plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.java138
-rw-r--r--plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkDialog.java41
-rw-r--r--plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkPanel.java8
-rw-r--r--plugins/github/src/org/jetbrains/plugins/github/ui/GithubSettingsPanel.java13
-rw-r--r--plugins/github/src/org/jetbrains/plugins/github/util/GithubNotifications.java26
-rw-r--r--plugins/github/src/org/jetbrains/plugins/github/util/GithubSettings.java11
-rw-r--r--plugins/github/src/org/jetbrains/plugins/github/util/GithubUtil.java177
-rw-r--r--plugins/github/test/org/jetbrains/plugins/github/GithubCreateGistTestBase.java5
-rw-r--r--plugins/github/test/org/jetbrains/plugins/github/GithubCreatePullRequestTestBase.java2
-rw-r--r--plugins/github/test/org/jetbrains/plugins/github/GithubIssuesTest.java19
-rw-r--r--plugins/github/test/org/jetbrains/plugins/github/GithubRequestPagingTest.java28
-rw-r--r--plugins/github/test/org/jetbrains/plugins/github/GithubShareProjectTest.java3
-rw-r--r--plugins/github/test/org/jetbrains/plugins/github/GithubShareProjectTestBase.java3
-rw-r--r--plugins/gradle/resources/i18n/GradleBundle.properties2
-rw-r--r--plugins/gradle/src/META-INF/plugin.xml2
-rw-r--r--plugins/gradle/src/org/jetbrains/plugins/gradle/execution/GradleOrderEnumeratorHandler.java2
-rw-r--r--plugins/gradle/src/org/jetbrains/plugins/gradle/service/GradleInstallationManager.java2
-rw-r--r--plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java36
-rw-r--r--plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleFoldersImportingTest.java36
-rw-r--r--plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleImportingTestCase.java2
-rw-r--r--plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ExternalProjectBuilderImpl.groovy6
-rw-r--r--plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/GroovyBundle.properties2
-rw-r--r--plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/dsl/GroovyClassDescriptor.java2
-rw-r--r--plugins/groovy/src/META-INF/plugin.xml2
-rw-r--r--plugins/groovy/src/org/jetbrains/plugins/groovy/config/GroovyFacetUtil.java10
-rw-r--r--plugins/groovy/src/org/jetbrains/plugins/groovy/ivy/AbstractAttachSourceProvider.java2
-rw-r--r--plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionUtil.java3
-rw-r--r--plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcActionBase.java3
-rw-r--r--plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyDebuggerTest.groovy6
-rw-r--r--plugins/hg4idea/hg4idea.iml1
-rw-r--r--plugins/hg4idea/src/META-INF/plugin.xml2
-rw-r--r--plugins/hg4idea/src/org/zmlx/hg4idea/HgProjectSettings.java15
-rw-r--r--plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractGlobalAction.java2
-rw-r--r--plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchPopup.java127
-rw-r--r--plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCommonBranchActions.java133
-rw-r--r--plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgBranchAbstractAction.java (renamed from plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchAbstractAction.java)10
-rw-r--r--plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgBranchPopup.java119
-rw-r--r--plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgBranchPopupActions.java (renamed from plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchPopupActions.java)80
-rw-r--r--plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgBranchUtil.java77
-rw-r--r--plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgBranchesAction.java (renamed from plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchesAction.java)3
-rw-r--r--plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgCommonBranchActions.java141
-rw-r--r--plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgMultiRootBranchConfig.java50
-rw-r--r--plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCommitCommand.java24
-rw-r--r--plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgCommandExecutor.java2
-rw-r--r--plugins/hg4idea/src/org/zmlx/hg4idea/log/HgHistoryUtil.java6
-rw-r--r--plugins/hg4idea/src/org/zmlx/hg4idea/log/HgLogProvider.java28
-rw-r--r--plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgChangeProvider.java44
-rw-r--r--plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgCurrentBinaryContentRevision.java18
-rw-r--r--plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgCurrentContentRevision.java2
-rw-r--r--plugins/hg4idea/src/org/zmlx/hg4idea/provider/commit/HgCheckinEnvironment.java114
-rw-r--r--plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushSupport.java44
-rw-r--r--plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushTargetPanel.java88
-rw-r--r--plugins/hg4idea/src/org/zmlx/hg4idea/push/HgTarget.java1
-rw-r--r--plugins/hg4idea/src/org/zmlx/hg4idea/push/PushTargetTextField.java63
-rw-r--r--plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepoInfo.java16
-rw-r--r--plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepository.java5
-rw-r--r--plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryImpl.java27
-rw-r--r--plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryReader.java18
-rw-r--r--plugins/hg4idea/src/org/zmlx/hg4idea/status/ui/HgStatusWidget.java2
-rw-r--r--plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgConfigurationProjectPanel.form44
-rw-r--r--plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgConfigurationProjectPanel.java11
-rw-r--r--plugins/hg4idea/src/org/zmlx/hg4idea/util/HgUtil.java22
-rw-r--r--plugins/java-decompiler/engine/.gitattributes1
-rw-r--r--plugins/java-decompiler/engine/build.xml58
-rw-r--r--plugins/java-decompiler/engine/readme.txt88
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/CodeConstants.java370
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/ConstantsUtil.java482
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/ExceptionHandler.java61
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/ExceptionTable.java58
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/FullInstructionSequence.java38
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/IfInstruction.java36
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/Instruction.java126
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/InstructionSequence.java227
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/JumpInstruction.java42
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/SimpleInstructionSequence.java39
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/SwitchInstruction.java97
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/cfg/BasicBlock.java266
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/cfg/ControlFlowGraph.java884
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/cfg/ExceptionRangeCFG.java129
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/interpreter/InstructionImpact.java527
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/interpreter/Util.java286
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/ALOAD.java60
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/ANEWARRAY.java33
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/ASTORE.java60
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/BIPUSH.java48
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/CHECKCAST.java34
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/DLOAD.java60
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/DSTORE.java60
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/FLOAD.java60
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/FSTORE.java60
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/GETFIELD.java33
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/GETSTATIC.java33
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/GOTO.java46
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/GOTO_W.java33
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/IINC.java43
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/ILOAD.java55
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/INSTANCEOF.java33
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKEDYNAMIC.java35
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKEINTERFACE.java35
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKESPECIAL.java33
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKESTATIC.java33
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKEVIRTUAL.java33
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/ISTORE.java55
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/JSR.java46
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/JSR_W.java33
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/LDC.java33
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/LDC2_W.java33
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/LDC_W.java33
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/LLOAD.java55
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/LOOKUPSWITCH.java42
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/LSTORE.java55
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/MULTIANEWARRAY.java34
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/NEW.java33
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/NEWARRAY.java33
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/PUTFIELD.java33
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/PUTSTATIC.java33
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/RET.java41
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/SIPUSH.java33
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/TABLESWITCH.java42
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/AssertProcessor.java310
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/ClassReference14Processor.java296
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/ClassWriter.java987
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java431
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/DecompilerContext.java150
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/EnumProcessor.java118
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/Fernflower.java94
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/InitializerProcessor.java323
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/collectors/CounterContainer.java37
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/collectors/ImportCollector.java148
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/collectors/VarNamesCollector.java51
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/decompiler/BaseDecompiler.java47
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/decompiler/ConsoleDecompiler.java299
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/decompiler/PrintStreamLogger.java80
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/extern/IBytecodeProvider.java22
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/extern/IFernflowerLogger.java49
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java86
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/extern/IIdentifierRenamer.java35
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/extern/IResultSaver.java36
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/rels/ClassWrapper.java207
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/rels/LambdaProcessor.java151
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/rels/MethodProcessorThread.java259
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/rels/MethodWrapper.java62
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java1030
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/rels/NestedMemberAccess.java449
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/code/DeadCodeHelper.java436
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/ClearStructHelper.java40
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/ConcatenationHelper.java209
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/DecHelper.java218
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/DomHelper.java707
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/EliminateLoopsHelper.java214
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/ExitHelper.java345
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java913
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/ExprentStack.java45
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/FinallyProcessor.java1087
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/IdeaNotNullHelper.java336
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/IfHelper.java750
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/InlineSingleBlockHelper.java220
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/LabelHelper.java506
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/LoopExtractHelper.java206
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/LowBreakHelper.java208
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/MergeHelper.java421
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/PPandMMHelper.java154
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/PrimitiveExprsList.java49
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/SecondaryFunctionsHelper.java432
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/SequenceHelper.java327
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/SimplifyExprentsHelper.java853
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/StackVarsProcessor.java735
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/StatEdge.java104
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/StrongConnectivityHelper.java207
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/DominatorEngine.java128
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/DominatorTreeExceptionFilter.java184
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/FastExtendedPostdominanceHelper.java355
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/GenericDominatorEngine.java152
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/IGraph.java26
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/IGraphNode.java23
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/deobfuscator/ExceptionDeobfuscator.java330
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/deobfuscator/IrreducibleCFGDeobfuscator.java245
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AnnotationExprent.java114
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ArrayExprent.java126
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssertExprent.java51
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java204
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java402
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExitExprent.java151
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java133
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java200
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java615
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/IfExprent.java145
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java515
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/MonitorExprent.java83
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java504
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchExprent.java114
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java182
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/DirectGraph.java136
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/DirectNode.java67
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/FlattenStatementsHelper.java574
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAConstructorSparseEx.java529
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAUConstructorSparseEx.java844
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/BasicBlockStatement.java96
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchAllStatement.java233
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchStatement.java210
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/DoStatement.java222
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/GeneralStatement.java74
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/IfStatement.java416
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/RootStatement.java48
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SequenceStatement.java144
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java863
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SwitchStatement.java367
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SynchronizedStatement.java153
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/CheckTypesResult.java57
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java355
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarProcessor.java129
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarTypeProcessor.java278
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionEdge.java56
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionNode.java80
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionPaar.java63
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsGraph.java167
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsProcessor.java334
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/renamer/ClassWrapperNode.java55
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/renamer/ConverterHelper.java143
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/renamer/IdentifierConverter.java463
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/renamer/PoolInterceptor.java50
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/ContextUnit.java165
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/IDecompiledData.java23
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/StructClass.java195
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/StructContext.java189
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/StructField.java58
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/StructMember.java87
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/StructMethod.java392
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructAnnDefaultAttribute.java35
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructAnnotationAttribute.java184
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructAnnotationParameterAttribute.java51
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructAnnotationTypeAttribute.java194
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructBootstrapMethodsAttribute.java66
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructConstantValueAttribute.java34
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructEnclosingMethodAttribute.java55
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructExceptionsAttribute.java52
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructGeneralAttribute.java118
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructGenericSignatureAttribute.java35
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructInnerClassesAttribute.java72
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTableAttribute.java67
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/consts/ConstantPool.java281
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/consts/LinkConstant.java165
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/consts/PooledConstant.java117
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/consts/PrimitiveConstant.java126
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/consts/VariableTypeEnum.java47
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/DataPoint.java100
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/FieldDescriptor.java59
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/MethodDescriptor.java102
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/VarType.java422
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericClassDescriptor.java30
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericFieldDescriptor.java21
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericMain.java249
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericMethodDescriptor.java32
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericType.java268
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/lazy/LazyLoader.java173
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/DataInputFullStream.java55
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/FastFixedSetFactory.java360
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/FastSetFactory.java489
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/FastSparseSetFactory.java552
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/InterpreterUtil.java175
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/ListStack.java93
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/SFormsFastMapDirect.java414
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/VBStyleCollection.java204
-rw-r--r--plugins/java-decompiler/engine/test/org/jetbrains/java/decompiler/BulkDecompilationTest.java110
-rw-r--r--plugins/java-decompiler/engine/test/org/jetbrains/java/decompiler/DecompilerTestFixture.java88
-rw-r--r--plugins/java-decompiler/engine/test/org/jetbrains/java/decompiler/SingleClassesTest.java125
-rw-r--r--plugins/java-decompiler/engine/testData/bulk.jarbin0 -> 1997 bytes
-rw-r--r--plugins/java-decompiler/engine/testData/bulk/META-INF/MANIFEST.MF0
-rw-r--r--plugins/java-decompiler/engine/testData/bulk/pkg/Main.java0
-rw-r--r--plugins/java-decompiler/engine/testData/bulk/pkg/res/Loader.java0
-rw-r--r--plugins/java-decompiler/engine/testData/bulk/pkg/res/resource.txt0
-rw-r--r--plugins/java-decompiler/engine/testData/classes/InvalidMethodSignature.classbin0 -> 761 bytes
-rw-r--r--plugins/java-decompiler/engine/testData/classes/pkg/TestClassCast.classbin0 -> 625 bytes
-rw-r--r--plugins/java-decompiler/engine/testData/classes/pkg/TestClassFields.classbin0 -> 415 bytes
-rw-r--r--plugins/java-decompiler/engine/testData/classes/pkg/TestClassLambda.classbin0 -> 3723 bytes
-rw-r--r--plugins/java-decompiler/engine/testData/classes/pkg/TestClassLoop.classbin0 -> 880 bytes
-rw-r--r--plugins/java-decompiler/engine/testData/classes/pkg/TestClassNestedInitializer$1.classbin0 -> 477 bytes
-rw-r--r--plugins/java-decompiler/engine/testData/classes/pkg/TestClassNestedInitializer.classbin0 -> 599 bytes
-rw-r--r--plugins/java-decompiler/engine/testData/classes/pkg/TestClassSwitch.classbin0 -> 464 bytes
-rw-r--r--plugins/java-decompiler/engine/testData/classes/pkg/TestClassTypes.classbin0 -> 1151 bytes
-rw-r--r--plugins/java-decompiler/engine/testData/classes/pkg/TestClassVar.classbin0 -> 992 bytes
-rw-r--r--plugins/java-decompiler/engine/testData/classes/pkg/TestCodeConstructs.classbin0 -> 513 bytes
-rw-r--r--plugins/java-decompiler/engine/testData/classes/pkg/TestConstants$A.classbin0 -> 293 bytes
-rw-r--r--plugins/java-decompiler/engine/testData/classes/pkg/TestConstants.classbin0 -> 1668 bytes
-rw-r--r--plugins/java-decompiler/engine/testData/classes/pkg/TestDebugSymbols.classbin0 -> 878 bytes
-rw-r--r--plugins/java-decompiler/engine/testData/classes/pkg/TestDeprecations$ByAnno.classbin0 -> 367 bytes
-rw-r--r--plugins/java-decompiler/engine/testData/classes/pkg/TestDeprecations$ByComment.classbin0 -> 308 bytes
-rw-r--r--plugins/java-decompiler/engine/testData/classes/pkg/TestDeprecations.classbin0 -> 576 bytes
-rw-r--r--plugins/java-decompiler/engine/testData/classes/pkg/TestEnum$1.classbin0 -> 363 bytes
-rw-r--r--plugins/java-decompiler/engine/testData/classes/pkg/TestEnum$2.classbin0 -> 428 bytes
-rw-r--r--plugins/java-decompiler/engine/testData/classes/pkg/TestEnum.classbin0 -> 1491 bytes
-rw-r--r--plugins/java-decompiler/engine/testData/classes/pkg/TestExtendsList.class (renamed from plugins/java-decompiler/testData/ExtendsList.class)bin510 -> 522 bytes
-rw-r--r--plugins/java-decompiler/engine/testData/classes/pkg/TestMethodParameters$1Local.classbin0 -> 567 bytes
-rw-r--r--plugins/java-decompiler/engine/testData/classes/pkg/TestMethodParameters$C1.classbin0 -> 519 bytes
-rw-r--r--plugins/java-decompiler/engine/testData/classes/pkg/TestMethodParameters$C2.classbin0 -> 483 bytes
-rw-r--r--plugins/java-decompiler/engine/testData/classes/pkg/TestMethodParameters.classbin0 -> 629 bytes
-rw-r--r--plugins/java-decompiler/engine/testData/results/InvalidMethodSignature.dec26
-rw-r--r--plugins/java-decompiler/engine/testData/results/TestClassCast.dec15
-rw-r--r--plugins/java-decompiler/engine/testData/results/TestClassFields.dec10
-rw-r--r--plugins/java-decompiler/engine/testData/results/TestClassLambda.dec73
-rw-r--r--plugins/java-decompiler/engine/testData/results/TestClassLoop.dec43
-rw-r--r--plugins/java-decompiler/engine/testData/results/TestClassNestedInitializer.dec14
-rw-r--r--plugins/java-decompiler/engine/testData/results/TestClassSwitch.dec14
-rw-r--r--plugins/java-decompiler/engine/testData/results/TestClassTypes.dec49
-rw-r--r--plugins/java-decompiler/engine/testData/results/TestClassVar.dec40
-rw-r--r--plugins/java-decompiler/engine/testData/results/TestCodeConstructs.dec13
-rw-r--r--plugins/java-decompiler/engine/testData/results/TestConstants.dec73
-rw-r--r--plugins/java-decompiler/engine/testData/results/TestDebugSymbols.dec11
-rw-r--r--plugins/java-decompiler/engine/testData/results/TestDeprecations.dec27
-rw-r--r--plugins/java-decompiler/engine/testData/results/TestEnum.dec27
-rw-r--r--plugins/java-decompiler/engine/testData/results/TestExtendsList.dec11
-rw-r--r--plugins/java-decompiler/engine/testData/results/TestMethodParameters.dec42
-rw-r--r--plugins/java-decompiler/engine/testData/src/pkg/TestClassCast.java28
-rw-r--r--plugins/java-decompiler/engine/testData/src/pkg/TestClassFields.java28
-rw-r--r--plugins/java-decompiler/engine/testData/src/pkg/TestClassLambda.java77
-rw-r--r--plugins/java-decompiler/engine/testData/src/pkg/TestClassLoop.java61
-rw-r--r--plugins/java-decompiler/engine/testData/src/pkg/TestClassNestedInitializer.java25
-rw-r--r--plugins/java-decompiler/engine/testData/src/pkg/TestClassSwitch.java30
-rw-r--r--plugins/java-decompiler/engine/testData/src/pkg/TestClassTypes.java69
-rw-r--r--plugins/java-decompiler/engine/testData/src/pkg/TestClassVar.java59
-rw-r--r--plugins/java-decompiler/engine/testData/src/pkg/TestCodeConstructs.java27
-rw-r--r--plugins/java-decompiler/engine/testData/src/pkg/TestConstants.java (renamed from plugins/java-decompiler/testData/Constants.java)19
-rw-r--r--plugins/java-decompiler/engine/testData/src/pkg/TestDebugSymbols.java27
-rw-r--r--plugins/java-decompiler/engine/testData/src/pkg/TestDeprecations.java36
-rw-r--r--plugins/java-decompiler/engine/testData/src/pkg/TestEnum.java36
-rw-r--r--plugins/java-decompiler/engine/testData/src/pkg/TestExtendsList.java26
-rw-r--r--plugins/java-decompiler/engine/testData/src/pkg/TestMethodParameters.java40
-rw-r--r--plugins/java-decompiler/java-decompiler.iml12
-rw-r--r--plugins/java-decompiler/lib/fernflower.jarbin273340 -> 0 bytes
-rw-r--r--plugins/java-decompiler/src/META-INF/plugin.xml2
-rw-r--r--plugins/java-decompiler/src/org/jetbrains/java/decompiler/IdeaDecompiler.java44
-rw-r--r--plugins/java-decompiler/src/org/jetbrains/java/decompiler/IdeaLogger.java24
-rw-r--r--plugins/java-decompiler/test/org/jetbrains/java/decompiler/IdeaDecompilerTest.java113
-rw-r--r--plugins/java-decompiler/testData/Anonymous$1.classbin672 -> 0 bytes
-rw-r--r--plugins/java-decompiler/testData/Anonymous.classbin407 -> 0 bytes
-rw-r--r--plugins/java-decompiler/testData/Anonymous.java13
-rw-r--r--plugins/java-decompiler/testData/Anonymous.txt24
-rw-r--r--plugins/java-decompiler/testData/CodeConstructs.classbin324 -> 0 bytes
-rw-r--r--plugins/java-decompiler/testData/CodeConstructs.java5
-rw-r--r--plugins/java-decompiler/testData/CodeConstructs.txt15
-rw-r--r--plugins/java-decompiler/testData/Constants$A.classbin273 -> 0 bytes
-rw-r--r--plugins/java-decompiler/testData/Constants.classbin1640 -> 0 bytes
-rw-r--r--plugins/java-decompiler/testData/Constants.txt82
-rw-r--r--plugins/java-decompiler/testData/Deprecations$ByAnno.classbin347 -> 0 bytes
-rw-r--r--plugins/java-decompiler/testData/Deprecations$ByComment.classbin288 -> 0 bytes
-rw-r--r--plugins/java-decompiler/testData/Deprecations.classbin548 -> 0 bytes
-rw-r--r--plugins/java-decompiler/testData/Deprecations.java19
-rw-r--r--plugins/java-decompiler/testData/Deprecations.txt42
-rw-r--r--plugins/java-decompiler/testData/Enum$1.classbin335 -> 0 bytes
-rw-r--r--plugins/java-decompiler/testData/Enum$2.classbin392 -> 0 bytes
-rw-r--r--plugins/java-decompiler/testData/Enum.classbin1407 -> 0 bytes
-rw-r--r--plugins/java-decompiler/testData/Enum.java19
-rw-r--r--plugins/java-decompiler/testData/Enum.txt33
-rw-r--r--plugins/java-decompiler/testData/ExtendsList.java9
-rw-r--r--plugins/java-decompiler/testData/ExtendsList.txt19
-rw-r--r--plugins/java-decompiler/testData/Parameters$1Local.classbin501 -> 0 bytes
-rw-r--r--plugins/java-decompiler/testData/Parameters$C1.classbin453 -> 0 bytes
-rw-r--r--plugins/java-decompiler/testData/Parameters$C2.classbin445 -> 0 bytes
-rw-r--r--plugins/java-decompiler/testData/Parameters.classbin563 -> 0 bytes
-rw-r--r--plugins/java-decompiler/testData/Parameters.java23
-rw-r--r--plugins/java-decompiler/testData/Parameters.txt50
-rw-r--r--plugins/java-i18n/java-i18n.iml1
-rw-r--r--plugins/junit/src/com/intellij/execution/ConfigurationUtil.java8
-rw-r--r--plugins/junit/src/com/intellij/execution/junit/JUnitConfiguration.java61
-rw-r--r--plugins/junit/src/com/intellij/execution/junit/TestCategory.java14
-rw-r--r--plugins/junit/src/com/intellij/execution/junit/TestClass.java12
-rw-r--r--plugins/junit/src/com/intellij/execution/junit/TestDirectory.java21
-rw-r--r--plugins/junit/src/com/intellij/execution/junit/TestMethod.java13
-rw-r--r--plugins/junit/src/com/intellij/execution/junit/TestMethods.java20
-rw-r--r--plugins/junit/src/com/intellij/execution/junit/TestObject.java170
-rw-r--r--plugins/junit/src/com/intellij/execution/junit/TestPackage.java8
-rw-r--r--plugins/junit/src/com/intellij/execution/junit/TestsPattern.java8
-rw-r--r--plugins/junit/src/com/intellij/execution/junit2/configuration/JUnitConfigurable.java1
-rw-r--r--plugins/junit/src/com/intellij/execution/junit2/states/ComparisonFailureState.java17
-rw-r--r--plugins/junit/src/com/intellij/execution/junit2/ui/ConsolePanel.java17
-rw-r--r--plugins/junit/src/com/intellij/execution/junit2/ui/JUnitStatusLine.java27
-rw-r--r--plugins/junit/src/com/intellij/execution/junit2/ui/JUnitTreeConsoleView.java3
-rw-r--r--plugins/junit/src/com/intellij/execution/junit2/ui/actions/RerunFailedTestsAction.java22
-rw-r--r--plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitForkedStarter.java49
-rw-r--r--plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitStarter.java15
-rw-r--r--plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/references/MavenPathReferenceConverter.java5
-rw-r--r--plugins/maven/src/main/java/org/jetbrains/idea/maven/plugins/api/common/MavenCommonParamReferenceProviders.java7
-rw-r--r--plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenArtifactDownloader.java4
-rw-r--r--plugins/maven/src/main/resources/META-INF/plugin.xml2
-rw-r--r--plugins/maven/src/test/java/org/jetbrains/idea/maven/MavenImportingTestCase.java2
-rw-r--r--plugins/maven/src/test/java/org/jetbrains/idea/maven/compiler/ManifestGenerationTest.java22
-rw-r--r--plugins/maven/src/test/java/org/jetbrains/idea/maven/compiler/MavenCompilingTestCase.java60
-rw-r--r--plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/PropertiesImplUtil.java11
-rw-r--r--plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfiguration.java7
-rw-r--r--plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryTreeModel.java2
-rw-r--r--plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryTreeNode.java86
-rw-r--r--plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SimpleTextNode.java46
-rw-r--r--plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SvnRepositoryTreeCellRenderer.java15
-rw-r--r--plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/browserCache/CacheLoader.java15
-rw-r--r--plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/browserCache/Loader.java57
-rw-r--r--plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/browserCache/RepositoryLoader.java34
-rw-r--r--plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/JiraRepository.java41
-rw-r--r--plugins/tasks/tasks-core/src/com/intellij/tasks/actions/SwitchTaskCombo.java2
-rw-r--r--plugins/tasks/tasks-core/src/com/intellij/tasks/gitlab/GitlabRepository.java24
-rw-r--r--plugins/tasks/tasks-core/src/com/intellij/tasks/impl/httpclient/NewBaseRepositoryImpl.java42
-rw-r--r--plugins/tasks/tasks-core/src/com/intellij/tasks/redmine/RedmineRepository.java76
-rw-r--r--plugins/tasks/tasks-core/src/com/intellij/tasks/redmine/model/RedmineIssue.java4
-rw-r--r--plugins/tasks/tasks-tests/test/com/intellij/tasks/integration/JiraIntegrationTest.java17
-rw-r--r--plugins/tasks/tasks-tests/test/com/intellij/tasks/integration/RedmineIntegrationTest.java17
-rw-r--r--plugins/terminal/src/org/jetbrains/plugins/terminal/JBTerminalSystemSettingsProvider.java4
-rw-r--r--plugins/terminal/src/org/jetbrains/plugins/terminal/LocalTerminalDirectRunner.java2
-rw-r--r--plugins/testng/src/META-INF/plugin.xml1
-rw-r--r--plugins/testng/src/com/theoryinpractice/testng/TestNGReferenceContributor.java28
-rw-r--r--plugins/testng/src/com/theoryinpractice/testng/configuration/SearchingForTestsTask.java3
-rw-r--r--plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGRunnableState.java26
-rw-r--r--plugins/testng/src/com/theoryinpractice/testng/model/TestProxy.java12
-rw-r--r--plugins/testng/src/com/theoryinpractice/testng/ui/actions/RerunFailedTestsAction.java18
-rw-r--r--plugins/ui-designer-core/src/com/intellij/designer/AbstractToolWindowManager.java302
-rw-r--r--plugins/ui-designer-core/src/com/intellij/designer/DesignerToolWindowManager.java8
-rw-r--r--plugins/ui-designer-core/src/com/intellij/designer/PaletteToolWindowContent.java11
-rw-r--r--plugins/ui-designer-core/src/com/intellij/designer/designSurface/DesignerEditorPanel.java102
-rw-r--r--plugins/ui-designer-core/src/com/intellij/designer/palette/PalettePanel.java6
-rw-r--r--plugins/ui-designer-core/src/com/intellij/designer/palette/PaletteToolWindowManager.java11
-rw-r--r--plugins/ui-designer/src/META-INF/plugin.xml11
-rw-r--r--plugins/ui-designer/src/com/intellij/ide/palette/PaletteDragEventListener.java (renamed from java/openapi/src/com/intellij/ide/palette/PaletteDragEventListener.java)0
-rw-r--r--plugins/ui-designer/src/com/intellij/ide/palette/PaletteGroup.java (renamed from java/openapi/src/com/intellij/ide/palette/PaletteGroup.java)0
-rw-r--r--plugins/ui-designer/src/com/intellij/ide/palette/PaletteItem.java (renamed from java/openapi/src/com/intellij/ide/palette/PaletteItem.java)0
-rw-r--r--plugins/ui-designer/src/com/intellij/ide/palette/PaletteItemProvider.java (renamed from java/openapi/src/com/intellij/ide/palette/PaletteItemProvider.java)0
-rw-r--r--plugins/ui-designer/src/com/intellij/ide/palette/impl/PaletteComponentList.java (renamed from java/idea-ui/src/com/intellij/ide/palette/impl/PaletteComponentList.java)12
-rw-r--r--plugins/ui-designer/src/com/intellij/ide/palette/impl/PaletteContentWindow.java (renamed from java/idea-ui/src/com/intellij/ide/palette/impl/PaletteContentWindow.java)0
-rw-r--r--plugins/ui-designer/src/com/intellij/ide/palette/impl/PaletteGroupHeader.java (renamed from java/idea-ui/src/com/intellij/ide/palette/impl/PaletteGroupHeader.java)0
-rw-r--r--plugins/ui-designer/src/com/intellij/ide/palette/impl/PaletteToolWindowManager.java118
-rw-r--r--plugins/ui-designer/src/com/intellij/ide/palette/impl/PaletteWindow.java (renamed from java/idea-ui/src/com/intellij/ide/palette/impl/PaletteWindow.java)101
-rw-r--r--plugins/ui-designer/src/com/intellij/uiDesigner/AbstractToolWindowManager.java67
-rw-r--r--plugins/ui-designer/src/com/intellij/uiDesigner/FormEditingUtil.java10
-rw-r--r--plugins/ui-designer/src/com/intellij/uiDesigner/FormHighlightingPass.java6
-rw-r--r--plugins/ui-designer/src/com/intellij/uiDesigner/actions/ExpandSelectionAction.java13
-rw-r--r--plugins/ui-designer/src/com/intellij/uiDesigner/actions/ResetValueAction.java7
-rw-r--r--plugins/ui-designer/src/com/intellij/uiDesigner/actions/SelectAllComponentsAction.java12
-rw-r--r--plugins/ui-designer/src/com/intellij/uiDesigner/actions/ShowFormSourceAction.java32
-rw-r--r--plugins/ui-designer/src/com/intellij/uiDesigner/actions/ShrinkSelectionAction.java6
-rw-r--r--plugins/ui-designer/src/com/intellij/uiDesigner/componentTree/ComponentTreeBuilder.java4
-rw-r--r--plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/DesignDropTargetListener.java32
-rw-r--r--plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/GlassLayer.java4
-rw-r--r--plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/GridCaptionPanel.java20
-rw-r--r--plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/GuiEditor.java213
-rw-r--r--plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/InsertComponentProcessor.java12
-rw-r--r--plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/MainProcessor.java12
-rw-r--r--plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/PassiveDecorationLayer.java4
-rw-r--r--plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/QuickFixManagerImpl.java10
-rw-r--r--plugins/ui-designer/src/com/intellij/uiDesigner/editor/UIFormEditor.java4
-rw-r--r--plugins/ui-designer/src/com/intellij/uiDesigner/editor/UIFormEditorProvider.java8
-rw-r--r--plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/DesignerToolWindow.java139
-rw-r--r--plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/DesignerToolWindowManager.java131
-rw-r--r--plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/PropertyInspectorTable.java3
-rw-r--r--plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/UIDesignerToolWindowManager.java264
-rw-r--r--plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/editors/BindingEditor.java5
-rw-r--r--plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/editors/string/StringEditor.java6
-rw-r--r--plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/properties/BindingProperty.java4
-rw-r--r--plugins/ui-designer/src/com/intellij/uiDesigner/quickFixes/ShowHintAction.java5
-rw-r--r--plugins/ui-designer/src/messages/UIDesignerBundle.properties5
-rw-r--r--plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/run/HighlightingOutputConsole.java2
-rw-r--r--plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/run/XsltRunConfiguration.java42
-rw-r--r--plugins/xpath/xpath-view/src/org/intellij/plugins/xpathView/ShowXPathAction.java2
-rw-r--r--plugins/xpath/xpath-view/src/org/intellij/plugins/xpathView/XPathAction.java9
-rw-r--r--plugins/xpath/xpath-view/src/org/intellij/plugins/xpathView/search/SearchScope.java9
-rw-r--r--plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/XsltDebuggerExtension.java14
-rw-r--r--plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/AbstractTabComponent.java4
-rw-r--r--python/edu/build/pycharm_edu_build.gant8
-rw-r--r--python/edu/build/upload_pythonInfo.xml2
-rw-r--r--python/edu/course-creator/resources/META-INF/plugin.xml14
-rw-r--r--python/edu/course-creator/resources/fileTemplates/internal/task.answer.ft1
-rw-r--r--python/edu/course-creator/resources/fileTemplates/internal/task.py.ft1
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/AnswerFileType.java40
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/AnswerFileTypeFactory.java28
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCEditorFactoryListener.java13
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCProjectComponent.java141
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCProjectService.java52
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCRefactoringElementListenerProvider.java96
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCRunTests.java284
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/RunTestsLineMarker.java109
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/StudyDocumentListener.java5
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/AddTaskWindow.java5
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCRename.java97
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCRenameLesson.java48
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCRenameTask.java57
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCShowPreview.java104
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CreateCourseArchive.java188
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CreateTask.java14
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CreateTaskFile.java6
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/Course.java14
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/Lesson.java31
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/Task.java20
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/TaskFile.java27
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/TaskWindow.java11
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/projectView/CCDirectoryNode.java2
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/projectView/CCTreeStructureProvider.java18
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/ui/CreateCourseArchivePanel.form2
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/ui/CreateTaskWindowDialog.java6
-rw-r--r--python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/ui/CreateTaskWindowPanel.java5
-rw-r--r--python/edu/learn-python/resources/META-INF/plugin.xml7
-rw-r--r--python/edu/learn-python/resources/courses/introduction_course.zipbin93557 -> 95274 bytes
-rw-r--r--python/edu/learn-python/src/com/jetbrains/python/edu/StudyDirectoryProjectGenerator.java2
-rw-r--r--python/edu/learn-python/src/com/jetbrains/python/edu/StudyTestRunner.java4
-rw-r--r--python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyIntroductionCourseAction.java75
-rw-r--r--python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyRefreshTaskFileAction.java211
-rw-r--r--python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyReloadCourseAction.java134
-rw-r--r--python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyTaskNavigationAction.java7
-rw-r--r--python/edu/learn-python/src/com/jetbrains/python/edu/projectView/StudyDirectoryNode.java55
-rw-r--r--python/edu/learn-python/src/com/jetbrains/python/edu/ui/StudyToolWindowFactory.java11
-rw-r--r--python/edu/resources/idea/PyCharmEduApplicationInfo.xml2
-rw-r--r--python/helpers/packaging_tool.py14
-rw-r--r--python/helpers/pycharm/_bdd_utils.py37
-rw-r--r--python/helpers/pycharm/behave_runner.py38
-rw-r--r--python/helpers/pycharm/lettuce_runner.py51
-rw-r--r--python/helpers/pycharm_generator_utils/clr_tools.py13
-rw-r--r--python/helpers/pydev/django_debug.py124
-rw-r--r--python/helpers/pydev/django_frame.py132
-rw-r--r--python/helpers/pydev/pydev_log.py9
-rw-r--r--python/helpers/pydev/pydev_monkey_qt.py7
-rw-r--r--python/helpers/pydev/pydev_run_in_console.py19
-rw-r--r--python/helpers/pydev/pydevconsole.py13
-rw-r--r--python/helpers/pydev/pydevd.py185
-rw-r--r--python/helpers/pydev/pydevd_breakpoints.py2
-rw-r--r--python/helpers/pydev/pydevd_constants.py1
-rw-r--r--python/helpers/pydev/pydevd_frame.py274
-rw-r--r--python/helpers/pydev/pydevd_frame_utils.py31
-rw-r--r--python/helpers/pydev/pydevd_plugin_utils.py85
-rw-r--r--python/helpers/pydev/pydevd_plugins/__init__.py0
-rw-r--r--python/helpers/pydev/pydevd_plugins/django_debug.py357
-rw-r--r--python/helpers/pydev/pydevd_plugins/jinja2_debug.py341
-rw-r--r--python/helpers/pydev/pydevd_resolver.py14
-rw-r--r--python/helpers/pydev/pydevd_trace_api.py35
-rw-r--r--python/helpers/pydev/pydevd_utils.py23
-rw-r--r--python/helpers/pydev/pydevd_vars.py11
-rw-r--r--python/helpers/pydev/test_debug.py4
-rw-r--r--python/helpers/pydev/tests/check_pydevconsole.py110
-rw-r--r--python/helpers/pydev/tests/test_pydev_ipython_010.py80
-rw-r--r--python/helpers/pydev/tests_python/_debugger_case_qthread3.py1
-rw-r--r--python/helpers/pydev/third_party/pkgutil_old.py591
-rw-r--r--python/helpers/pydev/third_party/pluginbase.py454
-rw-r--r--python/helpers/pydev/third_party/uuid_old.py541
-rw-r--r--python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java18
-rw-r--r--python/ide/src/com/jetbrains/python/newProject/actions/AbstractProjectSettingsStep.java74
-rw-r--r--python/ide/src/com/jetbrains/python/newProject/actions/GenerateProjectCallback.java2
-rw-r--r--python/openapi/src/com/jetbrains/python/documentation/PythonDocumentationQuickInfoProvider.java25
-rw-r--r--python/openapi/src/com/jetbrains/python/packaging/PyPackageManager.java42
-rw-r--r--python/openapi/src/com/jetbrains/python/packaging/PyPackageManagers.java22
-rw-r--r--python/openapi/src/com/jetbrains/python/templateLanguages/PyTemplatesUtil.java4
-rw-r--r--python/psi-api/src/com/jetbrains/python/PyNames.java2
-rw-r--r--python/pydevSrc/com/jetbrains/python/debugger/IPyDebugProcess.java6
-rw-r--r--python/pydevSrc/com/jetbrains/python/debugger/PyDebugValue.java53
-rw-r--r--python/pydevSrc/com/jetbrains/python/debugger/PyFrameAccessor.java3
-rw-r--r--python/pydevSrc/com/jetbrains/python/debugger/PyReferrersLoader.java20
-rw-r--r--python/pydevSrc/com/jetbrains/python/debugger/PyReferringObjectsValue.java71
-rw-r--r--python/pydevSrc/com/jetbrains/python/debugger/PyThreadInfo.java2
-rw-r--r--python/pydevSrc/com/jetbrains/python/debugger/PyTypeHandler.java3
-rw-r--r--python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractCommand.java12
-rw-r--r--python/pydevSrc/com/jetbrains/python/debugger/pydev/ConsoleExecCommand.java2
-rw-r--r--python/pydevSrc/com/jetbrains/python/debugger/pydev/GetReferrersCommand.java50
-rw-r--r--python/pydevSrc/com/jetbrains/python/debugger/pydev/GetVariableCommand.java32
-rw-r--r--python/pydevSrc/com/jetbrains/python/debugger/pydev/MultiProcessDebugger.java12
-rw-r--r--python/pydevSrc/com/jetbrains/python/debugger/pydev/ProcessDebugger.java17
-rw-r--r--python/pydevSrc/com/jetbrains/python/debugger/pydev/ProtocolParser.java26
-rw-r--r--python/pydevSrc/com/jetbrains/python/debugger/pydev/PyDebugCallback.java12
-rw-r--r--python/pydevSrc/com/jetbrains/python/debugger/pydev/PyVariableLocator.java17
-rw-r--r--python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java50
-rw-r--r--python/pydevSrc/com/jetbrains/python/debugger/pydev/RunCustomOperationCommand.java86
-rw-r--r--python/python-rest/src/com/jetbrains/rest/RestPythonUtil.java5
-rw-r--r--python/src/META-INF/pycharm-core.xml8
-rw-r--r--python/src/META-INF/python-core.xml25
-rw-r--r--python/src/com/jetbrains/python/PyBundle.properties3
-rw-r--r--python/src/com/jetbrains/python/codeInsight/completion/PyKeywordCompletionContributor.java17
-rw-r--r--python/src/com/jetbrains/python/codeInsight/editorActions/moveUpDown/PyStatementMover.java31
-rw-r--r--python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyWithFixer.java10
-rw-r--r--python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.java2
-rw-r--r--python/src/com/jetbrains/python/console/PydevConsoleCommunication.java10
-rw-r--r--python/src/com/jetbrains/python/console/PythonDebugConsoleCommunication.java8
-rw-r--r--python/src/com/jetbrains/python/debugger/PyDebugProcess.java28
-rw-r--r--python/src/com/jetbrains/python/debugger/PyDebugSupportUtils.java22
-rw-r--r--python/src/com/jetbrains/python/debugger/PyExceptionBreakpointProperties.java5
-rw-r--r--python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java14
-rw-r--r--python/src/com/jetbrains/python/findUsages/PyFunctionFindUsagesHandler.java4
-rw-r--r--python/src/com/jetbrains/python/hierarchy/PyHierarchyNodeDescriptor.java (renamed from python/src/com/jetbrains/python/hierarchy/PyTypeHierarchyNodeDescriptor.java)31
-rw-r--r--python/src/com/jetbrains/python/hierarchy/PyTypeHierarchyBrowser.java4
-rw-r--r--python/src/com/jetbrains/python/hierarchy/call/PyCallHierarchyBrowser.java101
-rw-r--r--python/src/com/jetbrains/python/hierarchy/call/PyCallHierarchyProvider.java76
-rw-r--r--python/src/com/jetbrains/python/hierarchy/call/PyCallHierarchyTreeStructureBase.java85
-rw-r--r--python/src/com/jetbrains/python/hierarchy/call/PyCalleeFunctionTreeStructure.java42
-rw-r--r--python/src/com/jetbrains/python/hierarchy/call/PyCallerFunctionTreeStructure.java42
-rw-r--r--python/src/com/jetbrains/python/hierarchy/call/PyStaticCallHierarchyUtil.java163
-rw-r--r--python/src/com/jetbrains/python/hierarchy/treestructures/PySubTypesHierarchyTreeStructure.java18
-rw-r--r--python/src/com/jetbrains/python/hierarchy/treestructures/PySuperTypesHierarchyTreeStructure.java25
-rw-r--r--python/src/com/jetbrains/python/hierarchy/treestructures/PyTypeHierarchyTreeStructure.java27
-rw-r--r--python/src/com/jetbrains/python/inspections/PyPackageRequirementsInspection.java97
-rw-r--r--python/src/com/jetbrains/python/inspections/quickfix/GenerateBinaryStubsFix.java2
-rw-r--r--python/src/com/jetbrains/python/inspections/quickfix/PyDefaultArgumentQuickFix.java2
-rw-r--r--python/src/com/jetbrains/python/inspections/quickfix/StatementEffectFunctionCallQuickFix.java21
-rw-r--r--python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java5
-rw-r--r--python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java665
-rw-r--r--python/src/com/jetbrains/python/packaging/PyPackageManagerUI.java367
-rw-r--r--python/src/com/jetbrains/python/packaging/PyPackageManagersImpl.java24
-rw-r--r--python/src/com/jetbrains/python/packaging/PyRemotePackageManagerImpl.java177
-rw-r--r--python/src/com/jetbrains/python/packaging/ui/PyInstalledPackagesPanel.java119
-rw-r--r--python/src/com/jetbrains/python/packaging/ui/PyPackageManagementService.java15
-rw-r--r--python/src/com/jetbrains/python/projectView/PyElementNode.java24
-rw-r--r--python/src/com/jetbrains/python/psi/PyUtil.java4
-rw-r--r--python/src/com/jetbrains/python/psi/impl/PyClassImpl.java32
-rw-r--r--python/src/com/jetbrains/python/psi/impl/PyElementPresentation.java76
-rw-r--r--python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java84
-rw-r--r--python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java8
-rw-r--r--python/src/com/jetbrains/python/psi/impl/PyPresentableElementImpl.java73
-rw-r--r--python/src/com/jetbrains/python/psi/impl/PySingleStarParameterImpl.java20
-rw-r--r--python/src/com/jetbrains/python/psi/impl/PyStringLiteralExpressionImpl.java2
-rw-r--r--python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java22
-rw-r--r--python/src/com/jetbrains/python/psi/impl/PyTupleParameterImpl.java15
-rw-r--r--python/src/com/jetbrains/python/psi/impl/PythonLanguageLevelPusher.java5
-rw-r--r--python/src/com/jetbrains/python/refactoring/changeSignature/PyChangeSignatureHandler.java2
-rw-r--r--python/src/com/jetbrains/python/refactoring/move/PyMoveClassOrFunctionDelegate.java3
-rw-r--r--python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.java6
-rw-r--r--python/src/com/jetbrains/python/sdk/PySdkUtil.java153
-rw-r--r--python/src/com/jetbrains/python/sdk/PythonSdkDetailsStep.java6
-rw-r--r--python/src/com/jetbrains/python/sdk/PythonSdkType.java26
-rw-r--r--python/src/com/jetbrains/python/sdk/PythonSdkUpdater.java3
-rw-r--r--python/src/com/jetbrains/python/sdk/flavors/WinPythonSdkFlavor.java33
-rw-r--r--python/src/com/jetbrains/python/sdk/skeletons/PySkeletonGenerator.java39
-rw-r--r--python/src/com/jetbrains/python/sdk/skeletons/PySkeletonRefresher.java152
-rw-r--r--python/src/com/jetbrains/python/statistics/PyPackageUsagesCollector.java6
-rw-r--r--python/src/com/jetbrains/python/structureView/PyStructureViewElement.java33
-rw-r--r--python/src/com/jetbrains/python/testing/PyRerunFailedTestsAction.java33
-rw-r--r--python/src/com/jetbrains/python/testing/PythonTestCommandLineStateBase.java4
-rw-r--r--python/src/com/jetbrains/python/testing/TestRunConfigurationReRunResponsible.java30
-rw-r--r--python/src/com/jetbrains/python/testing/VFSTestFrameworkListener.java5
-rw-r--r--python/src/com/jetbrains/python/testing/pytest/PyTestConfigurationProducer.java5
-rw-r--r--python/src/com/jetbrains/python/validation/Pep8ExternalAnnotator.java3
-rw-r--r--python/src/com/jetbrains/python/validation/StringLiteralQuotesAnnotator.java45
-rw-r--r--python/testData/codeInsight/smartEnter/withOnlyColonMissing.py1
-rw-r--r--python/testData/codeInsight/smartEnter/withOnlyColonMissing_after.py2
-rw-r--r--python/testData/hierarchy/call/Static/ArgumentList/ArgumentList_callee_verification.xml1
-rw-r--r--python/testData/hierarchy/call/Static/ArgumentList/ArgumentList_caller_verification.xml1
-rw-r--r--python/testData/hierarchy/call/Static/ArgumentList/file_1.py8
-rw-r--r--python/testData/hierarchy/call/Static/ArgumentList/main.py8
-rw-r--r--python/testData/hierarchy/call/Static/Constructor/Constructor_callee_verification.xml8
-rw-r--r--python/testData/hierarchy/call/Static/Constructor/Constructor_caller_verification.xml6
-rw-r--r--python/testData/hierarchy/call/Static/Constructor/main.py32
-rw-r--r--python/testData/hierarchy/call/Static/DefaultValue/DefaultValue_callee_verification.xml1
-rw-r--r--python/testData/hierarchy/call/Static/DefaultValue/DefaultValue_caller_verification.xml4
-rw-r--r--python/testData/hierarchy/call/Static/DefaultValue/main.py30
-rw-r--r--python/testData/hierarchy/call/Static/Inheritance/Inheritance_callee_verification.xml1
-rw-r--r--python/testData/hierarchy/call/Static/Inheritance/Inheritance_caller_verification.xml4
-rw-r--r--python/testData/hierarchy/call/Static/Inheritance/main.py36
-rw-r--r--python/testData/hierarchy/call/Static/InnerFunction/InnerFunction_callee_verification.xml5
-rw-r--r--python/testData/hierarchy/call/Static/InnerFunction/InnerFunction_caller_verification.xml1
-rw-r--r--python/testData/hierarchy/call/Static/InnerFunction/main.py9
-rw-r--r--python/testData/hierarchy/call/Static/Lambda/Lambda_callee_verification.xml8
-rw-r--r--python/testData/hierarchy/call/Static/Lambda/Lambda_caller_verification.xml1
-rw-r--r--python/testData/hierarchy/call/Static/Lambda/file_1.py18
-rw-r--r--python/testData/hierarchy/call/Static/Lambda/main.py18
-rw-r--r--python/testData/hierarchy/call/Static/NestedCall/NestedCall_callee_verification.xml12
-rw-r--r--python/testData/hierarchy/call/Static/NestedCall/NestedCall_caller_verification.xml1
-rw-r--r--python/testData/hierarchy/call/Static/NestedCall/file_1.py10
-rw-r--r--python/testData/hierarchy/call/Static/NestedCall/main.py10
-rw-r--r--python/testData/hierarchy/call/Static/OverriddenMethod/OverriddenMethod_callee_verification.xml3
-rw-r--r--python/testData/hierarchy/call/Static/OverriddenMethod/OverriddenMethod_caller_verification.xml5
-rw-r--r--python/testData/hierarchy/call/Static/OverriddenMethod/file_1.py8
-rw-r--r--python/testData/hierarchy/call/Static/OverriddenMethod/main.py29
-rw-r--r--python/testData/hierarchy/call/Static/Parentheses/Parentheses_callee_verification.xml3
-rw-r--r--python/testData/hierarchy/call/Static/Parentheses/Parentheses_caller_verification.xml3
-rw-r--r--python/testData/hierarchy/call/Static/Parentheses/file_1.py20
-rw-r--r--python/testData/hierarchy/call/Static/Parentheses/main.py7
-rw-r--r--python/testData/hierarchy/call/Static/Simple/Simple_callee_verification.xml3
-rw-r--r--python/testData/hierarchy/call/Static/Simple/Simple_caller_verification.xml3
-rw-r--r--python/testData/hierarchy/call/Static/Simple/main.py10
-rw-r--r--python/testData/highlighting/multipleEscapedBackslashes.py2
-rw-r--r--python/testData/inspections/DefaultArgumentEmptyList.py2
-rw-r--r--python/testData/inspections/DefaultArgumentEmptyList_after.py2
-rw-r--r--python/testData/mover/outsideFromDict.py5
-rw-r--r--python/testData/mover/outsideFromDict_afterDown.py5
-rw-r--r--python/testData/mover/outsideFromDict_afterUp.py5
-rw-r--r--python/testData/mover/sameLevelAsDict.py9
-rw-r--r--python/testData/mover/sameLevelAsDict_afterDown.py9
-rw-r--r--python/testData/mover/sameLevelAsDict_afterUp.py9
-rw-r--r--python/testSrc/com/jetbrains/env/python/PyPackagingTest.java18
-rw-r--r--python/testSrc/com/jetbrains/env/python/PythonDebuggerTest.java21
-rw-r--r--python/testSrc/com/jetbrains/env/ut/PyUnitTestTask.java108
-rw-r--r--python/testSrc/com/jetbrains/python/PySmartEnterTest.java5
-rw-r--r--python/testSrc/com/jetbrains/python/PyStatementMoverTest.java8
-rw-r--r--python/testSrc/com/jetbrains/python/PythonHighlightingTest.java4
-rw-r--r--python/testSrc/com/jetbrains/python/PythonKeywordCompletionTest.java11
-rw-r--r--python/testSrc/com/jetbrains/python/fixtures/PyTestCase.java66
-rw-r--r--python/testSrc/com/jetbrains/python/hierarchy/PyCallHierarchyTest.java158
-rw-r--r--python/testSrc/com/jetbrains/python/refactoring/PyInlineLocalTest.java16
-rw-r--r--python/testSrc/com/jetbrains/python/sdkTools/PyTestSdkTools.java2
-rw-r--r--resources-en/src/messages/CompilerBundle.properties2
-rw-r--r--resources-en/src/messages/DebuggerBundle.properties13
-rw-r--r--resources/src/META-INF/IdeaPlugin.xml4
-rw-r--r--resources/src/componentSets/IdeaComponents.xml1
-rw-r--r--resources/src/componentSets/Toolwindows.xml7
-rw-r--r--resources/src/idea/JavaActions.xml4
-rw-r--r--resources/src/idea/RichPlatformActions.xml2
-rw-r--r--resources/src/idea/RichPlatformPlugin.xml3
-rw-r--r--resources/src/idea/RunManager.xml2
-rw-r--r--spellchecker/src/com/intellij/spellchecker/quickfixes/DictionarySuggestionProvider.java3
-rw-r--r--spellchecker/src/com/intellij/spellchecker/state/CachedDictionaryState.java7
-rwxr-xr-xupdater/src/com/intellij/updater/Runner.java8
-rw-r--r--xml/dom-impl/src/com/intellij/util/xml/impl/DomInvocationHandler.java11
-rw-r--r--xml/dom-impl/src/com/intellij/util/xml/impl/IndexedElementInvocationHandler.java2
-rw-r--r--xml/dom-impl/src/com/intellij/util/xml/stubs/StubParentStrategy.java21
-rw-r--r--xml/dom-tests/tests/com/intellij/util/xml/stubs/DomStubTest.java28
-rw-r--r--xml/impl/src/com/intellij/application/options/editor/WebEditorOptionsForm.form21
-rw-r--r--xml/impl/src/com/intellij/application/options/editor/WebEditorOptionsProvider.java6
-rw-r--r--xml/impl/src/com/intellij/codeInsight/editorActions/XmlEqTypedHandler.java2
-rw-r--r--xml/impl/src/com/intellij/codeInsight/editorActions/XmlSlashTypedHandler.java2
-rw-r--r--xml/impl/src/com/intellij/codeInsight/template/emmet/EmmetParser.java8
-rw-r--r--xml/impl/src/com/intellij/codeInsight/template/emmet/XmlEmmetParser.java2
-rw-r--r--xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/MoreOperationNode.java8
-rw-r--r--xml/impl/src/com/intellij/xml/arrangement/XmlArrangementVisitor.java2
-rw-r--r--xml/impl/src/com/intellij/xml/refactoring/SchemaPrefixRenameHandler.java19
-rw-r--r--xml/impl/src/com/intellij/xml/refactoring/XmlInlineHandler.java7
-rw-r--r--xml/impl/src/org/jetbrains/io/fastCgi/FastCgiChannelHandler.java9
-rw-r--r--xml/relaxng/src/org/intellij/html/RelaxedHtmlFromRngElementDescriptor.java3
-rw-r--r--xml/relaxng/src/org/intellij/plugins/relaxNG/convert/ConvertSchemaSettingsImpl.java2
-rw-r--r--xml/relaxng/src/resources/html5-schema/html5-svg-mathml.rnc2
-rw-r--r--xml/relaxng/src/resources/html5-schema/xhtml5-svg-mathml.rnc2
-rw-r--r--xml/relaxng/src/resources/patches/0007_html5_svg_tiny.patch11
-rw-r--r--xml/relaxng/src/resources/patches/0008_xhtml5_svg_tiny.patch11
-rw-r--r--xml/xml-analysis-impl/src/com/intellij/application/options/editor/WebEditorOptions.java41
-rw-r--r--xml/xml-analysis-impl/src/com/intellij/xml/util/XmlRefCountHolder.java14
-rw-r--r--xml/xml-psi-impl/resources/standardSchemas/xlink.dtd66
-rw-r--r--xml/xml-psi-impl/src/com/intellij/javaee/ExternalResourceManagerExImpl.java85
-rw-r--r--xml/xml-psi-impl/src/com/intellij/javaee/InternalResourceProvider.java1
-rw-r--r--xml/xml-psi-impl/src/com/intellij/javaee/ProjectResources.java31
-rw-r--r--xml/xml-psi-impl/src/com/intellij/lexer/HtmlHighlightingLexer.java121
-rw-r--r--xml/xml-psi-impl/src/com/intellij/psi/XmlElementFactoryImpl.java13
-rw-r--r--xml/xml-psi-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/XmlAttributeValueManipulator.java3
-rw-r--r--xml/xml-psi-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/XmlTextManipulator.java3
-rw-r--r--xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/XmlTagImpl.java89
-rw-r--r--xml/xml-psi-impl/src/com/intellij/xml/HtmlXmlExtension.java13
-rw-r--r--xml/xml-psi-impl/src/com/intellij/xml/XmlCoreEnvironment.java5
-rw-r--r--xml/xml-psi-impl/src/com/intellij/xml/impl/schema/XmlNSDescriptorImpl.java520
-rw-r--r--xml/xml-psi-impl/src/com/intellij/xml/util/XmlUtil.java122
1846 files changed, 76283 insertions, 17172 deletions
diff --git a/.gitignore b/.gitignore
index 8ccf95b67a7e..78fbd0bfb226 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+/android
/config
/system
.idea/workspace.xml
diff --git a/.idea/libraries/JSch.xml b/.idea/libraries/JSch.xml
index 196b08ba1091..27c51c853ea3 100644
--- a/.idea/libraries/JSch.xml
+++ b/.idea/libraries/JSch.xml
@@ -1,12 +1,12 @@
<component name="libraryTable">
<library name="JSch">
<CLASSES>
- <root url="jar://$PROJECT_DIR$/lib/jsch-0.1.50.jar!/" />
+ <root url="jar://$PROJECT_DIR$/lib/jsch-0.1.51.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
- <root url="jar://$PROJECT_DIR$/lib/src/jsch-0.1.50.zip!/jsch-0.1.50/src/main/java" />
- <root url="jar://$PROJECT_DIR$/lib/src/jsch-0.1.50.zip!/jsch-0.1.50/examples" />
+ <root url="jar://$PROJECT_DIR$/lib/src/jsch-0.1.51.zip!/jsch-0.1.51/src/main/java" />
+ <root url="jar://$PROJECT_DIR$/lib/src/jsch-0.1.51.zip!/jsch-0.1.51/examples" />
</SOURCES>
</library>
</component> \ No newline at end of file
diff --git a/.idea/libraries/guava_tools.xml b/.idea/libraries/guava_tools.xml
index ac5f2f6b6ec6..b492cf4758e7 100644
--- a/.idea/libraries/guava_tools.xml
+++ b/.idea/libraries/guava_tools.xml
@@ -1,11 +1,11 @@
<component name="libraryTable">
<library name="guava-tools">
<CLASSES>
- <root url="jar://$PROJECT_DIR$/../../prebuilts/tools/common/m2/repository/com/google/guava/guava/15.0/guava-15.0.jar!/" />
+ <root url="jar://$PROJECT_DIR$/lib/guava-17.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
- <root url="jar://$PROJECT_DIR$/../../prebuilts/tools/common/m2/repository/com/google/guava/guava/15.0/guava-15.0-sources.jar!/" />
+ <root url="jar://$PROJECT_DIR$/lib/src/guava-17.0-sources.jar!/" />
</SOURCES>
</library>
</component> \ No newline at end of file
diff --git a/.idea/libraries/javawriter.xml b/.idea/libraries/javawriter.xml
new file mode 100644
index 000000000000..1d73b23855f5
--- /dev/null
+++ b/.idea/libraries/javawriter.xml
@@ -0,0 +1,11 @@
+<component name="libraryTable">
+ <library name="javawriter">
+ <CLASSES>
+ <root url="jar://$PROJECT_DIR$/android/android/lib/javawriter-2.2.1.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES>
+ <root url="jar://$PROJECT_DIR$/android/android/lib/src/javawriter-2.2.1-sources.jar!/" />
+ </SOURCES>
+ </library>
+</component> \ No newline at end of file
diff --git a/.idea/libraries/winp.xml b/.idea/libraries/winp.xml
index 6e23b6ef4581..07689aee601a 100644
--- a/.idea/libraries/winp.xml
+++ b/.idea/libraries/winp.xml
@@ -1,11 +1,12 @@
<component name="libraryTable">
<library name="winp">
<CLASSES>
- <root url="jar://$PROJECT_DIR$/lib/winp-1.17-patched.jar!/" />
+ <root url="jar://$PROJECT_DIR$/lib/winp-1.21-patched.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
- <root url="jar://$PROJECT_DIR$/lib/src/winp-1.17-patched-src.zip!/" />
+ <root url="jar://$PROJECT_DIR$/lib/src/winp-1.21-patched.zip!/winp-1.21/src/main/java" />
+ <root url="jar://$PROJECT_DIR$/lib/src/winp-1.21-patched.zip!/winp-1.21/src/test/java" />
</SOURCES>
</library>
</component> \ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 2d80274f2dc4..62b77e8702b0 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -80,7 +80,6 @@
<module fileurl="file://$PROJECT_DIR$/../studio/cloud/google-cloud-tools.iml" filepath="$PROJECT_DIR$/../studio/cloud/google-cloud-tools.iml" group="plugins/Google" />
<module fileurl="file://$PROJECT_DIR$/../studio/cloud/login/google-login.iml" filepath="$PROJECT_DIR$/../studio/cloud/login/google-login.iml" group="plugins/Google" />
<module fileurl="file://$PROJECT_DIR$/plugins/gradle/gradle.iml" filepath="$PROJECT_DIR$/plugins/gradle/gradle.iml" group="community/plugins/gradle" />
- <module fileurl="file://$PROJECT_DIR$/../base/gradle-import/gradle-import.iml" filepath="$PROJECT_DIR$/../base/gradle-import/gradle-import.iml" group="plugins/Android/android-sdk" />
<module fileurl="file://$PROJECT_DIR$/plugins/gradle/jps-plugin/gradle-jps-plugin.iml" filepath="$PROJECT_DIR$/plugins/gradle/jps-plugin/gradle-jps-plugin.iml" group="community/plugins/gradle" />
<module fileurl="file://$PROJECT_DIR$/plugins/gradle/tooling-extension-api/gradle-tooling-extension-api.iml" filepath="$PROJECT_DIR$/plugins/gradle/tooling-extension-api/gradle-tooling-extension-api.iml" group="community/plugins/gradle" />
<module fileurl="file://$PROJECT_DIR$/plugins/gradle/tooling-extension-impl/gradle-tooling-extension-impl.iml" filepath="$PROJECT_DIR$/plugins/gradle/tooling-extension-impl/gradle-tooling-extension-impl.iml" group="community/plugins/gradle" />
@@ -136,6 +135,7 @@
<module fileurl="file://$PROJECT_DIR$/../base/lint/libs/lint-checks/lint-checks.iml" filepath="$PROJECT_DIR$/../base/lint/libs/lint-checks/lint-checks.iml" group="plugins/Android/android-sdk/lint" />
<module fileurl="file://$PROJECT_DIR$/platform/lvcs-api/lvcs-api.iml" filepath="$PROJECT_DIR$/platform/lvcs-api/lvcs-api.iml" group="platform" />
<module fileurl="file://$PROJECT_DIR$/platform/lvcs-impl/lvcs-impl.iml" filepath="$PROJECT_DIR$/platform/lvcs-impl/lvcs-impl.iml" group="platform" />
+ <module fileurl="file://$PROJECT_DIR$/android/android/main_AndroidStudio.iml" filepath="$PROJECT_DIR$/android/android/main_AndroidStudio.iml" group="android" />
<module fileurl="file://$PROJECT_DIR$/python/main_idea_python_plugin.iml" filepath="$PROJECT_DIR$/python/main_idea_python_plugin.iml" group="python" />
<module fileurl="file://$PROJECT_DIR$/python/main_pycharm_ce.iml" filepath="$PROJECT_DIR$/python/main_pycharm_ce.iml" group="python" />
<module fileurl="file://$PROJECT_DIR$/python/edu/main_pycharm_edu.iml" filepath="$PROJECT_DIR$/python/edu/main_pycharm_edu.iml" group="python/educational" />
diff --git a/bin/WinLauncher/WinLauncher.exe b/bin/WinLauncher/WinLauncher.exe
index 66b04fa1bfd8..afe000ae7459 100644
--- a/bin/WinLauncher/WinLauncher.exe
+++ b/bin/WinLauncher/WinLauncher.exe
Binary files differ
diff --git a/bin/WinLauncher/WinLauncher64.exe b/bin/WinLauncher/WinLauncher64.exe
index 12a18522deed..7dc6ef8deb5e 100644
--- a/bin/WinLauncher/WinLauncher64.exe
+++ b/bin/WinLauncher/WinLauncher64.exe
Binary files differ
diff --git a/bin/scripts/unix/idea.sh b/bin/scripts/unix/idea.sh
index 19b5e717160b..a4e545509029 100755
--- a/bin/scripts/unix/idea.sh
+++ b/bin/scripts/unix/idea.sh
@@ -99,7 +99,7 @@ fi
VERSION_LOG=`"$MKTEMP" -t java.version.log.XXXXXX`
"$JDK/bin/java" -version 2> "$VERSION_LOG"
-"$GREP" "64-Bit|x86_64" "$VERSION_LOG" > /dev/null
+"$GREP" "64-Bit|x86_64|amd64" "$VERSION_LOG" > /dev/null
BITS=$?
"$RM" -f "$VERSION_LOG"
if [ $BITS -eq 0 ]; then
diff --git a/build/conf/mac/Contents/Info.plist b/build/conf/mac/Contents/Info.plist
index 4a9c7d117dce..c4ac45b3ef62 100644
--- a/build/conf/mac/Contents/Info.plist
+++ b/build/conf/mac/Contents/Info.plist
@@ -86,8 +86,6 @@
<key>VMOptions</key>
<string>@@vmoptions@@ -Xbootclasspath/a:../lib/boot.jar</string>
- <key>WorkingDirectory</key>
- <string>$APP_PACKAGE/Contents/bin</string>
</dict>
</dict>
</plist>
diff --git a/build/conf/mac/Contents/MacOS/idea b/build/conf/mac/Contents/MacOS/idea
index 6ba553f866fd..0699ef280f54 100755
--- a/build/conf/mac/Contents/MacOS/idea
+++ b/build/conf/mac/Contents/MacOS/idea
Binary files differ
diff --git a/build/scripts/dist.gant b/build/scripts/dist.gant
index a31b66f5a654..81400fb9c8ac 100644
--- a/build/scripts/dist.gant
+++ b/build/scripts/dist.gant
@@ -139,7 +139,7 @@ def layoutAll(Map args, String home, String out, Paths _paths = null, buildJps =
layoutUnix(args, home, paths)
def winAppRoot = "android-studio"
- def macAppRoot = "Android Studio.app"
+ def macAppRoot = "Android Studio.app/Contents"
def linTarRoot = "android-studio"
androidBuildNumber = p("buildNumber")
diff --git a/build/scripts/layouts.gant b/build/scripts/layouts.gant
index ba7a556eefe5..69c817e25d4f 100644
--- a/build/scripts/layouts.gant
+++ b/build/scripts/layouts.gant
@@ -569,14 +569,7 @@ public def layoutCommunityPlugins(String home) {
}
}
- pluginDir("java-decompiler") {
- dir("lib") {
- jar("java-decompiler.jar") {
- module("java-decompiler")
- }
- fileset(file: "$home/plugins/java-decompiler/lib/fernflower.jar")
- }
- }
+ layoutPlugin("java-decompiler")
}
}
diff --git a/build/scripts/libLicenses.gant b/build/scripts/libLicenses.gant
index 5319444eaae6..b4a3c835999e 100644
--- a/build/scripts/libLicenses.gant
+++ b/build/scripts/libLicenses.gant
@@ -196,7 +196,7 @@ libraryLicense(name: "JGoodies Forms", libraryName: "jgoodies-forms", version: "
libraryLicense(name: "JGoodies Looks", libraryName: "jgoodies-looks", version: "2.4.2", license: "BSD ", url: "http://www.jgoodies.com/freeware/looks/", licenseUrl: "http://www.jgoodies.com/downloads/libraries.html")
libraryLicense(name: "JGoodies Common", libraryName: "jgoodies-common", version: "1.2.1", license: "BSD ", url: "http://www.jgoodies.com/freeware/looks/", licenseUrl: "http://www.jgoodies.com/downloads/libraries.html")
libraryLicense(name: "JNA", libraryName: "jna", version: "3.4.0", license: "LGPL 2.1", url: "https://jna.dev.java.net/", licenseUrl: "http://www.opensource.org/licenses/lgpl-2.1.php")
-libraryLicense(name: "JSch", libraryName: "JSch", version: "0.1.50", license: "BSD", url: "http://www.jcraft.com/jsch/", licenseUrl: "http://www.jcraft.com/jsch/LICENSE.txt")
+libraryLicense(name: "JSch", libraryName: "JSch", version: "0.1.51", license: "BSD", url: "http://www.jcraft.com/jsch/", licenseUrl: "http://www.jcraft.com/jsch/LICENSE.txt")
libraryLicense(name: "jsch-agent-proxy", libraryName: "jsch-agent-proxy", version: "0.0.6", license: "BSD", url: "https://github.com/ymnk/jsch-agent-proxy", licenseUrl: "https://github.com/ymnk/jsch-agent-proxy/blob/master/LICENSE.txt")
libraryLicense(name: "jsch-agent-proxy for svnkit trilead", libraryName: "jsch.agentproxy.svnkit-trilead-ssh2.jar", version: "0.0.6", license: "BSD", url: "https://github.com/ymnk/jsch-agent-proxy", licenseUrl: "https://github.com/ymnk/jsch-agent-proxy/blob/master/LICENSE.txt")
libraryLicense(name: "JUnit", libraryName: "JUnit3", version: "3.8.1", license: "CPL 1.0", url: "http://junit.org/")
@@ -243,7 +243,7 @@ libraryLicense(name: "TestNG", version: "5.7 snapshot", license: "Apache 2.0", u
libraryLicense(name: "Trilead SSH", libraryName: "trilead-ssh2", version: "build 213 and 217", license: "BSD style (see LICENSE.txt in trilead.jar)", url: "http://www.trilead.com/SSH_Library/")
libraryLicense(name: "Trove4j", version: "1.1 (with patches by JetBrains)", license: "LGPL", url: "http://trove4j.sourceforge.net/", licenseUrl: "http://trove4j.sourceforge.net/html/license.html")
libraryLicense(name: "Velocity", version: "1.7", license: "Apache 2.0", url: "http://velocity.apache.org/", licenseUrl: "http://velocity.apache.org/index.html")
-libraryLicense(name: "winp", version: "1.17 (patched)", license: "MIT", url: "http://java.net/projects/winp", licenseUrl: "http://opensource.org/licenses/mit-license.php")
+libraryLicense(name: "winp", version: "1.21 (patched)", license: "MIT", url: "http://java.net/projects/winp", licenseUrl: "http://opensource.org/licenses/mit-license.php")
libraryLicense(name: "Xalan", libraryName:"Xalan-2.7.1", version: "2.7.1", license: "Apache 2.0", url: "http://xml.apache.org/xalan-j/", licenseUrl: "http://xml.apache.org/xalan-j/")
libraryLicense(name: "Xerces", version: "2.9.1", license: "Apache 2.0", url: "http://xerces.apache.org/xerces2-j/", licenseUrl: "http://xerces.apache.org/xerces2-j/")
libraryLicense(name: "XML Commons (xml-apis.jar, resolver.jar)", version: "", license: "Apache 2.0, W3C Software License , public domain", url: "http://xml.apache.org/commons/", licenseUrl: "http://xml.apache.org/commons/licenses.html")
@@ -285,4 +285,3 @@ jetbrainsLibrary("JPS")
jetbrainsLibrary("Maven Embedder")
jetbrainsLibrary("tcServiceMessages")
jetbrainsLibrary("optimizedFileManager.jar")
-jetbrainsLibrary("fernflower.jar")
diff --git a/community-tests/src/tests/testGroups.properties b/community-tests/src/tests/testGroups.properties
index a528fa8840df..5104b681ee6f 100644
--- a/community-tests/src/tests/testGroups.properties
+++ b/community-tests/src/tests/testGroups.properties
@@ -4,6 +4,3 @@ org.jetbrains.idea.svn.*
org.jetbrains.idea.svn16.*
com.intellij.util.net.ssl.*
com.intellij.tasks.integration.live.*
-
-[DECOMPILER_TESTS]
-org.jetbrains.java.decompiler.*
diff --git a/getPlugins.bat b/getPlugins.bat
new file mode 100644
index 000000000000..3cd8b977612a
--- /dev/null
+++ b/getPlugins.bat
@@ -0,0 +1,2 @@
+call git clone git://git.jetbrains.org/idea/android.git android
+call git clone git://git.jetbrains.org/idea/adt-tools-base.git android/tools-base
diff --git a/getPlugins.sh b/getPlugins.sh
new file mode 100755
index 000000000000..9afcebda7d70
--- /dev/null
+++ b/getPlugins.sh
@@ -0,0 +1,2 @@
+git clone git://git.jetbrains.org/idea/android.git android
+git clone git://git.jetbrains.org/idea/adt-tools-base.git android/tools-base
diff --git a/images/src/org/intellij/images/editor/impl/ImageEditorUI.java b/images/src/org/intellij/images/editor/impl/ImageEditorUI.java
index f3d920d3d3c3..b14296626eba 100644
--- a/images/src/org/intellij/images/editor/impl/ImageEditorUI.java
+++ b/images/src/org/intellij/images/editor/impl/ImageEditorUI.java
@@ -16,9 +16,11 @@
package org.intellij.images.editor.impl;
import com.intellij.ide.CopyPasteSupport;
+import com.intellij.ide.CopyProvider;
import com.intellij.ide.DeleteProvider;
import com.intellij.ide.PsiActionSupportFactory;
import com.intellij.openapi.actionSystem.*;
+import com.intellij.openapi.ide.CopyPasteManager;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
@@ -46,12 +48,16 @@ import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.Transferable;
+import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
+import java.io.IOException;
import java.util.Locale;
/**
@@ -59,7 +65,7 @@ import java.util.Locale;
*
* @author <a href="mailto:aefimov.box@gmail.com">Alexey Efimov</a>
*/
-final class ImageEditorUI extends JPanel implements DataProvider {
+final class ImageEditorUI extends JPanel implements DataProvider, CopyProvider {
@NonNls
private static final String IMAGE_PANEL = "image";
@NonNls
@@ -390,7 +396,7 @@ final class ImageEditorUI extends JPanel implements DataProvider {
} else if (LangDataKeys.PSI_ELEMENT_ARRAY.is(dataId)) {
return new PsiElement[]{(PsiElement)getData(CommonDataKeys.PSI_ELEMENT.getName())};
} else if (PlatformDataKeys.COPY_PROVIDER.is(dataId) && copyPasteSupport != null) {
- return copyPasteSupport.getCopyProvider();
+ return this;
} else if (PlatformDataKeys.CUT_PROVIDER.is(dataId) && copyPasteSupport != null) {
return copyPasteSupport.getCutProvider();
} else if (PlatformDataKeys.DELETE_ELEMENT_PROVIDER.is(dataId)) {
@@ -401,4 +407,47 @@ final class ImageEditorUI extends JPanel implements DataProvider {
return null;
}
+
+ @Override
+ public void performCopy(@NotNull DataContext dataContext) {
+ ImageDocument document = imageComponent.getDocument();
+ BufferedImage image = document.getValue();
+ CopyPasteManager.getInstance().setContents(new ImageTransferable(image));
+ }
+
+ @Override
+ public boolean isCopyEnabled(@NotNull DataContext dataContext) {
+ return true;
+ }
+
+ @Override
+ public boolean isCopyVisible(@NotNull DataContext dataContext) {
+ return true;
+ }
+
+ private static class ImageTransferable implements Transferable {
+ private final BufferedImage myImage;
+
+ public ImageTransferable(@NotNull BufferedImage image) {
+ myImage = image;
+ }
+
+ @Override
+ public DataFlavor[] getTransferDataFlavors() {
+ return new DataFlavor[] { DataFlavor.imageFlavor };
+ }
+
+ @Override
+ public boolean isDataFlavorSupported(DataFlavor dataFlavor) {
+ return DataFlavor.imageFlavor.equals(dataFlavor);
+ }
+
+ @Override
+ public Object getTransferData(DataFlavor dataFlavor) throws UnsupportedFlavorException, IOException {
+ if (!DataFlavor.imageFlavor.equals(dataFlavor)) {
+ throw new UnsupportedFlavorException(dataFlavor);
+ }
+ return myImage;
+ }
+ }
}
diff --git a/images/src/org/intellij/images/options/impl/OptionsManagerImpl.java b/images/src/org/intellij/images/options/impl/OptionsManagerImpl.java
index 50edd78feab0..146655408931 100644
--- a/images/src/org/intellij/images/options/impl/OptionsManagerImpl.java
+++ b/images/src/org/intellij/images/options/impl/OptionsManagerImpl.java
@@ -28,11 +28,8 @@ import org.jdom.Element;
* @author <a href="mailto:aefimov.box@gmail.com">Alexey Efimov</a>
*/
@State(
- name = "Images.OptionsManager",
- roamingType = RoamingType.DISABLED,
- storages = {
- @Storage(file = StoragePathMacros.APP_CONFIG + "/images.support.xml")
- }
+ name = "Images.OptionsManager",
+ storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/images.support.xml", roamingType = RoamingType.DISABLED)}
)
final class OptionsManagerImpl extends OptionsManager implements PersistentStateComponent<Element> {
private final OptionsImpl options = new OptionsImpl();
diff --git a/java/compiler/impl/compiler-impl.iml b/java/compiler/impl/compiler-impl.iml
index c6e3e4f81eab..552d0dfe0d38 100644
--- a/java/compiler/impl/compiler-impl.iml
+++ b/java/compiler/impl/compiler-impl.iml
@@ -17,7 +17,6 @@
<orderEntry type="module" module-name="java-runtime" />
<orderEntry type="module" module-name="instrumentation-util" />
<orderEntry type="library" name="asm5" level="project" />
- <orderEntry type="library" name="Eclipse" level="project" />
<orderEntry type="module" module-name="platform-api" />
<orderEntry type="module" module-name="lang-impl" />
<orderEntry type="module" module-name="jsp-openapi" />
diff --git a/java/compiler/impl/src/com/intellij/compiler/actions/CompileAction.java b/java/compiler/impl/src/com/intellij/compiler/actions/CompileAction.java
index 38f230f92997..542f1331d2d5 100644
--- a/java/compiler/impl/src/com/intellij/compiler/actions/CompileAction.java
+++ b/java/compiler/impl/src/com/intellij/compiler/actions/CompileAction.java
@@ -110,7 +110,7 @@ public class CompileAction extends CompileActionBase {
elementDescription = "'" + file.getName() + "'";
}
else {
- if (!ActionPlaces.MAIN_MENU.equals(event.getPlace())) {
+ if (!ActionPlaces.isMainMenuOrActionSearch(event.getPlace())) {
// the action should be invisible in popups for non-java files
presentation.setEnabled(false);
presentation.setVisible(false);
diff --git a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java
index 669cf92d37da..69bb36054f21 100644
--- a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java
+++ b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java
@@ -73,7 +73,10 @@ import com.intellij.openapi.vfs.newvfs.BulkFileListener;
import com.intellij.openapi.vfs.newvfs.events.VFileEvent;
import com.intellij.openapi.vfs.newvfs.impl.FileNameCache;
import com.intellij.openapi.wm.IdeFrame;
-import com.intellij.util.*;
+import com.intellij.util.Alarm;
+import com.intellij.util.ArrayUtil;
+import com.intellij.util.Function;
+import com.intellij.util.SmartList;
import com.intellij.util.concurrency.Semaphore;
import com.intellij.util.concurrency.SequentialTaskExecutor;
import com.intellij.util.containers.IntArrayList;
@@ -897,9 +900,6 @@ public class BuildManager implements ApplicationComponent{
if (!Registry.is("compiler.process.use.memory.temp.cache")) {
cmdLine.addParameter("-D"+ GlobalOptions.USE_MEMORY_TEMP_CACHE_OPTION + "=false");
}
- if (Registry.is("compiler.process.use.external.javac")) {
- cmdLine.addParameter("-D"+ GlobalOptions.USE_EXTERNAL_JAVAC_OPTION);
- }
// javac's VM should use the same default locale that IDEA uses in order for javac to print messages in 'correct' language
if (mySystemCharset != null) {
@@ -907,13 +907,15 @@ public class BuildManager implements ApplicationComponent{
cmdLine.addParameter("-D" + CharsetToolkit.FILE_ENCODING_PROPERTY + "=" + mySystemCharset.name());
}
cmdLine.addParameter("-D" + JpsGlobalLoader.FILE_TYPES_COMPONENT_NAME_KEY + "=" + FileTypeManagerImpl.getFileTypeComponentName());
- for (String name : new String[]{"user.language", "user.country", "user.region", PathManager.PROPERTY_HOME_PATH,
- PathManager.PROPERTY_CONFIG_PATH, PathManager.PROPERTY_PLUGINS_PATH, PathManager.PROPERTY_PATHS_SELECTOR}) {
+ for (String name : new String[]{"user.language", "user.country", "user.region", PathManager.PROPERTY_PATHS_SELECTOR}) {
final String value = System.getProperty(name);
if (value != null) {
cmdLine.addParameter("-D" + name + "=" + value);
}
}
+ cmdLine.addParameter("-D" + PathManager.PROPERTY_HOME_PATH + "=" + PathManager.getHomePath());
+ cmdLine.addParameter("-D" + PathManager.PROPERTY_CONFIG_PATH + "=" + PathManager.getConfigPath());
+ cmdLine.addParameter("-D" + PathManager.PROPERTY_PLUGINS_PATH + "=" + PathManager.getPluginsPath());
cmdLine.addParameter("-D" + GlobalOptions.LOG_DIR_OPTION + "=" + FileUtil.toSystemIndependentName(getBuildLogDirectory().getAbsolutePath()));
@@ -941,7 +943,6 @@ public class BuildManager implements ApplicationComponent{
cmdLine.addParameter(launcherClass.getName());
final List<String> cp = ClasspathBootstrap.getBuildProcessApplicationClasspath(true);
- cp.add(getJpsPluginSystemClassesPath());
cp.addAll(myClasspathManager.getBuildProcessPluginsClasspath(project));
if (isProfilingMode) {
cp.add(new File(workDirectory, "yjp-controller-api-redist.jar").getPath());
@@ -967,17 +968,6 @@ public class BuildManager implements ApplicationComponent{
};
}
- private static String getJpsPluginSystemClassesPath() {
- File classesRoot = new File(PathUtil.getJarPathForClass(BuildManager.class));
- if (classesRoot.isDirectory()) {
- //running from sources: load classes from .../out/production/jps-plugin-system
- return new File(classesRoot.getParentFile(), "jps-plugin-system").getAbsolutePath();
- }
- else {
- return new File(classesRoot.getParentFile(), "rt/jps-plugin-system.jar").getAbsolutePath();
- }
- }
-
public File getBuildSystemDirectory() {
return new File(mySystemDirectory, SYSTEM_ROOT);
}
diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactFromModulesDialog.form b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactFromModulesDialog.form
index eed2b888d43f..aeffe083cd9e 100644
--- a/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactFromModulesDialog.form
+++ b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactFromModulesDialog.form
@@ -67,7 +67,7 @@
<clientProperties>
<BorderFactoryClass class="java.lang.String" value="com.intellij.ui.IdeBorderFactory$PlainSmallWithIndent"/>
</clientProperties>
- <border type="none" title="Jar files from libraries"/>
+ <border type="none" title="JAR files from libraries"/>
<children>
<component id="f9a17" class="javax.swing.JRadioButton" binding="myExtractJarsRadioButton">
<constraints>
@@ -75,7 +75,7 @@
</constraints>
<properties>
<selected value="true"/>
- <text value="&amp;extract to the target jar"/>
+ <text value="&amp;extract to the target JAR"/>
</properties>
</component>
<hspacer id="90c4f">
diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactFromModulesDialog.java b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactFromModulesDialog.java
index 02d9e4228eec..ea2f4a64f622 100644
--- a/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactFromModulesDialog.java
+++ b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactFromModulesDialog.java
@@ -55,7 +55,7 @@ public class JarArtifactFromModulesDialog extends DialogWrapper {
public JarArtifactFromModulesDialog(PackagingElementResolvingContext context) {
super(context.getProject());
myContext = context;
- setTitle("Create Jar from Modules");
+ setTitle("Create JAR from Modules");
myMainClassLabel.setLabelFor(myMainClassField.getTextField());
myManifestDirLabel.setLabelFor(myManifestDirField.getTextField());
diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactType.java b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactType.java
index 2a0af9007963..bd4494c6f4a3 100644
--- a/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactType.java
+++ b/java/compiler/impl/src/com/intellij/packaging/impl/artifacts/JarArtifactType.java
@@ -33,7 +33,7 @@ import java.util.List;
*/
public class JarArtifactType extends ArtifactType {
public JarArtifactType() {
- super("jar", "Jar");
+ super("jar", "JAR");
}
public static JarArtifactType getInstance() {
diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/elements/PackagingElementFactoryImpl.java b/java/compiler/impl/src/com/intellij/packaging/impl/elements/PackagingElementFactoryImpl.java
index 0d1737b07e42..7e8f6016d591 100644
--- a/java/compiler/impl/src/com/intellij/packaging/impl/elements/PackagingElementFactoryImpl.java
+++ b/java/compiler/impl/src/com/intellij/packaging/impl/elements/PackagingElementFactoryImpl.java
@@ -274,7 +274,7 @@ public class PackagingElementFactoryImpl extends PackagingElementFactory {
@NotNull
@Override
public PackagingElement<?> createExtractedDirectory(@NotNull VirtualFile jarEntry) {
- LOG.assertTrue(jarEntry.getFileSystem() instanceof JarFileSystem, "Expected file from jar but file from " + jarEntry.getFileSystem() + " found");
+ LOG.assertTrue(jarEntry.getFileSystem() instanceof JarFileSystem, "Expected file from JAR but file from " + jarEntry.getFileSystem() + " found");
final String fullPath = jarEntry.getPath();
final int jarEnd = fullPath.indexOf(JarFileSystem.JAR_SEPARATOR);
return new ExtractedDirectoryPackagingElement(fullPath.substring(0, jarEnd), fullPath.substring(jarEnd + 1));
diff --git a/java/debugger/impl/src/com/intellij/debugger/DebugUIEnvironment.java b/java/debugger/impl/src/com/intellij/debugger/DebugUIEnvironment.java
index 8c89bada270d..04f4d583cf99 100644
--- a/java/debugger/impl/src/com/intellij/debugger/DebugUIEnvironment.java
+++ b/java/debugger/impl/src/com/intellij/debugger/DebugUIEnvironment.java
@@ -15,7 +15,6 @@
*/
package com.intellij.debugger;
-import com.intellij.diagnostic.logging.LogFilesManager;
import com.intellij.execution.configurations.RunProfile;
import com.intellij.execution.ui.RunContentDescriptor;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
@@ -37,8 +36,6 @@ public interface DebugUIEnvironment {
@Nullable
Icon getIcon();
- void initLogs(RunContentDescriptor content, LogFilesManager logFilesManager);
-
void initActions(RunContentDescriptor content, DefaultActionGroup actionGroup);
@Nullable
diff --git a/java/debugger/impl/src/com/intellij/debugger/DefaultDebugUIEnvironment.java b/java/debugger/impl/src/com/intellij/debugger/DefaultDebugUIEnvironment.java
index f29f3bfe572d..6f8b13e4d06a 100644
--- a/java/debugger/impl/src/com/intellij/debugger/DefaultDebugUIEnvironment.java
+++ b/java/debugger/impl/src/com/intellij/debugger/DefaultDebugUIEnvironment.java
@@ -15,14 +15,10 @@
*/
package com.intellij.debugger;
-import com.intellij.diagnostic.logging.LogFilesManager;
-import com.intellij.diagnostic.logging.OutputFileUtil;
import com.intellij.execution.Executor;
import com.intellij.execution.configurations.RemoteConnection;
-import com.intellij.execution.configurations.RunConfigurationBase;
import com.intellij.execution.configurations.RunProfile;
import com.intellij.execution.configurations.RunProfileState;
-import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.runners.RestartAction;
import com.intellij.execution.ui.RunContentDescriptor;
@@ -64,21 +60,6 @@ public class DefaultDebugUIEnvironment implements DebugUIEnvironment {
}
@Override
- public void initLogs(RunContentDescriptor content, LogFilesManager logFilesManager) {
- ProcessHandler processHandler = content.getProcessHandler();
- if (getRunProfile() instanceof RunConfigurationBase) {
- RunConfigurationBase runConfiguration = (RunConfigurationBase)getRunProfile();
-
- logFilesManager.registerFileMatcher(runConfiguration);
-
- if (processHandler != null) {
- logFilesManager.initLogConsoles(runConfiguration, processHandler);
- OutputFileUtil.attachDumpListener(runConfiguration, processHandler, content.getExecutionConsole());
- }
- }
- }
-
- @Override
public void initActions(RunContentDescriptor content, DefaultActionGroup actionGroup) {
Executor executor = myExecutionEnvironment.getExecutor();
RestartAction restartAction = new RestartAction(content, myExecutionEnvironment);
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/AdjustArrayRangeAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/AdjustArrayRangeAction.java
index ce375815bb77..0f5398a56cba 100644
--- a/java/debugger/impl/src/com/intellij/debugger/actions/AdjustArrayRangeAction.java
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/AdjustArrayRangeAction.java
@@ -16,6 +16,7 @@
package com.intellij.debugger.actions;
import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.JavaValue;
import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
import com.intellij.debugger.impl.DebuggerContextImpl;
import com.intellij.debugger.settings.ArrayRendererConfigurable;
@@ -27,6 +28,9 @@ import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ShowSettingsUtil;
import com.intellij.openapi.project.Project;
+import com.intellij.xdebugger.frame.XValue;
+import com.intellij.xdebugger.impl.ui.tree.actions.XDebuggerTreeActionBase;
+import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl;
import org.jetbrains.annotations.Nullable;
public class AdjustArrayRangeAction extends DebuggerAction {
@@ -44,42 +48,48 @@ public class AdjustArrayRangeAction extends DebuggerAction {
final Project project = debuggerContext.getProject();
- final DebuggerTreeNodeImpl selectedNode = getSelectedNode(e.getDataContext());
- if (selectedNode == null) {
+ final XValueNodeImpl node = XDebuggerTreeActionBase.getSelectedNode(e.getDataContext());
+ if (node == null) {
return;
}
- NodeDescriptorImpl descriptor = selectedNode.getDescriptor();
- if(!(descriptor instanceof ValueDescriptorImpl /*&& ((ValueDescriptorImpl)descriptor).isArray()*/)) {
+
+ XValue container = node.getValueContainer();
+ if (!(container instanceof JavaValue)) {
return;
}
- final ArrayRenderer renderer = getArrayRenderer((ValueDescriptorImpl)descriptor)/*(ArrayRenderer)((ValueDescriptorImpl)selectedNode.getDescriptor()).getLastRenderer()*/;
+ final ValueDescriptorImpl descriptor = ((JavaValue)container).getDescriptor();
+ ArrayRenderer renderer = getArrayRenderer(descriptor);
if (renderer == null) {
return;
}
- String title = createNodeTitle("", selectedNode);
- String label = selectedNode.toString();
- int index = label.indexOf('=');
- if (index > 0) {
- title = title + " " + label.substring(index);
- }
+ //String title = createNodeTitle("", selectedNode);
+ //String label = selectedNode.toString();
+ //int index = label.indexOf('=');
+ //if (index > 0) {
+ // title = title + " " + label.substring(index);
+ //}
+ String title = node.getName();
final ArrayRenderer clonedRenderer = renderer.clone();
+ clonedRenderer.setForced(true);
if (ShowSettingsUtil.getInstance().editConfigurable(project, new NamedArrayConfigurable(title, clonedRenderer))) {
debugProcess.getManagerThread().schedule(new SuspendContextCommandImpl(debuggerContext.getSuspendContext()) {
@Override
public void contextAction() throws Exception {
- final ValueDescriptorImpl nodeDescriptor = (ValueDescriptorImpl)selectedNode.getDescriptor();
- final Renderer lastRenderer = nodeDescriptor.getLastRenderer();
+ final Renderer lastRenderer = descriptor.getLastRenderer();
if (lastRenderer instanceof ArrayRenderer) {
- selectedNode.setRenderer(clonedRenderer);
+ descriptor.setRenderer(clonedRenderer);
+ refreshViews(node);
+ //selectedNode.setRenderer(clonedRenderer);
}
else if (lastRenderer instanceof CompoundNodeRenderer) {
final CompoundNodeRenderer compoundRenderer = (CompoundNodeRenderer)lastRenderer;
final ChildrenRenderer childrenRenderer = compoundRenderer.getChildrenRenderer();
if (childrenRenderer instanceof ExpressionChildrenRenderer) {
- ExpressionChildrenRenderer.setPreferableChildrenRenderer(nodeDescriptor, clonedRenderer);
- selectedNode.calcRepresentation();
+ ExpressionChildrenRenderer.setPreferableChildrenRenderer(descriptor, clonedRenderer);
+ refreshViews(node);
+ //selectedNode.calcRepresentation();
}
}
}
@@ -90,10 +100,14 @@ public class AdjustArrayRangeAction extends DebuggerAction {
@Override
public void update(AnActionEvent e) {
boolean enable = false;
- DebuggerTreeNodeImpl selectedNode = getSelectedNode(e.getDataContext());
- if(selectedNode != null) {
- NodeDescriptorImpl descriptor = selectedNode.getDescriptor();
- enable = descriptor instanceof ValueDescriptorImpl && getArrayRenderer((ValueDescriptorImpl)descriptor) != null;
+ XValueNodeImpl node = XDebuggerTreeActionBase.getSelectedNode(e.getDataContext());
+ if (node == null) {
+ return;
+ }
+ XValue container = node.getValueContainer();
+ if (container instanceof JavaValue) {
+ ValueDescriptorImpl descriptor = ((JavaValue)container).getDescriptor();
+ enable = getArrayRenderer(descriptor) != null;
}
e.getPresentation().setVisible(enable);
}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/DebuggerAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/DebuggerAction.java
index 86ddfaa5fc08..2e87aa973285 100644
--- a/java/debugger/impl/src/com/intellij/debugger/actions/DebuggerAction.java
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/DebuggerAction.java
@@ -22,6 +22,7 @@ package com.intellij.debugger.actions;
import com.intellij.debugger.DebuggerManagerEx;
+import com.intellij.debugger.engine.JavaDebugProcess;
import com.intellij.debugger.impl.DebuggerContextImpl;
import com.intellij.debugger.impl.DebuggerStateManager;
import com.intellij.debugger.ui.impl.DebuggerTreePanel;
@@ -32,6 +33,11 @@ import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.project.Project;
import com.intellij.ui.DoubleClickListener;
+import com.intellij.xdebugger.XDebugProcess;
+import com.intellij.xdebugger.XDebugSession;
+import com.intellij.xdebugger.impl.frame.XDebugView;
+import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
@@ -153,4 +159,18 @@ public abstract class DebuggerAction extends AnAction {
}
});
}
+
+ public static void refreshViews(@NotNull XValueNodeImpl node) {
+ refreshViews(XDebugView.getSession(node.getTree()));
+ }
+
+ public static void refreshViews(@Nullable XDebugSession session) {
+ if (session != null) {
+ XDebugProcess process = session.getDebugProcess();
+ if (process instanceof JavaDebugProcess) {
+ ((JavaDebugProcess)process).saveNodeHistory();
+ }
+ session.rebuildViews();
+ }
+ }
}
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/JavaMarkObjectActionHandler.java b/java/debugger/impl/src/com/intellij/debugger/actions/JavaMarkObjectActionHandler.java
index dcd0454c16aa..282a6dc9f30b 100644
--- a/java/debugger/impl/src/com/intellij/debugger/actions/JavaMarkObjectActionHandler.java
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/JavaMarkObjectActionHandler.java
@@ -50,6 +50,8 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
+import static com.intellij.openapi.actionSystem.PlatformDataKeys.CONTEXT_COMPONENT;
+
/*
* Class SetValueAction
* @author Jeka
@@ -71,7 +73,8 @@ public class JavaMarkObjectActionHandler extends MarkObjectActionHandler {
final DebuggerTree tree = node.getTree();
tree.saveState(node);
-
+
+ final Component parent = event.getData(CONTEXT_COMPONENT);
final ValueDescriptorImpl valueDescriptor = ((ValueDescriptorImpl)descriptor);
final DebuggerContextImpl debuggerContext = tree.getDebuggerContext();
final DebugProcessImpl debugProcess = debuggerContext.getDebugProcess();
@@ -93,7 +96,7 @@ public class JavaMarkObjectActionHandler extends MarkObjectActionHandler {
final boolean suggestAdditionalMarkup = canSuggestAdditionalMarkup(debugProcess, valueDescriptor.getValue());
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
- ObjectMarkupPropertiesDialog dialog = new ObjectMarkupPropertiesDialog(defaultText, suggestAdditionalMarkup);
+ ObjectMarkupPropertiesDialog dialog = new ObjectMarkupPropertiesDialog(parent, defaultText, suggestAdditionalMarkup);
dialog.show();
if (dialog.isOK()) {
result.set(Pair.create(dialog.getConfiguredMarkup(), dialog.isMarkAdditionalFields()));
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/JavaReferringObjectsValue.java b/java/debugger/impl/src/com/intellij/debugger/actions/JavaReferringObjectsValue.java
index 815ddd231f14..a362e7d7caff 100644
--- a/java/debugger/impl/src/com/intellij/debugger/actions/JavaReferringObjectsValue.java
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/JavaReferringObjectsValue.java
@@ -61,6 +61,7 @@ public class JavaReferringObjectsValue extends JavaValue {
@Override
public void computeChildren(@NotNull final XCompositeNode node) {
+ if (checkContextNotResumed(node)) return;
getEvaluationContext().getDebugProcess().getManagerThread().schedule(
new SuspendContextCommandImpl(getEvaluationContext().getSuspendContext()) {
@Override
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/ObjectMarkupPropertiesDialog.java b/java/debugger/impl/src/com/intellij/debugger/actions/ObjectMarkupPropertiesDialog.java
index cd4aa14b7703..454b130307cf 100644
--- a/java/debugger/impl/src/com/intellij/debugger/actions/ObjectMarkupPropertiesDialog.java
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/ObjectMarkupPropertiesDialog.java
@@ -20,6 +20,7 @@ import com.intellij.openapi.ui.ex.MultiLineLabel;
import com.intellij.xdebugger.impl.ui.tree.ValueMarkerPresentationDialogBase;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
@@ -35,8 +36,8 @@ public class ObjectMarkupPropertiesDialog extends ValueMarkerPresentationDialogB
private JPanel myAdditionalPropertiesPanel;
private MultiLineLabel myDescriptionLabel;
- public ObjectMarkupPropertiesDialog(@NotNull final String defaultText, boolean suggestAdditionalMarkup) {
- super(defaultText);
+ public ObjectMarkupPropertiesDialog(@Nullable Component parent, @NotNull final String defaultText, boolean suggestAdditionalMarkup) {
+ super(parent, defaultText);
mySuggestAdditionalMarkup = suggestAdditionalMarkup;
myDescriptionLabel.setText("If the value is referenced by a constant field of an abstract class,\n" +
"IDEA could additionally mark all values referenced from this class with the names of referencing fields.");
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/PopFrameAction.java b/java/debugger/impl/src/com/intellij/debugger/actions/PopFrameAction.java
index f5aa685c7994..f89ae5ce8292 100644
--- a/java/debugger/impl/src/com/intellij/debugger/actions/PopFrameAction.java
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/PopFrameAction.java
@@ -19,68 +19,212 @@
*/
package com.intellij.debugger.actions;
+import com.intellij.CommonBundle;
import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.SourcePosition;
import com.intellij.debugger.engine.DebugProcessImpl;
import com.intellij.debugger.engine.JavaStackFrame;
import com.intellij.debugger.engine.SuspendContextImpl;
import com.intellij.debugger.impl.DebuggerContextImpl;
import com.intellij.debugger.jdi.StackFrameProxyImpl;
import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
-import com.intellij.debugger.ui.impl.watch.*;
+import com.intellij.debugger.settings.DebuggerSettings;
+import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
+import com.intellij.debugger.ui.impl.watch.StackFrameDescriptorImpl;
+import com.intellij.debugger.ui.impl.watch.ThreadDescriptorImpl;
import com.intellij.idea.ActionsBundle;
import com.intellij.openapi.actionSystem.ActionPlaces;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
+import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.openapi.ui.MessageDialogBuilder;
import com.intellij.openapi.ui.Messages;
+import com.intellij.psi.PsiCodeBlock;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiStatement;
+import com.intellij.psi.PsiTryStatement;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.ui.UIUtil;
import com.intellij.xdebugger.XDebugSession;
+import com.intellij.xdebugger.XDebuggerBundle;
import com.intellij.xdebugger.XDebuggerManager;
+import com.intellij.xdebugger.evaluation.EvaluationMode;
+import com.intellij.xdebugger.evaluation.XDebuggerEvaluator;
import com.intellij.xdebugger.frame.XStackFrame;
+import com.intellij.xdebugger.frame.XValue;
+import com.intellij.xdebugger.impl.breakpoints.XExpressionImpl;
import com.sun.jdi.InvalidStackFrameException;
import com.sun.jdi.NativeMethodException;
import com.sun.jdi.VMDisconnectedException;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import java.util.ArrayList;
+import java.util.List;
+
public class PopFrameAction extends DebuggerAction {
public void actionPerformed(AnActionEvent e) {
- Project project = e.getData(CommonDataKeys.PROJECT);
- StackFrameProxyImpl stackFrame = getStackFrameProxy(e);
+ final Project project = e.getData(CommonDataKeys.PROJECT);
+ final JavaStackFrame stackFrame = getStackFrame(e);
if(stackFrame == null) {
return;
}
try {
- DebuggerContextImpl debuggerContext = DebuggerAction.getDebuggerContext(e.getDataContext());
- DebugProcessImpl debugProcess = debuggerContext.getDebugProcess();
+ final DebuggerContextImpl debuggerContext = DebuggerAction.getDebuggerContext(e.getDataContext());
+ final DebugProcessImpl debugProcess = debuggerContext.getDebugProcess();
if(debugProcess == null) {
return;
}
- debugProcess.getManagerThread().schedule(debugProcess.createPopFrameCommand(debuggerContext, stackFrame));
+
+ if (!DebuggerSettings.EVALUATE_FINALLY_NEVER.equals(DebuggerSettings.getInstance().EVALUATE_FINALLY_ON_POP_FRAME)) {
+ List<PsiStatement> statements = getFinallyStatements(debuggerContext.getSourcePosition());
+ if (!statements.isEmpty()) {
+ StringBuilder sb = new StringBuilder();
+ for (PsiStatement statement : statements) {
+ sb.append("\n").append(statement.getText());
+ }
+ if (DebuggerSettings.EVALUATE_FINALLY_ALWAYS.equals(DebuggerSettings.getInstance().EVALUATE_FINALLY_ON_POP_FRAME)) {
+ evaluateAndPop(project, stackFrame, debuggerContext, debugProcess, sb);
+ return;
+ }
+ else {
+ int res = MessageDialogBuilder
+ .yesNoCancel(UIUtil.removeMnemonic(ActionsBundle.actionText(DebuggerActions.POP_FRAME)),
+ DebuggerBundle.message("warning.finally.block.detected") + sb)
+ .project(project)
+ .icon(Messages.getWarningIcon())
+ .yesText(DebuggerBundle.message("button.execute.finally"))
+ .noText(DebuggerBundle.message("button.drop.anyway"))
+ .cancelText(CommonBundle.message("button.cancel"))
+ .doNotAsk(
+ new DialogWrapper.DoNotAskOption() {
+ @Override
+ public boolean isToBeShown() {
+ return !DebuggerSettings.EVALUATE_FINALLY_ALWAYS.equals(DebuggerSettings.getInstance().EVALUATE_FINALLY_ON_POP_FRAME) &&
+ !DebuggerSettings.EVALUATE_FINALLY_NEVER.equals(DebuggerSettings.getInstance().EVALUATE_FINALLY_ON_POP_FRAME);
+ }
+
+ @Override
+ public void setToBeShown(boolean value, int exitCode) {
+ if (!value) {
+ DebuggerSettings.getInstance().EVALUATE_FINALLY_ON_POP_FRAME =
+ exitCode == Messages.YES ? DebuggerSettings.EVALUATE_FINALLY_ALWAYS : DebuggerSettings.EVALUATE_FINALLY_NEVER;
+ }
+ else {
+ DebuggerSettings.getInstance().EVALUATE_FINALLY_ON_POP_FRAME = DebuggerSettings.EVALUATE_FINALLY_ASK;
+ }
+ }
+
+ @Override
+ public boolean canBeHidden() {
+ return true;
+ }
+
+ @Override
+ public boolean shouldSaveOptionsOnCancel() {
+ return false;
+ }
+
+ @NotNull
+ @Override
+ public String getDoNotShowMessage() {
+ return CommonBundle.message("dialog.options.do.not.show");
+ }
+ })
+ .show();
+
+ switch (res) {
+ case Messages.CANCEL:
+ return;
+ case Messages.NO:
+ break;
+ case Messages.YES: // evaluate finally
+ evaluateAndPop(project, stackFrame, debuggerContext, debugProcess, sb);
+ return;
+ }
+ }
+ }
+ }
+ debugProcess.getManagerThread().schedule(debugProcess.createPopFrameCommand(debuggerContext, stackFrame.getStackFrameProxy()));
}
catch (NativeMethodException e2){
- Messages.showMessageDialog(project, DebuggerBundle.message("error.native.method.exception"), ActionsBundle.actionText(DebuggerActions.POP_FRAME), Messages.getErrorIcon());
+ Messages.showMessageDialog(project, DebuggerBundle.message("error.native.method.exception"),
+ UIUtil.removeMnemonic(ActionsBundle.actionText(DebuggerActions.POP_FRAME)), Messages.getErrorIcon());
}
catch (InvalidStackFrameException ignored) {
}
- catch(VMDisconnectedException vde) {
+ catch(VMDisconnectedException ignored) {
}
}
- @Nullable
- private static StackFrameProxyImpl getStackFrameProxy(AnActionEvent e) {
- DebuggerTreeNodeImpl selectedNode = getSelectedNode(e.getDataContext());
- if(selectedNode != null) {
- NodeDescriptorImpl descriptor = selectedNode.getDescriptor();
- if(descriptor instanceof StackFrameDescriptorImpl) {
- if(selectedNode.getNextSibling() != null) {
- StackFrameDescriptorImpl frameDescriptor = ((StackFrameDescriptorImpl)descriptor);
- return frameDescriptor.getFrameProxy();
- }
- return null;
- }
- else if(descriptor instanceof ThreadDescriptorImpl || descriptor instanceof ThreadGroupDescriptorImpl) {
- return null;
+ private static void evaluateAndPop(final Project project,
+ final JavaStackFrame stackFrame,
+ final DebuggerContextImpl debuggerContext,
+ final DebugProcessImpl debugProcess, StringBuilder sb) {
+ XDebuggerEvaluator evaluator = stackFrame.getEvaluator();
+ if (evaluator != null) {
+ evaluator.evaluate(XExpressionImpl.fromText(sb.toString(), EvaluationMode.CODE_FRAGMENT),
+ new XDebuggerEvaluator.XEvaluationCallback() {
+ @Override
+ public void evaluated(@NotNull XValue result) {
+ debugProcess.getManagerThread()
+ .schedule(debugProcess.createPopFrameCommand(debuggerContext, stackFrame.getStackFrameProxy()));
+ }
+
+ @Override
+ public void errorOccurred(@NotNull final String errorMessage) {
+ ApplicationManager.getApplication().invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ Messages
+ .showMessageDialog(project, DebuggerBundle.message("error.executing.finally", errorMessage),
+ UIUtil.removeMnemonic(ActionsBundle.actionText(DebuggerActions.POP_FRAME)),
+ Messages.getErrorIcon());
+ }
+ });
+ }
+ }, stackFrame.getSourcePosition());
+ }
+ else {
+ Messages.showMessageDialog(project, XDebuggerBundle.message("xdebugger.evaluate.stack.frame.has.not.evaluator"),
+ UIUtil.removeMnemonic(ActionsBundle.actionText(DebuggerActions.POP_FRAME)),
+ Messages.getErrorIcon());
+ }
+ }
+
+ private static List<PsiStatement> getFinallyStatements(SourcePosition position) {
+ List<PsiStatement> res = new ArrayList<PsiStatement>();
+ PsiElement element = position.getFile().findElementAt(position.getOffset());
+ PsiTryStatement tryStatement = PsiTreeUtil.getParentOfType(element, PsiTryStatement.class);
+ while (tryStatement != null) {
+ PsiCodeBlock finallyBlock = tryStatement.getFinallyBlock();
+ if (finallyBlock != null) {
+ ContainerUtil.addAll(res, finallyBlock.getStatements());
}
+ tryStatement = PsiTreeUtil.getParentOfType(tryStatement, PsiTryStatement.class);
}
+ return res;
+ }
+
+ @Nullable
+ private static JavaStackFrame getStackFrame(AnActionEvent e) {
+ //DebuggerTreeNodeImpl selectedNode = getSelectedNode(e.getDataContext());
+ //if(selectedNode != null) {
+ // NodeDescriptorImpl descriptor = selectedNode.getDescriptor();
+ // if(descriptor instanceof StackFrameDescriptorImpl) {
+ // if(selectedNode.getNextSibling() != null) {
+ // StackFrameDescriptorImpl frameDescriptor = ((StackFrameDescriptorImpl)descriptor);
+ // return frameDescriptor.getFrameProxy();
+ // }
+ // return null;
+ // }
+ // else if(descriptor instanceof ThreadDescriptorImpl || descriptor instanceof ThreadGroupDescriptorImpl) {
+ // return null;
+ // }
+ //}
Project project = e.getProject();
if (project != null) {
@@ -89,18 +233,19 @@ public class PopFrameAction extends DebuggerAction {
XStackFrame frame = session.getCurrentStackFrame();
if (frame instanceof JavaStackFrame) {
StackFrameProxyImpl proxy = ((JavaStackFrame)frame).getStackFrameProxy();
- return !proxy.isBottom() ? proxy : null;
+ return !proxy.isBottom() ? ((JavaStackFrame)frame) : null;
}
}
}
- DebuggerContextImpl debuggerContext = DebuggerAction.getDebuggerContext(e.getDataContext());
- StackFrameProxyImpl frameProxy = debuggerContext.getFrameProxy();
-
- if(frameProxy == null || frameProxy.isBottom()) {
- return null;
- }
- return frameProxy;
+ //DebuggerContextImpl debuggerContext = DebuggerAction.getDebuggerContext(e.getDataContext());
+ //StackFrameProxyImpl frameProxy = debuggerContext.getFrameProxy();
+ //
+ //if(frameProxy == null || frameProxy.isBottom()) {
+ // return null;
+ //}
+ //return frameProxy;
+ return null;
}
private static boolean isAtBreakpoint(AnActionEvent e) {
@@ -118,14 +263,14 @@ public class PopFrameAction extends DebuggerAction {
public void update(AnActionEvent e) {
boolean enable = false;
- StackFrameProxyImpl stackFrameProxy = getStackFrameProxy(e);
+ JavaStackFrame stackFrame = getStackFrame(e);
- if(stackFrameProxy != null && isAtBreakpoint(e)) {
- VirtualMachineProxyImpl virtualMachineProxy = stackFrameProxy.getVirtualMachine();
+ if(stackFrame != null && isAtBreakpoint(e)) {
+ VirtualMachineProxyImpl virtualMachineProxy = stackFrame.getStackFrameProxy().getVirtualMachine();
enable = virtualMachineProxy.canPopFrames();
}
- if(ActionPlaces.MAIN_MENU.equals(e.getPlace()) || ActionPlaces.DEBUGGER_TOOLBAR.equals(e.getPlace())) {
+ if(ActionPlaces.isMainMenuOrActionSearch(e.getPlace()) || ActionPlaces.DEBUGGER_TOOLBAR.equals(e.getPlace())) {
e.getPresentation().setEnabled(enable);
}
else {
diff --git a/java/debugger/impl/src/com/intellij/debugger/actions/ViewAsGroup.java b/java/debugger/impl/src/com/intellij/debugger/actions/ViewAsGroup.java
index bd8efab637ac..fd0d8f6785b3 100644
--- a/java/debugger/impl/src/com/intellij/debugger/actions/ViewAsGroup.java
+++ b/java/debugger/impl/src/com/intellij/debugger/actions/ViewAsGroup.java
@@ -22,13 +22,11 @@ import com.intellij.debugger.impl.DebuggerContextImpl;
import com.intellij.debugger.settings.NodeRendererSettings;
import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl;
import com.intellij.debugger.ui.impl.watch.ValueDescriptorImpl;
-import com.intellij.debugger.ui.tree.render.DescriptorLabelListener;
import com.intellij.debugger.ui.tree.render.NodeRenderer;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.DumbAware;
import com.intellij.xdebugger.frame.XValue;
-import com.intellij.xdebugger.frame.XValuePlace;
import com.intellij.xdebugger.impl.ui.tree.actions.XDebuggerTreeActionBase;
import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl;
import org.jetbrains.annotations.NotNull;
@@ -66,7 +64,7 @@ public class ViewAsGroup extends ActionGroup implements DumbAware {
}
XValue container = node.getValueContainer();
if (container instanceof JavaValue) {
- if (((ValueDescriptorImpl)((JavaValue)container).getDescriptor()).getLastRenderer() != myNodeRenderer) {
+ if (((JavaValue)container).getDescriptor().getLastRenderer() != myNodeRenderer) {
return false;
}
}
@@ -83,11 +81,12 @@ public class ViewAsGroup extends ActionGroup implements DumbAware {
public void threadAction() {
XValue container = node.getValueContainer();
if (container instanceof JavaValue) {
- final ValueDescriptorImpl valueDescriptor = (ValueDescriptorImpl)((JavaValue)container).getDescriptor();
+ final ValueDescriptorImpl valueDescriptor = ((JavaValue)container).getDescriptor();
if (state) {
valueDescriptor.setRenderer(myNodeRenderer);
- valueDescriptor.updateRepresentation(debuggerContext.createEvaluationContext(), DescriptorLabelListener.DUMMY_LISTENER);
- container.computePresentation(node, XValuePlace.TREE);
+ DebuggerAction.refreshViews(node);
+ //valueDescriptor.updateRepresentation(debuggerContext.createEvaluationContext(), DescriptorLabelListener.DUMMY_LISTENER);
+ //container.computePresentation(node, XValuePlace.TREE);
}
}
}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java
index 4714ca49bd06..7640a959597e 100644
--- a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessEvents.java
@@ -29,7 +29,6 @@ import com.intellij.debugger.requests.Requestor;
import com.intellij.debugger.settings.DebuggerSettings;
import com.intellij.debugger.ui.DebuggerPanelsManager;
import com.intellij.debugger.ui.breakpoints.Breakpoint;
-import com.intellij.debugger.ui.breakpoints.BreakpointManager;
import com.intellij.debugger.ui.breakpoints.LineBreakpoint;
import com.intellij.execution.configurations.RemoteConnection;
import com.intellij.openapi.application.ApplicationManager;
@@ -57,15 +56,15 @@ import com.sun.jdi.request.ThreadStartRequest;
* @author lex
*/
public class DebugProcessEvents extends DebugProcessImpl {
- private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.DebugProcessEvents");
+ private static final Logger LOG = Logger.getInstance(DebugProcessEvents.class);
+
private DebuggerEventThread myEventThread;
- private final BreakpointManager myBreakpointManager;
public DebugProcessEvents(Project project) {
super(project);
- myBreakpointManager = DebuggerManagerEx.getInstanceEx(getProject()).getBreakpointManager();
}
+ @Override
protected void commitVM(final VirtualMachine vm) {
super.commitVM(vm);
if(vm != null) {
@@ -134,18 +133,19 @@ public class DebugProcessEvents extends DebugProcessImpl {
return myIsStopped;
}
+ @Override
public void run() {
try {
EventQueue eventQueue = myVmProxy.eventQueue();
while (!isStopped()) {
try {
final EventSet eventSet = eventQueue.remove();
-
+
final boolean methodWatcherActive = myReturnValueWatcher != null && myReturnValueWatcher.isEnabled();
int processed = 0;
for (EventIterator eventIterator = eventSet.eventIterator(); eventIterator.hasNext();) {
final Event event = eventIterator.nextEvent();
-
+
if (methodWatcherActive) {
if (event instanceof MethodExitEvent) {
if (myReturnValueWatcher.processMethodExitEvent((MethodExitEvent)event)) {
@@ -158,6 +158,7 @@ public class DebugProcessEvents extends DebugProcessImpl {
processed++;
final ThreadReference thread = ((ThreadStartEvent)event).thread();
getManagerThread().schedule(new DebuggerCommandImpl() {
+ @Override
protected void action() throws Exception {
getVirtualMachineProxy().threadStarted(thread);
myDebugProcessDispatcher.getMulticaster().threadStarted(DebugProcessEvents.this, thread);
@@ -168,6 +169,7 @@ public class DebugProcessEvents extends DebugProcessImpl {
processed++;
final ThreadReference thread = ((ThreadDeathEvent)event).thread();
getManagerThread().schedule(new DebuggerCommandImpl() {
+ @Override
protected void action() throws Exception {
getVirtualMachineProxy().threadStopped(thread);
myDebugProcessDispatcher.getMulticaster().threadStopped(DebugProcessEvents.this, thread);
@@ -175,15 +177,15 @@ public class DebugProcessEvents extends DebugProcessImpl {
});
}
}
-
+
if (processed == eventSet.size()) {
eventSet.resume();
continue;
}
getManagerThread().invokeAndWait(new DebuggerCommandImpl() {
+ @Override
protected void action() throws Exception {
-
if (eventSet.suspendPolicy() == EventRequest.SUSPEND_ALL && !DebuggerSession.enableBreakpointsDuringEvaluation()) {
// check if there is already one request with policy SUSPEND_ALL
for (SuspendContextImpl context : getSuspendManager().getEventContexts()) {
@@ -193,12 +195,10 @@ public class DebugProcessEvents extends DebugProcessImpl {
}
}
}
-
+
final SuspendContextImpl suspendContext = getSuspendManager().pushSuspendContext(eventSet);
-
for (EventIterator eventIterator = eventSet.eventIterator(); eventIterator.hasNext();) {
final Event event = eventIterator.nextEvent();
-
//if (LOG.isDebugEnabled()) {
// LOG.debug("EVENT : " + event);
//}
@@ -207,10 +207,7 @@ public class DebugProcessEvents extends DebugProcessImpl {
//Sun WTK fails when J2ME when event set is resumed on VMStartEvent
processVMStartEvent(suspendContext, (VMStartEvent)event);
}
- else if (event instanceof VMDeathEvent) {
- processVMDeathEvent(suspendContext, event);
- }
- else if (event instanceof VMDisconnectEvent) {
+ else if (event instanceof VMDeathEvent || event instanceof VMDisconnectEvent) {
processVMDeathEvent(suspendContext, event);
}
else if (event instanceof ClassPrepareEvent) {
@@ -240,7 +237,6 @@ public class DebugProcessEvents extends DebugProcessImpl {
}
}
});
-
}
catch (InternalException e) {
LOG.debug(e);
@@ -264,13 +260,15 @@ public class DebugProcessEvents extends DebugProcessImpl {
}
catch (VMDisconnectedException e) {
invokeVMDeathEvent();
- } finally {
+ }
+ finally {
Thread.interrupted(); // reset interrupted status
}
}
private void invokeVMDeathEvent() {
getManagerThread().invokeAndWait(new DebuggerCommandImpl() {
+ @Override
protected void action() throws Exception {
SuspendContextImpl suspendContext = getSuspendManager().pushSuspendContext(EventRequest.SUSPEND_NONE, 1);
processVMDeathEvent(suspendContext, null);
@@ -307,7 +305,7 @@ public class DebugProcessEvents extends DebugProcessImpl {
if(myState.compareAndSet(STATE_INITIAL, STATE_ATTACHED)) {
final VirtualMachineProxyImpl machineProxy = getVirtualMachineProxy();
final EventRequestManager requestManager = machineProxy.eventRequestManager();
-
+
if (machineProxy.canGetMethodReturnValues()) {
myReturnValueWatcher = new MethodReturnValueWatcher(requestManager);
}
@@ -378,7 +376,7 @@ public class DebugProcessEvents extends DebugProcessImpl {
RequestHint hint = (RequestHint)event.request().getProperty("hint");
deleteStepRequests(event.thread());
-
+
boolean shouldResume = false;
final Project project = getProject();
@@ -426,8 +424,9 @@ public class DebugProcessEvents extends DebugProcessImpl {
preprocessEvent(suspendContext, thread);
//we use schedule to allow processing other events during processing this one
- //this is especially nesessary if a method is breakpoint condition
+ //this is especially necessary if a method is breakpoint condition
getManagerThread().schedule(new SuspendContextCommandImpl(suspendContext) {
+ @Override
public void contextAction() throws Exception {
final SuspendManager suspendManager = getSuspendManager();
SuspendContextImpl evaluatingContext = SuspendManagerUtil.getEvaluatingContext(suspendManager, getSuspendContext().getThread());
@@ -441,7 +440,7 @@ public class DebugProcessEvents extends DebugProcessImpl {
final LocatableEventRequestor requestor = (LocatableEventRequestor) getRequestsManager().findRequestor(event.request());
boolean resumePreferred = requestor != null && DebuggerSettings.SUSPEND_NONE.equals(requestor.getSuspendPolicy());
- boolean requestHit = false;
+ boolean requestHit;
try {
requestHit = (requestor != null) && requestor.processLocatableEvent(this, event);
}
@@ -451,6 +450,7 @@ public class DebugProcessEvents extends DebugProcessImpl {
}
final boolean[] considerRequestHit = new boolean[]{true};
DebuggerInvocationUtil.invokeAndWait(getProject(), new Runnable() {
+ @Override
public void run() {
DebuggerPanelsManager.getInstance(getProject()).toFront(mySession);
final String displayName = requestor instanceof Breakpoint? ((Breakpoint)requestor).getDisplayName() : requestor.getClass().getSimpleName();
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java
index 613217f93ac2..4f10e68440b9 100644
--- a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java
@@ -17,6 +17,7 @@ package com.intellij.debugger.engine;
import com.intellij.Patches;
import com.intellij.debugger.*;
+import com.intellij.debugger.actions.DebuggerAction;
import com.intellij.debugger.actions.DebuggerActions;
import com.intellij.debugger.apiAdapters.ConnectionServiceWrapper;
import com.intellij.debugger.engine.evaluation.*;
@@ -43,10 +44,7 @@ import com.intellij.execution.CantRunException;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.ExecutionResult;
import com.intellij.execution.configurations.RemoteConnection;
-import com.intellij.execution.process.ProcessAdapter;
-import com.intellij.execution.process.ProcessEvent;
-import com.intellij.execution.process.ProcessListener;
-import com.intellij.execution.process.ProcessOutputTypes;
+import com.intellij.execution.process.*;
import com.intellij.execution.runners.ExecutionUtil;
import com.intellij.idea.ActionsBundle;
import com.intellij.openapi.Disposable;
@@ -170,10 +168,7 @@ public abstract class DebugProcessImpl extends UserDataHolderBase implements Deb
final DebuggerSession session = mySession;
if (session != null && session.isAttached()) {
session.refresh(true);
- XDebugSession xDebugSession = mySession.getXDebugSession();
- if (xDebugSession != null) {
- xDebugSession.rebuildViews();
- }
+ DebuggerAction.refreshViews(mySession.getXDebugSession());
}
}
});
@@ -354,10 +349,16 @@ public abstract class DebugProcessImpl extends UserDataHolderBase implements Deb
return new CompoundPositionManager(new PositionManagerImpl(this));
}
+ @Override
public void printToConsole(final String text) {
myExecutionResult.getProcessHandler().notifyTextAvailable(text, ProcessOutputTypes.SYSTEM);
}
+ @Override
+ public ProcessHandler getProcessHandler() {
+ return myExecutionResult.getProcessHandler();
+ }
+
/**
*
* @param suspendContext
@@ -653,8 +654,8 @@ public abstract class DebugProcessImpl extends UserDataHolderBase implements Deb
public void addProcessListener(ProcessListener processListener) {
synchronized(myProcessListeners) {
- if(getExecutionResult() != null) {
- getExecutionResult().getProcessHandler().addProcessListener(processListener);
+ if(getProcessHandler() != null) {
+ getProcessHandler().addProcessListener(processListener);
}
else {
myProcessListeners.add(processListener);
@@ -664,8 +665,8 @@ public abstract class DebugProcessImpl extends UserDataHolderBase implements Deb
public void removeProcessListener(ProcessListener processListener) {
synchronized (myProcessListeners) {
- if(getExecutionResult() != null) {
- getExecutionResult().getProcessHandler().removeProcessListener(processListener);
+ if(getProcessHandler() != null) {
+ getProcessHandler().removeProcessListener(processListener);
}
else {
myProcessListeners.remove(processListener);
@@ -917,11 +918,32 @@ public abstract class DebugProcessImpl extends UserDataHolderBase implements Deb
ClassNotLoadedException,
IncompatibleThreadStateException,
InvalidTypeException;
- public E start(EvaluationContextImpl evaluationContext, Method method) throws EvaluateException {
- return start(evaluationContext, method, false);
+
+
+ E start(EvaluationContextImpl evaluationContext, Method method, boolean internalEvaluate) throws EvaluateException {
+ while (true) {
+ try {
+ return startInternal(evaluationContext, method, internalEvaluate);
+ }
+ catch (ClassNotLoadedException e) {
+ ReferenceType loadedClass = null;
+ try {
+ if (evaluationContext.isAutoLoadClasses()) {
+ loadedClass = loadClass(evaluationContext, e.className(), evaluationContext.getClassLoader());
+ }
+ }
+ catch (Exception ignored) {
+ loadedClass = null;
+ }
+ if (loadedClass == null) {
+ throw EvaluateExceptionUtil.createEvaluateException(e);
+ }
+ }
+ }
}
- public E start(EvaluationContextImpl evaluationContext, Method method, boolean internalEvaluate) throws EvaluateException {
+ E startInternal(EvaluationContextImpl evaluationContext, Method method, boolean internalEvaluate)
+ throws EvaluateException, ClassNotLoadedException {
DebuggerManagerThreadImpl.assertIsManagerThread();
SuspendContextImpl suspendContext = evaluationContext.getSuspendContext();
SuspendManagerUtil.assertSuspendContext(suspendContext);
@@ -956,26 +978,7 @@ public abstract class DebugProcessImpl extends UserDataHolderBase implements Deb
getVirtualMachineProxy().clearCaches();
- while (true) {
- try {
- return invokeMethodAndFork(suspendContext);
- }
- catch (ClassNotLoadedException e) {
- ReferenceType loadedClass;
- try {
- loadedClass = evaluationContext.isAutoLoadClasses() ? loadClass(evaluationContext, e.className(), evaluationContext.getClassLoader()) : null;
- }
- catch (EvaluateException ignored) {
- loadedClass = null;
- }
- if (loadedClass == null) {
- throw EvaluateExceptionUtil.createEvaluateException(e);
- }
- }
- }
- }
- catch (ClassNotLoadedException e) {
- throw EvaluateExceptionUtil.createEvaluateException(e);
+ return invokeMethodAndFork(suspendContext);
}
catch (InvocationException e) {
throw EvaluateExceptionUtil.createEvaluateException(e);
@@ -1115,7 +1118,7 @@ public abstract class DebugProcessImpl extends UserDataHolderBase implements Deb
}
return objRef.invokeMethod(thread, method, args, invokePolicy | invocationOptions);
}
- }.start((EvaluationContextImpl)evaluationContext, method);
+ }.start((EvaluationContextImpl)evaluationContext, method, false);
}
private static ThreadReference getEvaluationThread(final EvaluationContext evaluationContext) throws EvaluateException {
@@ -1182,7 +1185,7 @@ public abstract class DebugProcessImpl extends UserDataHolderBase implements Deb
return classType.newInstance(thread, method, args, invokePolicy);
}
};
- return invokeCommand.start((EvaluationContextImpl)evaluationContext, method);
+ return invokeCommand.start((EvaluationContextImpl)evaluationContext, method, false);
}
public void clearCashes(int suspendPolicy) {
@@ -1711,15 +1714,17 @@ public abstract class DebugProcessImpl extends UserDataHolderBase implements Deb
createVirtualMachine(environment.getSessionName(), environment.isPollConnection());
+ ExecutionResult executionResult;
try {
synchronized (myProcessListeners) {
- myExecutionResult = environment.createExecutionResult();
- if (myExecutionResult == null) {
+ executionResult = environment.createExecutionResult();
+ myExecutionResult = executionResult;
+ if (executionResult == null) {
fail();
return null;
}
for (ProcessListener processListener : myProcessListeners) {
- myExecutionResult.getProcessHandler().addProcessListener(processListener);
+ executionResult.getProcessHandler().addProcessListener(processListener);
}
myProcessListeners.clear();
}
@@ -1732,7 +1737,7 @@ public abstract class DebugProcessImpl extends UserDataHolderBase implements Deb
// writing to volatile field ensures the other threads will see the right values in non-volatile fields
if (ApplicationManager.getApplication().isUnitTestMode()) {
- return myExecutionResult;
+ return executionResult;
}
/*
@@ -1760,7 +1765,7 @@ public abstract class DebugProcessImpl extends UserDataHolderBase implements Deb
});
*/
- return myExecutionResult;
+ return executionResult;
}
private void fail() {
@@ -1885,8 +1890,8 @@ public abstract class DebugProcessImpl extends UserDataHolderBase implements Deb
}
MyProcessAdapter processListener = new MyProcessAdapter();
addProcessListener(processListener);
- if(myExecutionResult != null) {
- if(myExecutionResult.getProcessHandler().isStartNotified()) {
+ if (myExecutionResult != null) {
+ if (myExecutionResult.getProcessHandler().isStartNotified()) {
processListener.run();
}
}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JVMNameUtil.java b/java/debugger/impl/src/com/intellij/debugger/engine/JVMNameUtil.java
index 13e8f155dff4..eeaa1c21015e 100644
--- a/java/debugger/impl/src/com/intellij/debugger/engine/JVMNameUtil.java
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/JVMNameUtil.java
@@ -285,13 +285,20 @@ public class JVMNameUtil {
return DebuggerManager.getInstance(aClass.getProject()).getVMClassQualifiedName(aClass);
}
+ public static JVMName getJVMConstructorSignature(@Nullable PsiMethod method, @Nullable PsiClass declaringClass) {
+ return getJVMSignature(method, true, declaringClass);
+ }
+
+ public static JVMName getJVMSignature(@NotNull PsiMethod method) {
+ return getJVMSignature(method, method.isConstructor(), method.getContainingClass());
+ }
+
@SuppressWarnings({"HardCodedStringLiteral"})
- public static JVMName getJVMSignature(PsiMethod method) {
+ private static JVMName getJVMSignature(@Nullable PsiMethod method, boolean constructor, @Nullable PsiClass declaringClass) {
JVMNameBuffer signature = new JVMNameBuffer();
signature.append("(");
- if (method.isConstructor()) {
- final PsiClass declaringClass = method.getContainingClass();
+ if (constructor) {
if (declaringClass != null) {
final PsiClass outerClass = declaringClass.getContainingClass();
if (outerClass != null) {
@@ -302,11 +309,13 @@ public class JVMNameUtil {
}
}
}
- for (PsiParameter psiParameter : method.getParameterList().getParameters()) {
- appendJVMSignature(signature, psiParameter.getType());
+ if (method != null) {
+ for (PsiParameter psiParameter : method.getParameterList().getParameters()) {
+ appendJVMSignature(signature, psiParameter.getType());
+ }
}
signature.append(")");
- if (!method.isConstructor()) {
+ if (!constructor && method != null) {
appendJVMSignature(signature, method.getReturnType());
}
else {
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JavaDebugProcess.java b/java/debugger/impl/src/com/intellij/debugger/engine/JavaDebugProcess.java
index 37ee00b94eaf..af55182e3607 100644
--- a/java/debugger/impl/src/com/intellij/debugger/engine/JavaDebugProcess.java
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/JavaDebugProcess.java
@@ -18,20 +18,18 @@ package com.intellij.debugger.engine;
import com.intellij.debugger.DebuggerBundle;
import com.intellij.debugger.actions.DebuggerActions;
import com.intellij.debugger.engine.evaluation.EvaluationContext;
-import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
import com.intellij.debugger.engine.events.DebuggerCommandImpl;
import com.intellij.debugger.engine.events.DebuggerContextCommandImpl;
import com.intellij.debugger.impl.*;
+import com.intellij.debugger.jdi.StackFrameProxyImpl;
import com.intellij.debugger.settings.DebuggerSettings;
import com.intellij.debugger.ui.DebuggerContentInfo;
import com.intellij.debugger.ui.breakpoints.Breakpoint;
import com.intellij.debugger.ui.impl.ThreadsPanel;
import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
import com.intellij.debugger.ui.impl.watch.MessageDescriptor;
-import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl;
import com.intellij.debugger.ui.impl.watch.NodeManagerImpl;
import com.intellij.debugger.ui.tree.NodeDescriptor;
-import com.intellij.debugger.ui.tree.render.DescriptorLabelListener;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.ui.ExecutionConsole;
import com.intellij.execution.ui.ExecutionConsoleEx;
@@ -150,29 +148,40 @@ public class JavaDebugProcess extends XDebugProcess {
};
session.addSessionListener(new XDebugSessionAdapter() {
@Override
- public void beforeSessionResume() {
- myJavaSession.getProcess().getManagerThread().schedule(new DebuggerCommandImpl() {
- @Override
- protected void action() throws Exception {
- myNodeManager.setHistoryByContext(getDebuggerStateManager().getContext());
- }
- @Override
- public Priority getPriority() {
- return Priority.NORMAL;
- }
- });
+ public void sessionPaused() {
+ saveNodeHistory();
}
@Override
public void stackFrameChanged() {
XStackFrame frame = session.getCurrentStackFrame();
if (frame instanceof JavaStackFrame) {
- DebuggerContextUtil.setStackFrame(javaSession.getContextManager(), ((JavaStackFrame)frame).getStackFrameProxy());
+ StackFrameProxyImpl frameProxy = ((JavaStackFrame)frame).getStackFrameProxy();
+ DebuggerContextUtil.setStackFrame(javaSession.getContextManager(), frameProxy);
+ saveNodeHistory(frameProxy);
}
}
});
}
+ public void saveNodeHistory() {
+ saveNodeHistory(getDebuggerStateManager().getContext().getFrameProxy());
+ }
+
+ private void saveNodeHistory(final StackFrameProxyImpl frameProxy) {
+ myJavaSession.getProcess().getManagerThread().invoke(new DebuggerCommandImpl() {
+ @Override
+ protected void action() throws Exception {
+ myNodeManager.setHistoryByContext(frameProxy);
+ }
+
+ @Override
+ public Priority getPriority() {
+ return Priority.NORMAL;
+ }
+ });
+ }
+
private DebuggerStateManager getDebuggerStateManager() {
return myJavaSession.getContextManager();
}
@@ -243,7 +252,7 @@ public class JavaDebugProcess extends XDebugProcess {
@Nullable
@Override
protected ProcessHandler doGetProcessHandler() {
- return myJavaSession.getProcess().getExecutionResult().getProcessHandler();
+ return myJavaSession.getProcess().getProcessHandler();
}
@NotNull
@@ -302,23 +311,16 @@ public class JavaDebugProcess extends XDebugProcess {
}
@Override
- public void registerAdditionalActions(@NotNull DefaultActionGroup leftToolbar, @NotNull DefaultActionGroup topToolbar) {
+ public void registerAdditionalActions(@NotNull DefaultActionGroup leftToolbar, @NotNull DefaultActionGroup topToolbar, @NotNull DefaultActionGroup settings) {
Constraints beforeRunner = new Constraints(Anchor.BEFORE, "Runner.Layout");
leftToolbar.add(Separator.getInstance(), beforeRunner);
leftToolbar.add(ActionManager.getInstance().getAction(DebuggerActions.EXPORT_THREADS), beforeRunner);
leftToolbar.add(ActionManager.getInstance().getAction(DebuggerActions.DUMP_THREADS), beforeRunner);
leftToolbar.add(Separator.getInstance(), beforeRunner);
- for (AnAction action : leftToolbar.getChildren(null)) {
- //TODO: maybe introduce API for extra settings?
- if (action instanceof DefaultActionGroup && "DebuggerSettings".equals(action.getTemplatePresentation().getText())) {
- DefaultActionGroup settings = (DefaultActionGroup)action;
- addActionToGroup(settings, XDebuggerActions.AUTO_TOOLTIP);
- settings.addAction(new AutoVarsSwitchAction(), Constraints.FIRST);
- settings.addAction(new WatchLastMethodReturnValueAction(), Constraints.FIRST);
- break;
- }
- }
+ addActionToGroup(settings, XDebuggerActions.AUTO_TOOLTIP);
+ settings.addAction(new AutoVarsSwitchAction(), Constraints.FIRST);
+ settings.addAction(new WatchLastMethodReturnValueAction(), Constraints.FIRST);
}
private static class AutoVarsSwitchAction extends ToggleAction {
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JavaDebuggerEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/JavaDebuggerEvaluator.java
index f2178c1d4fb5..2eab90666967 100644
--- a/java/debugger/impl/src/com/intellij/debugger/engine/JavaDebuggerEvaluator.java
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/JavaDebuggerEvaluator.java
@@ -82,9 +82,11 @@ public class JavaDebuggerEvaluator extends XDebuggerEvaluator {
return;
}
JavaDebugProcess process = myDebugProcess.getXdebugProcess();
- if (process != null) {
- callback.evaluated(JavaValue.create(null, descriptor, evalContext, process.getNodeManager(), true));
+ if (process == null) {
+ callback.errorOccurred("No debug process");
+ return;
}
+ callback.evaluated(JavaValue.create(null, descriptor, evalContext, process.getNodeManager(), true));
}
});
}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JavaStaticGroup.java b/java/debugger/impl/src/com/intellij/debugger/engine/JavaStaticGroup.java
index 1293a0fdd0c0..60d0b708befb 100644
--- a/java/debugger/impl/src/com/intellij/debugger/engine/JavaStaticGroup.java
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/JavaStaticGroup.java
@@ -17,7 +17,9 @@ package com.intellij.debugger.engine;
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
+import com.intellij.debugger.settings.NodeRendererSettings;
import com.intellij.debugger.ui.impl.watch.*;
+import com.intellij.debugger.ui.tree.render.ClassRenderer;
import com.intellij.xdebugger.frame.*;
import com.sun.jdi.Field;
import com.sun.jdi.ReferenceType;
@@ -57,8 +59,14 @@ public class JavaStaticGroup extends XValueGroup implements NodeDescriptorProvid
final ReferenceType refType = myStaticDescriptor.getType();
List<Field> fields = refType.allFields();
+
+ final ClassRenderer classRenderer = NodeRendererSettings.getInstance().getClassRenderer();
for (Field field : fields) {
if (field.isStatic()) {
+ boolean isSynthetic = DebuggerUtils.isSynthetic(field);
+ if (!classRenderer.SHOW_SYNTHETICS && isSynthetic) {
+ continue;
+ }
final FieldDescriptorImpl fieldDescriptor = myNodeManager.getFieldDescriptor(myStaticDescriptor, null, field);
children.add(JavaValue.create(fieldDescriptor, myEvaluationContext, myNodeManager));
//final DebuggerTreeNodeImpl node = myNodeManager.createNode(fieldDescriptor, myEvaluationContext);
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java b/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java
index 7b0ffffe98d5..b678cf30d661 100644
--- a/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/JavaValue.java
@@ -15,6 +15,7 @@
*/
package com.intellij.debugger.engine;
+import com.intellij.debugger.DebuggerBundle;
import com.intellij.debugger.DebuggerInvocationUtil;
import com.intellij.debugger.SourcePosition;
import com.intellij.debugger.actions.JavaReferringObjectsValue;
@@ -102,6 +103,7 @@ public class JavaValue extends XNamedValue implements NodeDescriptorProvider, XV
}
@Override
+ @NotNull
public ValueDescriptorImpl getDescriptor() {
return myValueDescriptor;
}
@@ -273,7 +275,7 @@ public class JavaValue extends XNamedValue implements NodeDescriptorProvider, XV
@Override
public void computeChildren(@NotNull final XCompositeNode node) {
- if (myEvaluationContext.getSuspendContext().isResumed()) return;
+ if (checkContextNotResumed(node)) return;
myEvaluationContext.getDebugProcess().getManagerThread().schedule(new SuspendContextCommandImpl(myEvaluationContext.getSuspendContext()) {
@Override
public Priority getPriority() {
@@ -335,6 +337,14 @@ public class JavaValue extends XNamedValue implements NodeDescriptorProvider, XV
});
}
+ protected boolean checkContextNotResumed(XCompositeNode node) {
+ if (myEvaluationContext.getSuspendContext().isResumed()) {
+ node.setErrorMessage(DebuggerBundle.message("error.context.has.changed"));
+ return true;
+ }
+ return false;
+ }
+
@Override
public void computeSourcePosition(@NotNull final XNavigatable navigatable) {
if (myEvaluationContext.getSuspendContext().isResumed()) return;
@@ -419,6 +429,7 @@ public class JavaValue extends XNamedValue implements NodeDescriptorProvider, XV
public String getEvaluationExpression() {
if (evaluationExpression == null) {
// TODO: change API to allow to calculate it asynchronously
+ if (myEvaluationContext.getSuspendContext().isResumed()) return null;
DebugProcessImpl debugProcess = myEvaluationContext.getDebugProcess();
debugProcess.getManagerThread().invokeAndWait(new DebuggerCommandImpl() {
@Override
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/JavaValueModifier.java b/java/debugger/impl/src/com/intellij/debugger/engine/JavaValueModifier.java
index c7e59106beb8..5aa037191c17 100644
--- a/java/debugger/impl/src/com/intellij/debugger/engine/JavaValueModifier.java
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/JavaValueModifier.java
@@ -34,6 +34,7 @@ import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.util.ProgressIndicatorListenerAdapter;
import com.intellij.openapi.progress.util.ProgressWindowWithNotification;
import com.intellij.openapi.ui.Messages;
+import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.ui.SimpleColoredComponent;
@@ -62,9 +63,12 @@ public class JavaValueModifier extends XValueModifier {
@Override
public String getInitialValueEditorText() {
Value value = myJavaValue.getDescriptor().getValue();
- if (value instanceof PrimitiveValue || value instanceof StringReference) {
+ if (value instanceof PrimitiveValue) {
return myJavaValue.getValueString();
}
+ else if (value instanceof StringReference) {
+ return StringUtil.wrapWithDoubleQuote(DebuggerUtils.translateStringValue(myJavaValue.getValueString()));
+ }
return null;
}
@@ -96,10 +100,12 @@ public class JavaValueModifier extends XValueModifier {
@Override
public void setValue(@NotNull String expression, @NotNull XModificationCallback callback) {
final NodeDescriptorImpl descriptor = myJavaValue.getDescriptor();
- if (!(descriptor instanceof ValueDescriptorImpl)) {
+ if(!((ValueDescriptorImpl)descriptor).canSetValue()) {
return;
}
- if(!((ValueDescriptorImpl)descriptor).canSetValue()) {
+
+ if (myJavaValue.getEvaluationContext().getSuspendContext().isResumed()) {
+ callback.errorOccurred(DebuggerBundle.message("error.context.has.changed"));
return;
}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/EvaluationContextImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/EvaluationContextImpl.java
index b6ca9eafe1f1..759d92fd57a8 100644
--- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/EvaluationContextImpl.java
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/EvaluationContextImpl.java
@@ -30,6 +30,7 @@ public final class EvaluationContextImpl implements EvaluationContext{
private final SuspendContextImpl mySuspendContext;
private final StackFrameProxyImpl myFrameProxy;
private boolean myAutoLoadClasses = true;
+ private ClassLoaderReference myClassLoader;
public EvaluationContextImpl(@NotNull SuspendContextImpl suspendContext, StackFrameProxyImpl frameProxy, @Nullable Value thisObject) {
myThisObject = thisObject;
@@ -77,9 +78,16 @@ public final class EvaluationContextImpl implements EvaluationContext{
@Override
public ClassLoaderReference getClassLoader() throws EvaluateException {
DebuggerManagerThreadImpl.assertIsManagerThread();
+ if (myClassLoader != null) {
+ return myClassLoader;
+ }
return myFrameProxy != null ? myFrameProxy.getClassLoader() : null;
}
+ public void setClassLoader(ClassLoaderReference classLoader) {
+ myClassLoader = classLoader;
+ }
+
public boolean isAutoLoadClasses() {
return myAutoLoadClasses;
}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/EvaluatorBuilderImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/EvaluatorBuilderImpl.java
index 83ad91b4e27d..7d0a4aeb0989 100644
--- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/EvaluatorBuilderImpl.java
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/EvaluatorBuilderImpl.java
@@ -31,7 +31,7 @@ import com.intellij.debugger.engine.DebuggerUtils;
import com.intellij.debugger.engine.JVMName;
import com.intellij.debugger.engine.JVMNameUtil;
import com.intellij.debugger.engine.evaluation.*;
-import com.intellij.debugger.ui.DebuggerEditorImpl;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
@@ -66,8 +66,8 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder {
final Project project = contextElement.getProject();
- CodeFragmentFactory factory = DebuggerEditorImpl.findAppropriateFactory(text, contextElement);
- PsiCodeFragment codeFragment = new CodeFragmentFactoryContextWrapper(factory).createCodeFragment(text, contextElement, project);
+ CodeFragmentFactory factory = DebuggerUtilsEx.findAppropriateCodeFragmentFactory(text, contextElement);
+ PsiCodeFragment codeFragment = factory.createCodeFragment(text, contextElement, project);
if (codeFragment == null) {
throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", text.getText()));
}
@@ -185,6 +185,11 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder {
}
@Override
+ public void visitTryStatement(PsiTryStatement statement) {
+ throw new EvaluateRuntimeException(new UnsupportedExpressionException(statement.getText()));
+ }
+
+ @Override
public void visitStatement(PsiStatement statement) {
throwEvaluateException(DebuggerBundle.message("evaluation.error.statement.not.supported", statement.getText()));
}
@@ -741,24 +746,28 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder {
}
private int calcIterationCount(final PsiJavaCodeReferenceElement qualifier) {
- int iterationCount = 0;
if (qualifier != null) {
- PsiElement targetClass = qualifier.resolve();
- if (targetClass == null || getContextPsiClass() == null) {
- throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", qualifier.getText()));
- }
- try {
- PsiClass aClass = getContextPsiClass();
- while (aClass != null && !aClass.equals(targetClass)) {
- iterationCount++;
- aClass = getOuterClass(aClass);
- }
- }
- catch (Exception e) {
- //noinspection ThrowableResultOfMethodCallIgnored
- throw new EvaluateRuntimeException(EvaluateExceptionUtil.createEvaluateException(e));
+ return calcIterationCount(qualifier.resolve(), qualifier.getText());
+ }
+ return 0;
+ }
+
+ private int calcIterationCount(PsiElement targetClass, String name) {
+ int iterationCount = 0;
+ if (targetClass == null || getContextPsiClass() == null) {
+ throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", name));
+ }
+ try {
+ PsiClass aClass = getContextPsiClass();
+ while (aClass != null && !aClass.equals(targetClass)) {
+ iterationCount++;
+ aClass = getOuterClass(aClass);
}
}
+ catch (Exception e) {
+ //noinspection ThrowableResultOfMethodCallIgnored
+ throw new EvaluateRuntimeException(EvaluateExceptionUtil.createEvaluateException(e));
+ }
return iterationCount;
}
@@ -962,12 +971,16 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder {
}
}
+ boolean defaultInterfaceMethod = false;
+
if (psiMethod != null) {
processBoxingConversions(psiMethod.getParameterList().getParameters(), argExpressions, resolveResult.getSubstitutor(), argumentEvaluators);
argumentEvaluators = wrapVarargs(psiMethod.getParameterList().getParameters(), argExpressions, resolveResult.getSubstitutor(), argumentEvaluators);
+ defaultInterfaceMethod = psiMethod.hasModifierProperty(PsiModifier.DEFAULT);
}
- myResult = new MethodEvaluator(objectEvaluator, contextClass, methodExpr.getReferenceName(), psiMethod != null ? JVMNameUtil.getJVMSignature(psiMethod) : null, argumentEvaluators);
+ myResult = new MethodEvaluator(objectEvaluator, contextClass, methodExpr.getReferenceName(),
+ psiMethod != null ? JVMNameUtil.getJVMSignature(psiMethod) : null, argumentEvaluators, defaultInterfaceMethod);
}
@Override
@@ -1082,6 +1095,16 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder {
}
@Override
+ public void visitLambdaExpression(PsiLambdaExpression expression) {
+ throw new EvaluateRuntimeException(new UnsupportedExpressionException(DebuggerBundle.message("evaluation.error.lambda.evaluation.not.supported")));
+ }
+
+ @Override
+ public void visitMethodReferenceExpression(PsiMethodReferenceExpression expression) {
+ throw new EvaluateRuntimeException(new UnsupportedExpressionException(DebuggerBundle.message("evaluation.error.method.reference.evaluation.not.supported")));
+ }
+
+ @Override
public void visitNewExpression(final PsiNewExpression expression) {
PsiType expressionPsiType = expression.getType();
if (expressionPsiType instanceof PsiArrayType) {
@@ -1142,7 +1165,7 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder {
else if (expressionPsiType instanceof PsiClassType){ // must be a class ref
PsiClass aClass = ((PsiClassType)expressionPsiType).resolve();
if(aClass instanceof PsiAnonymousClass) {
- throwEvaluateException(DebuggerBundle.message("evaluation.error.anonymous.class.evaluation.not.supported"));
+ throw new EvaluateRuntimeException(new UnsupportedExpressionException(DebuggerBundle.message("evaluation.error.anonymous.class.evaluation.not.supported")));
}
PsiExpressionList argumentList = expression.getArgumentList();
if (argumentList == null) {
@@ -1173,8 +1196,11 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder {
argumentEvaluators = wrapVarargs(constructor.getParameterList().getParameters(), argExpressions, constructorResolveResult.getSubstitutor(), argumentEvaluators);
}
- //noinspection HardCodedStringLiteral
- JVMName signature = constructor != null ? JVMNameUtil.getJVMSignature(constructor) : JVMNameUtil.getJVMRawText("()V");
+ if (aClass != null && aClass.getContainingClass() != null && !aClass.hasModifierProperty(PsiModifier.STATIC)) {
+ argumentEvaluators = addThisEvaluator(argumentEvaluators, aClass.getContainingClass());
+ }
+
+ JVMName signature = JVMNameUtil.getJVMConstructorSignature(constructor, aClass);
myResult = new NewClassInstanceEvaluator(
new TypeEvaluator(JVMNameUtil.getJVMQualifiedName(expressionPsiType)),
signature,
@@ -1191,6 +1217,14 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder {
}
}
+ private Evaluator[] addThisEvaluator(Evaluator[] argumentEvaluators, PsiClass cls) {
+ Evaluator[] res = new Evaluator[argumentEvaluators.length+1];
+ int depth = calcIterationCount(cls, "this");
+ res[0] = new ThisEvaluator(depth);
+ System.arraycopy(argumentEvaluators, 0, res, 1, argumentEvaluators.length);
+ return res;
+ }
+
@Override
public void visitArrayInitializerExpression(PsiArrayInitializerExpression expression) {
PsiExpression[] initializers = expression.getInitializers();
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/MethodEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/MethodEvaluator.java
index 6ba88653749b..80e42e3b61e2 100644
--- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/MethodEvaluator.java
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/MethodEvaluator.java
@@ -43,13 +43,19 @@ public class MethodEvaluator implements Evaluator {
private final String myMethodName;
private final Evaluator[] myArgumentEvaluators;
private final Evaluator myObjectEvaluator;
+ private final boolean myCheckDefaultInterfaceMethod;
public MethodEvaluator(Evaluator objectEvaluator, JVMName className, String methodName, JVMName signature, Evaluator[] argumentEvaluators) {
+ this(objectEvaluator, className, methodName, signature, argumentEvaluators, false);
+ }
+
+ public MethodEvaluator(Evaluator objectEvaluator, JVMName className, String methodName, JVMName signature, Evaluator[] argumentEvaluators, boolean checkDefaultInterfaceMethod) {
myObjectEvaluator = new DisableGC(objectEvaluator);
myClassName = className;
myMethodName = methodName;
myMethodSignature = signature;
myArgumentEvaluators = argumentEvaluators;
+ myCheckDefaultInterfaceMethod = checkDefaultInterfaceMethod;
}
@Override
@@ -148,7 +154,7 @@ public class MethodEvaluator implements Evaluator {
return debugProcess.invokeInstanceMethod(context, objRef, jdiMethod, args, ObjectReference.INVOKE_NONVIRTUAL);
}
// fix for default methods in interfaces, see IDEA-124066
- if (Boolean.valueOf(System.getProperty("debugger.invoke.default")) && jdiMethod.declaringType() instanceof InterfaceType) {
+ if (myCheckDefaultInterfaceMethod && jdiMethod.declaringType() instanceof InterfaceType) {
return invokeDefaultMethod(debugProcess, context, objRef, myMethodName);
}
else {
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/NewClassInstanceEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/NewClassInstanceEvaluator.java
index c3e7f8173322..3bbb0c633cd6 100644
--- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/NewClassInstanceEvaluator.java
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/NewClassInstanceEvaluator.java
@@ -21,13 +21,13 @@
*/
package com.intellij.debugger.engine.evaluation.expression;
+import com.intellij.debugger.DebuggerBundle;
import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.DebuggerUtils;
import com.intellij.debugger.engine.JVMName;
import com.intellij.debugger.engine.evaluation.EvaluateException;
import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
-import com.intellij.debugger.impl.DebuggerUtilsEx;
-import com.intellij.debugger.DebuggerBundle;
import com.sun.jdi.ClassType;
import com.sun.jdi.Method;
import com.sun.jdi.ObjectReference;
@@ -55,7 +55,7 @@ class NewClassInstanceEvaluator implements Evaluator {
}
ClassType classType = (ClassType)obj;
// find constructor
- Method method = DebuggerUtilsEx.findMethod(classType, "<init>", myConstructorSignature.getName(debugProcess));
+ Method method = DebuggerUtils.findMethod(classType, "<init>", myConstructorSignature.getName(debugProcess));
if (method == null) {
throw EvaluateExceptionUtil.createEvaluateException(
DebuggerBundle.message("evaluation.error.cannot.resolve.constructor", myConstructorSignature.getDisplayName(debugProcess)));
diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/RoamingTypeExtensionPointBean.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/UnsupportedExpressionException.java
index ff5d16361228..f4c513d4036c 100644
--- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/RoamingTypeExtensionPointBean.java
+++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/UnsupportedExpressionException.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,17 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.intellij.openapi.components.impl.stores;
+package com.intellij.debugger.engine.evaluation.expression;
-import com.intellij.util.xmlb.annotations.Attribute;
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
/**
- * @deprecated use {@link com.intellij.openapi.components.RoamingType#DISABLED}
+ * @author egor
*/
-@Deprecated
-public class RoamingTypeExtensionPointBean {
- @Attribute("component")
- public String componentName;
- @Attribute("type")
- public String roamingType;
+public class UnsupportedExpressionException extends EvaluateException {
+ public UnsupportedExpressionException(String message) {
+ super(message);
+ }
}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerContextUtil.java b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerContextUtil.java
index 8408364f7e73..f36c9f14cee6 100644
--- a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerContextUtil.java
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerContextUtil.java
@@ -23,11 +23,12 @@ import com.intellij.debugger.jdi.StackFrameProxyImpl;
import com.intellij.debugger.ui.impl.watch.ThreadDescriptorImpl;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.fileEditor.FileEditorManager;
+import com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl;
import com.intellij.openapi.util.Couple;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
-import com.intellij.psi.util.PsiUtilBase;
import com.intellij.xdebugger.XDebugSession;
import com.intellij.xdebugger.XSourcePosition;
import org.jetbrains.annotations.NotNull;
@@ -75,7 +76,9 @@ public class DebuggerContextUtil {
final XDebugSession debugSession = session.getXDebugSession();
if (debugSession != null) {
final XSourcePosition position = debugSession.getCurrentPosition();
- final Editor editor = PsiUtilBase.findEditor(psi);
+ Editor editor = ((FileEditorManagerImpl)FileEditorManager.getInstance(file.getProject())).getSelectedTextEditor(true);
+
+ //final Editor editor = fileEditor instanceof TextEditorImpl ? ((TextEditorImpl)fileEditor).getEditor() : null;
if (editor != null && position != null && file.getVirtualFile().equals(position.getFile())) {
final Couple<Collection<TextRange>> usages = IdentifierHighlighterPass.getHighlightUsages(psi, file);
final List<TextRange> ranges = new ArrayList<TextRange>();
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerManagerImpl.java b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerManagerImpl.java
index 60c0d2dded3d..392a14b78bbf 100644
--- a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerManagerImpl.java
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerManagerImpl.java
@@ -607,8 +607,7 @@ public class DebuggerManagerImpl extends DebuggerManagerEx implements Persistent
}
private void dispose(DebuggerSession session) {
- ProcessHandler processHandler = session.getProcess().getExecutionResult().getProcessHandler();
-
+ ProcessHandler processHandler = session.getProcess().getProcessHandler();
synchronized (mySessions) {
DebuggerSession removed = mySessions.remove(processHandler);
LOG.assertTrue(removed != null);
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerSession.java b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerSession.java
index 0a5210f16c36..dbcf43fd6168 100644
--- a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerSession.java
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerSession.java
@@ -15,7 +15,10 @@
*/
package com.intellij.debugger.impl;
-import com.intellij.debugger.*;
+import com.intellij.debugger.DebugEnvironment;
+import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.DebuggerInvocationUtil;
+import com.intellij.debugger.SourcePosition;
import com.intellij.debugger.engine.*;
import com.intellij.debugger.engine.evaluation.EvaluateException;
import com.intellij.debugger.engine.evaluation.EvaluationListener;
@@ -29,14 +32,11 @@ import com.intellij.debugger.ui.breakpoints.BreakpointWithHighlighter;
import com.intellij.debugger.ui.breakpoints.LineBreakpoint;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.ExecutionResult;
-import com.intellij.execution.Executor;
-import com.intellij.execution.configurations.ModuleRunProfile;
import com.intellij.execution.configurations.RemoteConnection;
import com.intellij.execution.configurations.RemoteState;
import com.intellij.execution.configurations.RunProfileState;
+import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.process.ProcessOutputTypes;
-import com.intellij.execution.runners.ExecutionEnvironmentBuilder;
-import com.intellij.execution.runners.ProgramRunner;
import com.intellij.idea.ActionsBundle;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
@@ -199,6 +199,7 @@ public class DebuggerSession implements AbstractDebuggerSession {
ValueLookupManager.getInstance(getProject()).startListening();
}
+ @NotNull
public DebuggerStateManager getContextManager() {
return myContextManager;
}
@@ -251,7 +252,7 @@ public class DebuggerSession implements AbstractDebuggerSession {
case STATE_DISPOSED:
return DebuggerBundle.message("status.debug.stopped");
}
- return myState.myDescription;
+ return null;
}
/* Stepping */
@@ -371,7 +372,7 @@ public class DebuggerSession implements AbstractDebuggerSession {
}
public boolean isRunning() {
- return getState() == STATE_RUNNING && !getProcess().getExecutionResult().getProcessHandler().isProcessTerminated();
+ return getState() == STATE_RUNNING && !getProcess().getProcessHandler().isProcessTerminated();
}
private SuspendContextImpl getSuspendContext() {
@@ -380,19 +381,6 @@ public class DebuggerSession implements AbstractDebuggerSession {
}
@Nullable
- protected ExecutionResult attach(@NotNull Executor executor,
- @NotNull ProgramRunner runner,
- @NotNull ModuleRunProfile profile,
- @NotNull RunProfileState state,
- RemoteConnection remoteConnection,
- boolean pollConnection) throws ExecutionException {
- return attach(new DefaultDebugEnvironment(new ExecutionEnvironmentBuilder(myDebugProcess.getProject(), executor).runProfile(profile).runner(runner).build(),
- state,
- remoteConnection,
- pollConnection));
- }
-
- @Nullable
protected ExecutionResult attach(DebugEnvironment environment) throws ExecutionException {
RemoteConnection remoteConnection = environment.getRemoteConnection();
final String addressDisplayName = DebuggerBundle.getAddressDisplayName(remoteConnection);
@@ -603,7 +591,7 @@ public class DebuggerSession implements AbstractDebuggerSession {
final String transportName = DebuggerBundle.getTransportName(connection);
final String message = DebuggerBundle.message("status.connected", addressDisplayName, transportName);
- process.getExecutionResult().getProcessHandler().notifyTextAvailable(message + "\n", ProcessOutputTypes.SYSTEM);
+ process.printToConsole(message + "\n");
DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() {
@Override
public void run() {
@@ -630,12 +618,12 @@ public class DebuggerSession implements AbstractDebuggerSession {
@Override
public void processDetached(final DebugProcessImpl debugProcess, boolean closedByUser) {
if (!closedByUser) {
- ExecutionResult executionResult = debugProcess.getExecutionResult();
- if(executionResult != null) {
+ ProcessHandler processHandler = debugProcess.getProcessHandler();
+ if(processHandler != null) {
final RemoteConnection connection = getProcess().getConnection();
final String addressDisplayName = DebuggerBundle.getAddressDisplayName(connection);
final String transportName = DebuggerBundle.getTransportName(connection);
- executionResult.getProcessHandler().notifyTextAvailable(DebuggerBundle.message("status.disconnected", addressDisplayName, transportName) + "\n", ProcessOutputTypes.SYSTEM);
+ processHandler.notifyTextAvailable(DebuggerBundle.message("status.disconnected", addressDisplayName, transportName) + "\n", ProcessOutputTypes.SYSTEM);
}
}
DebuggerInvocationUtil.invokeLater(getProject(), new Runnable() {
@@ -659,7 +647,7 @@ public class DebuggerSession implements AbstractDebuggerSession {
public void threadStopped(DebugProcess proc, ThreadReference thread) {
notifyThreadsRefresh();
}
-
+
private void notifyThreadsRefresh() {
if (!myUpdateAlarm.isDisposed()) {
myUpdateAlarm.cancelAllRequests();
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsEx.java b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsEx.java
index 026b7111d18f..ae6bb5dd7b27 100644
--- a/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsEx.java
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/DebuggerUtilsEx.java
@@ -37,6 +37,7 @@ import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.*;
@@ -403,17 +404,25 @@ public abstract class DebuggerUtilsEx extends DebuggerUtils {
public abstract CompletionEditor createEditor(Project project, PsiElement context, @NonNls String recentsId);
- @Nullable
- public static CodeFragmentFactory getEffectiveCodeFragmentFactory(final PsiElement psiContext) {
- final CodeFragmentFactory factory = ApplicationManager.getApplication().runReadAction(new Computable<CodeFragmentFactory>() {
+ @NotNull
+ public static CodeFragmentFactory findAppropriateCodeFragmentFactory(final TextWithImports text, final PsiElement context) {
+ CodeFragmentFactory factory = ApplicationManager.getApplication().runReadAction(new Computable<CodeFragmentFactory>() {
@Override
public CodeFragmentFactory compute() {
- final List<CodeFragmentFactory> codeFragmentFactories = getCodeFragmentFactories(psiContext);
- // the list always contains at least DefaultCodeFragmentFactory
- return codeFragmentFactories.get(0);
+ final FileType fileType = text.getFileType();
+ final List<CodeFragmentFactory> factories = getCodeFragmentFactories(context);
+ if (fileType == null) {
+ return factories.get(0);
+ }
+ for (CodeFragmentFactory factory : factories) {
+ if (factory.getFileType().equals(fileType)) {
+ return factory;
+ }
+ }
+ return DefaultCodeFragmentFactory.getInstance();
}
});
- return factory != null? new CodeFragmentFactoryContextWrapper(factory) : null;
+ return new CodeFragmentFactoryContextWrapper(factory);
}
private static class SigReader {
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/JavaEditorTextProviderImpl.java b/java/debugger/impl/src/com/intellij/debugger/impl/JavaEditorTextProviderImpl.java
index 02f4ee44fd53..4c8fb08ef09d 100644
--- a/java/debugger/impl/src/com/intellij/debugger/impl/JavaEditorTextProviderImpl.java
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/JavaEditorTextProviderImpl.java
@@ -86,6 +86,10 @@ public class JavaEditorTextProviderImpl implements EditorTextProvider {
public Pair<PsiElement, TextRange> findExpression(PsiElement element, boolean allowMethodCalls) {
PsiElement expression = null;
PsiElement parent = element.getParent();
+ if (parent instanceof PsiLiteralExpression) {
+ element = parent;
+ parent = parent.getParent();
+ }
if (parent instanceof PsiVariable) {
expression = element;
}
@@ -107,12 +111,7 @@ public class JavaEditorTextProviderImpl implements EditorTextProvider {
else if (parent instanceof PsiThisExpression) {
expression = parent;
}
- else if (parent instanceof PsiInstanceOfExpression
- || parent instanceof PsiBinaryExpression
- || parent instanceof PsiPolyadicExpression
- || parent instanceof PsiPrefixExpression
- || parent instanceof PsiConditionalExpression
- ) {
+ else if (parent instanceof PsiExpression && !(parent instanceof PsiNewExpression)) {
if (allowMethodCalls || !DebuggerUtils.hasSideEffects(parent)) {
expression = parent;
}
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/PositionUtil.java b/java/debugger/impl/src/com/intellij/debugger/impl/PositionUtil.java
index 2b23f371f528..47558e8c4da8 100644
--- a/java/debugger/impl/src/com/intellij/debugger/impl/PositionUtil.java
+++ b/java/debugger/impl/src/com/intellij/debugger/impl/PositionUtil.java
@@ -41,6 +41,7 @@ public class PositionUtil extends ContextUtil {
return ContextUtil.getSourcePosition(context);
}
+ @Nullable
public static PsiElement getContextElement(final StackFrameContext context) {
if(context instanceof DebuggerContextImpl) return ((DebuggerContextImpl) context).getContextElement();
diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerDataViewsConfigurable.java b/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerDataViewsConfigurable.java
index 452a924aed00..8785e687eff3 100644
--- a/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerDataViewsConfigurable.java
+++ b/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerDataViewsConfigurable.java
@@ -53,7 +53,7 @@ public class DebuggerDataViewsConfigurable implements SearchableConfigurable {
private JCheckBox myCbShowObjectId;
private StateRestoringCheckBox myCbShowStaticFinalFields;
- private final ArrayRendererConfigurable myArrayRendererConfigurable;
+ //private final ArrayRendererConfigurable myArrayRendererConfigurable;
private JCheckBox myCbEnableAlternateViews;
private JCheckBox myCbEnableToString;
@@ -66,12 +66,12 @@ public class DebuggerDataViewsConfigurable implements SearchableConfigurable {
public DebuggerDataViewsConfigurable(@Nullable Project project) {
myProject = project;
- myArrayRendererConfigurable = new ArrayRendererConfigurable(NodeRendererSettings.getInstance().getArrayRenderer());
+ //myArrayRendererConfigurable = new ArrayRendererConfigurable(NodeRendererSettings.getInstance().getArrayRenderer());
}
@Override
public void disposeUIResources() {
- myArrayRendererConfigurable.disposeUIResources();
+ //myArrayRendererConfigurable.disposeUIResources();
myToStringFilterEditor = null;
myProject = null;
}
@@ -165,13 +165,14 @@ public class DebuggerDataViewsConfigurable implements SearchableConfigurable {
panel.add(showPanel, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 3, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(4, 0, 0, 0), 0, 0));
- final JPanel arraysPanel = new JPanel(new BorderLayout(0, UIUtil.DEFAULT_VGAP));
- final JComponent arraysComponent = myArrayRendererConfigurable.createComponent();
- assert arraysComponent != null;
- arraysPanel.add(arraysComponent, BorderLayout.CENTER);
- arraysPanel.add(myCbHideNullArrayElements, BorderLayout.SOUTH);
- arraysPanel.setBorder(IdeBorderFactory.createTitledBorder("Arrays", true));
- panel.add(arraysPanel, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 3, 1, 1.0, 0.0, GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
+ //final JPanel arraysPanel = new JPanel(new BorderLayout(0, UIUtil.DEFAULT_VGAP));
+ //final JComponent arraysComponent = myArrayRendererConfigurable.createComponent();
+ //assert arraysComponent != null;
+ //arraysPanel.add(arraysComponent, BorderLayout.CENTER);
+ //arraysPanel.add(myCbHideNullArrayElements, BorderLayout.SOUTH);
+ //arraysPanel.setBorder(IdeBorderFactory.createTitledBorder("Arrays", true));
+ //panel.add(arraysPanel, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 3, 1, 1.0, 0.0, GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
+ panel.add(myCbHideNullArrayElements, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 3, 1, 1.0, 0.0, GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
panel.add(myCbEnableAlternateViews, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(4, 0, 0, 10), 0, 0));
// starting 4-th row
@@ -209,7 +210,7 @@ public class DebuggerDataViewsConfigurable implements SearchableConfigurable {
myAutoTooltip.save();
- myArrayRendererConfigurable.apply();
+ //myArrayRendererConfigurable.apply();
rendererSettings.fireRenderersChanged();
}
@@ -250,7 +251,7 @@ public class DebuggerDataViewsConfigurable implements SearchableConfigurable {
myRbFromList.setEnabled(toStringEnabled);
myRbAllThatOverride.setEnabled(toStringEnabled);
- myArrayRendererConfigurable.reset();
+ //myArrayRendererConfigurable.reset();
}
@Override
@@ -266,9 +267,9 @@ public class DebuggerDataViewsConfigurable implements SearchableConfigurable {
}
private boolean areDefaultRenderersModified() {
- if (myArrayRendererConfigurable.isModified()) {
- return true;
- }
+ //if (myArrayRendererConfigurable.isModified()) {
+ // return true;
+ //}
final NodeRendererSettings rendererSettings = NodeRendererSettings.getInstance();
diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerSettings.java b/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerSettings.java
index bb3fafed746f..2855ab4dfc1f 100644
--- a/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerSettings.java
+++ b/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerSettings.java
@@ -20,6 +20,7 @@ import com.intellij.openapi.components.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.WriteExternalException;
+import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.classFilter.ClassFilter;
import com.intellij.util.containers.hash.LinkedHashMap;
import com.intellij.util.xmlb.SkipDefaultValuesSerializationFilters;
@@ -55,6 +56,10 @@ public class DebuggerSettings implements Cloneable, PersistentStateComponent<Ele
@NonNls public static final String RUN_HOTSWAP_NEVER = "RunHotswapNever";
@NonNls public static final String RUN_HOTSWAP_ASK = "RunHotswapAsk";
+ @NonNls public static final String EVALUATE_FINALLY_ALWAYS = "EvaluateFinallyAlways";
+ @NonNls public static final String EVALUATE_FINALLY_NEVER = "EvaluateFinallyNever";
+ @NonNls public static final String EVALUATE_FINALLY_ASK = "EvaluateFinallyAsk";
+
public boolean TRACING_FILTERS_ENABLED;
public int DEBUGGER_TRANSPORT;
public boolean FORCE_CLASSIC_VM;
@@ -74,6 +79,8 @@ public class DebuggerSettings implements Cloneable, PersistentStateComponent<Ele
public volatile boolean AUTO_VARIABLES_MODE = false;
public volatile boolean SHOW_LIBRARY_STACKFRAMES = true;
+ public String EVALUATE_FINALLY_ON_POP_FRAME = EVALUATE_FINALLY_ASK;
+
private ClassFilter[] mySteppingFilters = ClassFilter.EMPTY_ARRAY;
private Map<String, ContentState> myContentStates = new LinkedHashMap<String, ContentState>();
@@ -142,6 +149,7 @@ public class DebuggerSettings implements Cloneable, PersistentStateComponent<Ele
return
TRACING_FILTERS_ENABLED == secondSettings.TRACING_FILTERS_ENABLED &&
DEBUGGER_TRANSPORT == secondSettings.DEBUGGER_TRANSPORT &&
+ StringUtil.equals(EVALUATE_FINALLY_ON_POP_FRAME, secondSettings.EVALUATE_FINALLY_ON_POP_FRAME) &&
FORCE_CLASSIC_VM == secondSettings.FORCE_CLASSIC_VM &&
DISABLE_JIT == secondSettings.DISABLE_JIT &&
HOTSWAP_IN_BACKGROUND == secondSettings.HOTSWAP_IN_BACKGROUND &&
diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerSteppingConfigurable.java b/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerSteppingConfigurable.java
index cf7e367f1ce8..914df8b14a83 100644
--- a/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerSteppingConfigurable.java
+++ b/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerSteppingConfigurable.java
@@ -22,6 +22,7 @@ import com.intellij.ui.classFilter.ClassFilterEditor;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
+import javax.swing.border.Border;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
@@ -33,6 +34,9 @@ class DebuggerSteppingConfigurable implements ConfigurableUi<DebuggerSettings> {
private JCheckBox myCbSkipClassLoaders;
private ClassFilterEditor mySteppingFilterEditor;
private JCheckBox myCbSkipSimpleGetters;
+ private JRadioButton myRbEvaluateFinallyAlways;
+ private JRadioButton myRbEvaluateFinallyNever;
+ private JRadioButton myRbEvaluateFinallyAsk;
@Override
public void reset(@NotNull DebuggerSettings settings) {
@@ -45,6 +49,16 @@ class DebuggerSteppingConfigurable implements ConfigurableUi<DebuggerSettings> {
mySteppingFilterEditor.setFilters(settings.getSteppingFilters());
mySteppingFilterEditor.setEnabled(settings.TRACING_FILTERS_ENABLED);
+
+ if (DebuggerSettings.EVALUATE_FINALLY_ALWAYS.equals(settings.EVALUATE_FINALLY_ON_POP_FRAME)) {
+ myRbEvaluateFinallyAlways.setSelected(true);
+ }
+ else if (DebuggerSettings.EVALUATE_FINALLY_NEVER.equals(settings.EVALUATE_FINALLY_ON_POP_FRAME)) {
+ myRbEvaluateFinallyNever.setSelected(true);
+ }
+ else {
+ myRbEvaluateFinallyAsk.setSelected(true);
+ }
}
@Override
@@ -59,6 +73,16 @@ class DebuggerSteppingConfigurable implements ConfigurableUi<DebuggerSettings> {
settings.SKIP_CLASSLOADERS = myCbSkipClassLoaders.isSelected();
settings.TRACING_FILTERS_ENABLED = myCbStepInfoFiltersEnabled.isSelected();
+ if (myRbEvaluateFinallyAlways.isSelected()) {
+ settings.EVALUATE_FINALLY_ON_POP_FRAME = DebuggerSettings.EVALUATE_FINALLY_ALWAYS;
+ }
+ else if (myRbEvaluateFinallyNever.isSelected()) {
+ settings.EVALUATE_FINALLY_ON_POP_FRAME = DebuggerSettings.EVALUATE_FINALLY_NEVER;
+ }
+ else {
+ settings.EVALUATE_FINALLY_ON_POP_FRAME = DebuggerSettings.EVALUATE_FINALLY_ASK;
+ }
+
mySteppingFilterEditor.stopEditing();
settings.setSteppingFilters(mySteppingFilterEditor.getFilters());
}
@@ -94,6 +118,33 @@ class DebuggerSteppingConfigurable implements ConfigurableUi<DebuggerSettings> {
mySteppingFilterEditor.setEnabled(myCbStepInfoFiltersEnabled.isSelected());
}
});
+
+ myRbEvaluateFinallyAlways = new JRadioButton(DebuggerBundle.message("label.debugger.general.configurable.evaluate.finally.always"));
+ myRbEvaluateFinallyNever = new JRadioButton(DebuggerBundle.message("label.debugger.general.configurable.evaluate.finally.never"));
+ myRbEvaluateFinallyAsk = new JRadioButton(DebuggerBundle.message("label.debugger.general.configurable.evaluate.finally.ask"));
+
+ int cbLeftOffset = 0;
+ final Border border = myCbSkipSimpleGetters.getBorder();
+ if (border != null) {
+ final Insets insets = border.getBorderInsets(myCbSkipSimpleGetters);
+ if (insets != null) {
+ cbLeftOffset = insets.left;
+ }
+ }
+
+ final ButtonGroup group = new ButtonGroup();
+ group.add(myRbEvaluateFinallyAlways);
+ group.add(myRbEvaluateFinallyNever);
+ group.add(myRbEvaluateFinallyAsk);
+ final Box box = Box.createHorizontalBox();
+ box.add(myRbEvaluateFinallyAlways);
+ box.add(myRbEvaluateFinallyNever);
+ box.add(myRbEvaluateFinallyAsk);
+ final JPanel evalFinallyPanel = new JPanel(new BorderLayout());
+ evalFinallyPanel.add(box, BorderLayout.CENTER);
+ evalFinallyPanel.add(new JLabel(DebuggerBundle.message("label.debugger.general.configurable.evaluate.finally.on.pop")), BorderLayout.WEST);
+ panel.add(evalFinallyPanel, new GridBagConstraints(0, GridBagConstraints.RELATIVE, 1, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(4, cbLeftOffset, 0, 0), 0, 0));
+
return panel;
}
} \ No newline at end of file
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerEditorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerEditorImpl.java
index deff5fbd2ae5..8805341c5c46 100644
--- a/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerEditorImpl.java
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerEditorImpl.java
@@ -294,7 +294,7 @@ public abstract class DebuggerEditorImpl extends CompletionEditor{
}
@NotNull
- public static CodeFragmentFactory findAppropriateFactory(@NotNull TextWithImports text, @NotNull PsiElement context) {
+ private static CodeFragmentFactory findAppropriateFactory(@NotNull TextWithImports text, @Nullable PsiElement context) {
for (CodeFragmentFactory factory : DebuggerUtilsEx.getCodeFragmentFactories(context)) {
if (factory.getFileType().equals(text.getFileType())) {
return factory;
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerSessionTab.java b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerSessionTab.java
index 47fc217751a4..0855ed3c1cc4 100644
--- a/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerSessionTab.java
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/DebuggerSessionTab.java
@@ -41,7 +41,6 @@ import com.intellij.execution.filters.TextConsoleBuilder;
import com.intellij.execution.filters.TextConsoleBuilderFactory;
import com.intellij.execution.ui.ConsoleView;
import com.intellij.execution.ui.ExecutionConsoleEx;
-import com.intellij.execution.ui.RunContentDescriptor;
import com.intellij.execution.ui.RunnerLayoutUi;
import com.intellij.execution.ui.layout.PlaceInGrid;
import com.intellij.icons.AllIcons;
@@ -109,7 +108,7 @@ public class DebuggerSessionTab extends DebuggerSessionTabBase implements Dispos
if (XDebuggerSettingsManager.getInstanceImpl().getGeneralSettings().isHideDebuggerOnProcessTermination()) {
try {
- ExecutionManager.getInstance(getProject()).getContentManager().hideRunContent(DefaultDebugExecutor.getDebugExecutorInstance(), myRunContentDescriptor);
+ ExecutionManager.getInstance(project).getContentManager().hideRunContent(DefaultDebugExecutor.getDebugExecutorInstance(), myRunContentDescriptor);
}
catch (NullPointerException e) {
//if we can get closeProcess after the project have been closed
@@ -130,8 +129,8 @@ public class DebuggerSessionTab extends DebuggerSessionTabBase implements Dispos
topToolbar.add(Separator.getInstance(), new Constraints(Anchor.AFTER, DebuggerActions.POP_FRAME));
myUi.getOptions().setTopToolbar(topToolbar, ActionPlaces.DEBUGGER_TOOLBAR);
- myWatchPanel = new MainWatchPanel(getProject(), getContextManager());
- myFramesPanel = new FramesPanel(getProject(), getContextManager());
+ myWatchPanel = new MainWatchPanel(project, getContextManager());
+ myFramesPanel = new FramesPanel(project, getContextManager());
final AlertIcon breakpointAlert = new AlertIcon(AllIcons.Debugger.BreakpointAlert);
@@ -151,7 +150,7 @@ public class DebuggerSessionTab extends DebuggerSessionTabBase implements Dispos
myUi.addContent(framesContent, 0, PlaceInGrid.left, false);
// variables
- myVariablesPanel = new VariablesPanel(getProject(), myStateManager, this);
+ myVariablesPanel = new VariablesPanel(project, myStateManager, this);
myVariablesPanel.getFrameTree().setAutoVariablesMode(debuggerSettings.AUTO_VARIABLES_MODE);
Content vars = myUi.createContent(DebuggerContentInfo.VARIABLES_CONTENT, myVariablesPanel, XDebuggerBundle.message("debugger.session.tab.variables.title"),
AllIcons.Debugger.Value, null);
@@ -200,11 +199,11 @@ public class DebuggerSessionTab extends DebuggerSessionTabBase implements Dispos
}
});
- ExecutionResult executionResult = debuggerSession.getProcess().getExecutionResult();
- myConsole = executionResult.getExecutionConsole();
- myRunContentDescriptor = new RunContentDescriptor(myConsole, executionResult.getProcessHandler(), myUi.getComponent(), getSessionName(),
- environment.getIcon());
- initUI(executionResult);
+// ExecutionResult executionResult = debuggerSession.getProcess().getExecutionResult();
+// myConsole = executionResult.getExecutionConsole();
+// myRunContentDescriptor = new RunContentDescriptor(myConsole, executionResult.getProcessHandler(), myUi.getComponent(), getSessionName(),
+// environment.getIcon());
+// initUI(executionResult);
}
private static void updateStatus(final Content content) {
@@ -226,11 +225,6 @@ public class DebuggerSessionTab extends DebuggerSessionTabBase implements Dispos
return myWatchPanel;
}
- @Override
- public RunContentDescriptor getRunContentDescriptor() {
- return myRunContentDescriptor;
- }
-
private void initUI(ExecutionResult executionResult) {
if (ApplicationManager.getApplication().isUnitTestMode()) {
return;
@@ -270,18 +264,16 @@ public class DebuggerSessionTab extends DebuggerSessionTabBase implements Dispos
}
console.setActions(consoleActions, ActionPlaces.DEBUGGER_TOOLBAR, myConsole.getPreferredFocusableComponent());
- myDebugUIEnvironment.initLogs(myRunContentDescriptor, myManager);
+// myDebugUIEnvironment.initLogs(myRunContentDescriptor, myManager);
DefaultActionGroup leftToolbar = new DefaultActionGroup();
if (executionResult instanceof DefaultExecutionResult) {
final AnAction[] actions = ((DefaultExecutionResult)executionResult).getRestartActions();
- if (actions != null) {
leftToolbar.addAll(actions);
if (actions.length > 0) {
leftToolbar.addSeparator();
}
- }
}
final AnAction[] profileActions = executionResult.getActions();
leftToolbar.addAll(profileActions);
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/EvaluationDialog.java b/java/debugger/impl/src/com/intellij/debugger/ui/EvaluationDialog.java
index 6359af31e5a3..0acaf8779e1f 100644
--- a/java/debugger/impl/src/com/intellij/debugger/ui/EvaluationDialog.java
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/EvaluationDialog.java
@@ -30,7 +30,6 @@ import com.intellij.debugger.ui.impl.ValueNodeDnD;
import com.intellij.debugger.ui.impl.WatchDebuggerTree;
import com.intellij.debugger.ui.impl.WatchPanel;
import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
-import com.intellij.debugger.ui.impl.watch.EvaluationDescriptor;
import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.*;
@@ -110,10 +109,10 @@ public abstract class EvaluationDialog extends DialogWrapper {
try {
setOKActionEnabled(false);
NodeDescriptorImpl descriptor = myEvaluationPanel.getWatchTree().addWatch(codeToEvaluate, "result").getDescriptor();
- if (descriptor instanceof EvaluationDescriptor) {
- final EvaluationDescriptor evalDescriptor = (EvaluationDescriptor)descriptor;
- evalDescriptor.setCodeFragmentFactory(myEditor.getCurrentFactory());
- }
+ //if (descriptor instanceof EvaluationDescriptor) {
+ // final EvaluationDescriptor evalDescriptor = (EvaluationDescriptor)descriptor;
+ // evalDescriptor.setCodeFragmentFactory(myEditor.getCurrentFactory());
+ //}
myEvaluationPanel.getWatchTree().rebuild(getDebuggerContext());
descriptor.myIsExpanded = true;
}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/JavaDebuggerSupport.java b/java/debugger/impl/src/com/intellij/debugger/ui/JavaDebuggerSupport.java
index ec2288fa7a57..e01b8742c4b6 100644
--- a/java/debugger/impl/src/com/intellij/debugger/ui/JavaDebuggerSupport.java
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/JavaDebuggerSupport.java
@@ -61,7 +61,7 @@ public class JavaDebuggerSupport extends DebuggerSupport {
private final PauseActionHandler myPauseActionHandler = new PauseActionHandler();
private final ShowExecutionPointActionHandler myShowExecutionPointActionHandler = new ShowExecutionPointActionHandler();
//private final EvaluateActionHandler myEvaluateActionHandler = new EvaluateActionHandler();
- private final QuickEvaluateActionHandler myQuickEvaluateHandler = new QuickEvaluateActionHandler();
+ //private final QuickEvaluateActionHandler myQuickEvaluateHandler = new QuickEvaluateActionHandler();
private final DebuggerActionHandler mySmartStepIntoHandler = new JvmSmartStepIntoActionHandler();
private final DebuggerActionHandler myAddToWatchedActionHandler = new AddToWatchActionHandler();
private final JavaMarkObjectActionHandler myMarkObjectActionHandler = new JavaMarkObjectActionHandler();
@@ -156,12 +156,6 @@ public class JavaDebuggerSupport extends DebuggerSupport {
return DISABLED;
}
- @Override
- @NotNull
- public QuickEvaluateHandler getQuickEvaluateHandler() {
- return myQuickEvaluateHandler;
- }
-
@NotNull
@Override
public DebuggerActionHandler getAddToWatchesActionHandler() {
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/ValueHint.java b/java/debugger/impl/src/com/intellij/debugger/ui/ValueHint.java
index 8a0877273335..9034e5c82b13 100644
--- a/java/debugger/impl/src/com/intellij/debugger/ui/ValueHint.java
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/ValueHint.java
@@ -94,9 +94,8 @@ public class ValueHint extends AbstractValueHint {
return EvaluatorBuilderImpl.getInstance().build(myCurrentExpression, debuggerContext.getSourcePosition());
}
- CodeFragmentFactory factory = DebuggerUtilsEx.getEffectiveCodeFragmentFactory(myCurrentExpression);
TextWithImportsImpl textWithImports = new TextWithImportsImpl(CodeFragmentKind.EXPRESSION, myCurrentExpression.getText());
- if (factory == null) return null;
+ CodeFragmentFactory factory = DebuggerUtilsEx.findAppropriateCodeFragmentFactory(textWithImports, myCurrentExpression);
JavaCodeFragment codeFragment = factory.createCodeFragment(textWithImports, myCurrentExpression.getContext(), getProject());
codeFragment.forceResolveScope(GlobalSearchScope.allScope(getProject()));
return factory.getEvaluatorBuilder().build(codeFragment, debuggerContext.getSourcePosition());
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ArgumentValueDescriptorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ArgumentValueDescriptorImpl.java
index 7adee9d7c0eb..525abba6613f 100644
--- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ArgumentValueDescriptorImpl.java
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/ArgumentValueDescriptorImpl.java
@@ -50,6 +50,11 @@ public class ArgumentValueDescriptorImpl extends ValueDescriptorImpl{
setLvalue(true);
}
+ @Override
+ public boolean canSetValue() {
+ return false;
+ }
+
public boolean isPrimitive() {
return myValue instanceof PrimitiveValue;
}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/CompilingEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/CompilingEvaluator.java
index 042216c40f05..467cf985f04c 100644
--- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/CompilingEvaluator.java
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/CompilingEvaluator.java
@@ -15,28 +15,57 @@
*/
package com.intellij.debugger.ui.impl.watch;
+import com.intellij.debugger.DebuggerInvocationUtil;
+import com.intellij.debugger.EvaluatingComputable;
+import com.intellij.debugger.engine.ContextUtil;
import com.intellij.debugger.engine.DebugProcess;
-import com.intellij.debugger.engine.evaluation.EvaluateException;
-import com.intellij.debugger.engine.evaluation.EvaluationContext;
-import com.intellij.debugger.engine.evaluation.TextWithImports;
+import com.intellij.debugger.engine.evaluation.*;
import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator;
import com.intellij.debugger.engine.evaluation.expression.Modifier;
+import com.intellij.debugger.impl.DebuggerUtilsEx;
import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Computable;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiCodeFragment;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiJavaFile;
+import com.intellij.refactoring.extractMethodObject.ExtractLightMethodObjectHandler;
import com.sun.jdi.*;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.org.objectweb.asm.ClassReader;
+import org.jetbrains.org.objectweb.asm.ClassVisitor;
+import org.jetbrains.org.objectweb.asm.ClassWriter;
+import org.jetbrains.org.objectweb.asm.Opcodes;
import javax.tools.*;
import java.io.ByteArrayOutputStream;
import java.net.URI;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
/**
* @author egor
*/
-class CompilingEvaluator implements ExpressionEvaluator {
+public class CompilingEvaluator implements ExpressionEvaluator {
private final TextWithImports myText;
-
- public CompilingEvaluator(TextWithImports text) {
+ private final PsiCodeFragment myCodeFragment;
+ private final PsiElement myPsiContext;
+ @NotNull private final ExtractLightMethodObjectHandler.ExtractedData myData;
+ private final EvaluationDescriptor myDescriptor;
+
+ public CompilingEvaluator(TextWithImports text,
+ PsiCodeFragment codeFragment,
+ PsiElement context,
+ @NotNull ExtractLightMethodObjectHandler.ExtractedData data,
+ EvaluationDescriptor descriptor) {
myText = text;
+ myCodeFragment = codeFragment;
+ myPsiContext = context;
+ myData = data;
+ myDescriptor = descriptor;
}
@Override
@@ -49,20 +78,41 @@ class CompilingEvaluator implements ExpressionEvaluator {
return null;
}
+ private TextWithImports getCallCode() {
+ return new TextWithImportsImpl(CodeFragmentKind.CODE_BLOCK, myData.getGeneratedCallText());
+ }
+
@Override
- public Value evaluate(EvaluationContext context) throws EvaluateException {
+ public Value evaluate(final EvaluationContext evaluationContext) throws EvaluateException {
try {
- DebugProcess process = context.getDebugProcess();
- ThreadReference threadReference = context.getSuspendContext().getThread().getThreadReference();
+ DebugProcess process = evaluationContext.getDebugProcess();
+ ThreadReference threadReference = evaluationContext.getSuspendContext().getThread().getThreadReference();
- ClassLoaderReference classLoader = getClassLoader(context);
+ ClassLoaderReference classLoader = getClassLoader(evaluationContext);
Collection<OutputFileObject> classes = compile();
- ClassType mainClass = defineClasses(classes, context, process, threadReference, classLoader);
-
- Method foo = mainClass.methodsByName(GEN_METHOD_NAME).get(0);
- return mainClass.invokeMethod(threadReference, foo, Collections.<Value>emptyList() ,ClassType.INVOKE_SINGLE_THREADED);
+ ClassType mainClass = defineClasses(classes, evaluationContext, process, threadReference, classLoader);
+
+ //Method foo = mainClass.methodsByName(GEN_METHOD_NAME).get(0);
+ //return mainClass.invokeMethod(threadReference, foo, Collections.<Value>emptyList() ,ClassType.INVOKE_SINGLE_THREADED);
+
+ // invoke base evaluator on call code
+ final Project project = myPsiContext.getProject();
+ ExpressionEvaluator evaluator =
+ DebuggerInvocationUtil.commitAndRunReadAction(project, new EvaluatingComputable<ExpressionEvaluator>() {
+ @Override
+ public ExpressionEvaluator compute() throws EvaluateException {
+ final TextWithImports callCode = getCallCode();
+ PsiElement copyContext = myData.getAnchor();
+ final CodeFragmentFactory factory = DebuggerUtilsEx.findAppropriateCodeFragmentFactory(callCode, copyContext);
+ return factory.getEvaluatorBuilder().
+ build(factory.createCodeFragment(callCode, copyContext, project),
+ ContextUtil.getSourcePosition(evaluationContext));
+ }
+ });
+ ((EvaluationContextImpl)evaluationContext).setClassLoader(classLoader);
+ return evaluator.evaluate(evaluationContext);
}
catch (Exception e) {
throw new EvaluateException(e.getMessage());
@@ -74,13 +124,13 @@ class CompilingEvaluator implements ExpressionEvaluator {
// TODO: cache
DebugProcess process = context.getDebugProcess();
ClassType loaderClass = (ClassType)process.findClass(context, "java.net.URLClassLoader", context.getClassLoader());
- Method ctorMethod = loaderClass.concreteMethodByName("<init>", "([Ljava/net/URL;)V");
+ Method ctorMethod = loaderClass.concreteMethodByName("<init>", "([Ljava/net/URL;Ljava/lang/ClassLoader;)V");
ThreadReference threadReference = context.getSuspendContext().getThread().getThreadReference();
return (ClassLoaderReference)loaderClass.newInstance(threadReference, ctorMethod,
- Arrays.asList(createURLArray(context)), ClassType.INVOKE_SINGLE_THREADED);
+ Arrays.asList(createURLArray(context), context.getClassLoader()), ClassType.INVOKE_SINGLE_THREADED);
}
- private static ClassType defineClasses(Collection<OutputFileObject> classes,
+ private ClassType defineClasses(Collection<OutputFileObject> classes,
EvaluationContext context,
DebugProcess process,
ThreadReference threadReference,
@@ -89,16 +139,34 @@ class CompilingEvaluator implements ExpressionEvaluator {
VirtualMachineProxyImpl proxy = (VirtualMachineProxyImpl)process.getVirtualMachineProxy();
for (OutputFileObject cls : classes) {
- Method defineMethod = ((ClassType)classLoader.referenceType()).concreteMethodByName("defineClass", "(Ljava/lang/String;[BII)Ljava/lang/Class;");
- byte[] bytes = cls.toByteArray();
- ArrayList<Value> args = new ArrayList<Value>();
- args.add(proxy.mirrorOf(cls.myOrigName));
- args.add(mirrorOf(bytes, context, process));
- args.add(proxy.mirrorOf(0));
- args.add(proxy.mirrorOf(bytes.length));
- classLoader.invokeMethod(threadReference, defineMethod, args, ClassType.INVOKE_SINGLE_THREADED);
+ if (cls.getName().contains(getGenClassName())) {
+ Method defineMethod =
+ ((ClassType)classLoader.referenceType()).concreteMethodByName("defineClass", "(Ljava/lang/String;[BII)Ljava/lang/Class;");
+ byte[] bytes = changeSuperToMagicAccessor(cls.toByteArray());
+ ArrayList<Value> args = new ArrayList<Value>();
+ args.add(proxy.mirrorOf(cls.myOrigName));
+ args.add(mirrorOf(bytes, context, process));
+ args.add(proxy.mirrorOf(0));
+ args.add(proxy.mirrorOf(bytes.length));
+ classLoader.invokeMethod(threadReference, defineMethod, args, ClassType.INVOKE_SINGLE_THREADED);
+ }
}
- return (ClassType)process.findClass(context, GEN_CLASS_FULL_NAME, classLoader);
+ return (ClassType)process.findClass(context, getGenClassFullName(), classLoader);
+ }
+
+ private static byte[] changeSuperToMagicAccessor(byte[] bytes) {
+ ClassWriter classWriter = new ClassWriter(0);
+ ClassVisitor classVisitor = new ClassVisitor(Opcodes.ASM5, classWriter) {
+ @Override
+ public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+ if ("java/lang/Object".equals(superName)) {
+ superName = "sun/reflect/MagicAccessorImpl";
+ }
+ super.visit(version, access, name, signature, superName, interfaces);
+ }
+ };
+ new ClassReader(bytes).accept(classVisitor, 0);
+ return classWriter.toByteArray();
}
private static ArrayReference mirrorOf(byte[] bytes, EvaluationContext context, DebugProcess process)
@@ -112,10 +180,90 @@ class CompilingEvaluator implements ExpressionEvaluator {
return reference;
}
- private static final String GEN_CLASS_NAME = "Evaluator";
+ public static String getGeneratedClassName() {
+ return GEN_CLASS_NAME;
+ }
+
+ private static final String GEN_CLASS_NAME = "GeneratedEvaluationClass";
private static final String GEN_CLASS_PACKAGE = "dummy";
private static final String GEN_CLASS_FULL_NAME = GEN_CLASS_PACKAGE + '.' + GEN_CLASS_NAME;
- private static final String GEN_METHOD_NAME = "eval";
+ private static final String GEN_METHOD_NAME = "invoke";
+
+ private String getClassCode() {
+ if (myData != null) {
+ return ApplicationManager.getApplication().runReadAction(new Computable<String>() {
+ @Override
+ public String compute() {
+ //String text = myData.getGeneratedInnerClass().getText();
+ ////TODO: remove
+ //String prefix = "public static";
+ //if (text.startsWith(prefix)) {
+ // text = "public" + text.substring(prefix.length());
+ //}
+ //PsiElement[] children = ((PsiJavaFile)myPsiContext.getContainingFile()).getImportList().getChildren();
+ //StringBuilder imports = new StringBuilder();
+ //for (PsiElement child : children) {
+ // if (child instanceof PsiImportStatement) {
+ // String name = ((PsiImportStatement)child).getImportReference().getQualifiedName();
+ // imports.append("import ").append(name).append(";");
+ // }
+ //}
+ //text = text.replace("class " + GEN_CLASS_NAME, "class " + getGenClassName());
+ //text = text.replace(GEN_CLASS_NAME + "(", getGenClassName() + "(");
+ //text = text.replace(((PsiClass)myData.getGeneratedInnerClass().getParent()).getName() + "." + GEN_CLASS_NAME, getGenClassName());
+ //return "package " + getGenPackageName() + "; " + imports.toString() + text;
+ return myData.getGeneratedInnerClass().getContainingFile().getText();
+ }
+ });
+ }
+ return null;
+ }
+
+ private String getGenPackageName() {
+ return ApplicationManager.getApplication().runReadAction(new Computable<String>() {
+ @Override
+ public String compute() {
+ return ((PsiJavaFile)myData.getGeneratedInnerClass().getContainingFile()).getPackageName();
+ }
+ });
+ }
+
+ private String getMainClassName() {
+ return ApplicationManager.getApplication().runReadAction(new Computable<String>() {
+ @Override
+ public String compute() {
+ return ((PsiClass)myData.getGeneratedInnerClass().getParent()).getName();
+ }
+ });
+ }
+
+ private String getGenClassName() {
+ return getMainClassName() + '$' + GEN_CLASS_NAME;
+ }
+
+ private String getGenClassFullName() {
+ String packageName = getGenPackageName();
+ if (packageName.isEmpty()) {
+ return getGenClassName();
+ }
+ return packageName + '.' + getGenClassName();
+ }
+
+ //private String createClassCode() {
+ // return ApplicationManager.getApplication().runReadAction(new Computable<String>() {
+ // @Override
+ // public String compute() {
+ // try {
+ // myExtractedData =
+ // ExtractLightMethodObjectHandler.extractLightMethodObject(myCodeFragment.getProject(), myFile , myCodeFragment, "test");
+ // }
+ // catch (PrepareFailedException e) {
+ // e.printStackTrace();
+ // }
+ // return null;
+ // }
+ // });
+ //}
private static String createClassCode(TextWithImports body) {
StringBuilder text = new StringBuilder();
@@ -155,9 +303,9 @@ class CompilingEvaluator implements ExpressionEvaluator {
MemoryFileManager manager = new MemoryFileManager(compiler);
DiagnosticCollector<JavaFileObject> diagnostic = new DiagnosticCollector<JavaFileObject>();
if (!compiler.getTask(null, manager, diagnostic, null, null, Arrays
- .asList(new SourceFileObject(GEN_CLASS_NAME, JavaFileObject.Kind.SOURCE, createClassCode(myText)))).call()) {
+ .asList(new SourceFileObject(getMainClassName(), JavaFileObject.Kind.SOURCE, getClassCode()))).call()) {
// TODO: show only errors
- throw new EvaluateException(diagnostic.getDiagnostics().get(0).getMessage(Locale.getDefault()));
+ throw new EvaluateException(diagnostic.getDiagnostics().get(0).toString());
}
return manager.classes;
}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/EvaluationDescriptor.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/EvaluationDescriptor.java
index 1f880513cacd..05e0a1fe6aec 100644
--- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/EvaluationDescriptor.java
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/EvaluationDescriptor.java
@@ -21,22 +21,26 @@ import com.intellij.debugger.DebuggerInvocationUtil;
import com.intellij.debugger.EvaluatingComputable;
import com.intellij.debugger.engine.ContextUtil;
import com.intellij.debugger.engine.StackFrameContext;
-import com.intellij.debugger.engine.evaluation.*;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.debugger.engine.evaluation.TextWithImports;
+import com.intellij.debugger.engine.evaluation.expression.UnsupportedExpressionException;
import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator;
import com.intellij.debugger.engine.evaluation.expression.Modifier;
import com.intellij.debugger.impl.DebuggerUtilsEx;
import com.intellij.debugger.impl.PositionUtil;
import com.intellij.debugger.jdi.StackFrameProxyImpl;
+import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.registry.Registry;
-import com.intellij.psi.PsiCodeFragment;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiExpression;
-import com.intellij.psi.PsiExpressionCodeFragment;
+import com.intellij.psi.*;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.refactoring.extractMethod.PrepareFailedException;
+import com.intellij.refactoring.extractMethodObject.ExtractLightMethodObjectHandler;
+import com.sun.jdi.ObjectCollectedException;
import com.sun.jdi.ObjectReference;
import com.sun.jdi.Value;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
/**
* @author lex
@@ -44,7 +48,6 @@ import org.jetbrains.annotations.Nullable;
public abstract class EvaluationDescriptor extends ValueDescriptorImpl{
private Modifier myModifier;
protected TextWithImports myText;
- private CodeFragmentFactory myCodeFragmentFactory = null; // used to force specific context, e.g. from evaluation
protected EvaluationDescriptor(TextWithImports text, Project project, Value value) {
super(project, value);
@@ -57,44 +60,60 @@ public abstract class EvaluationDescriptor extends ValueDescriptorImpl{
myText = text;
}
- public final void setCodeFragmentFactory(CodeFragmentFactory codeFragmentFactory) {
- myCodeFragmentFactory = codeFragmentFactory != null? new CodeFragmentFactoryContextWrapper(codeFragmentFactory) : null;
- }
-
- @Nullable
- public final CodeFragmentFactory getCodeFragmentFactory() {
- return myCodeFragmentFactory;
- }
-
- protected final @NotNull CodeFragmentFactory getEffectiveCodeFragmentFactory(final PsiElement psiContext) {
- if (myCodeFragmentFactory != null) {
- return myCodeFragmentFactory;
- }
- return DebuggerUtilsEx.getEffectiveCodeFragmentFactory(psiContext);
- }
-
protected abstract EvaluationContextImpl getEvaluationContext (EvaluationContextImpl evaluationContext);
protected abstract PsiCodeFragment getEvaluationCode(StackFrameContext context) throws EvaluateException;
+ public PsiCodeFragment createCodeFragment(PsiElement context) {
+ TextWithImports text = getEvaluationText();
+ final PsiCodeFragment fragment =
+ DebuggerUtilsEx.findAppropriateCodeFragmentFactory(text, context).createCodeFragment(text, context, myProject);
+ fragment.forceResolveScope(GlobalSearchScope.allScope(myProject));
+ return fragment;
+ }
+
public final Value calcValue(final EvaluationContextImpl evaluationContext) throws EvaluateException {
try {
final EvaluationContextImpl thisEvaluationContext = getEvaluationContext(evaluationContext);
- final ExpressionEvaluator evaluator;
- if (Registry.is("debugger.compiling.evaluator")) {
- evaluator = new CompilingEvaluator(getEvaluationText());
- }
- else {
+ ExpressionEvaluator evaluator = null;
+ try {
evaluator = DebuggerInvocationUtil.commitAndRunReadAction(myProject, new EvaluatingComputable<ExpressionEvaluator>() {
public ExpressionEvaluator compute() throws EvaluateException {
final PsiElement psiContext = PositionUtil.getContextElement(evaluationContext);
- return getEffectiveCodeFragmentFactory(psiContext).getEvaluatorBuilder().build(getEvaluationCode(thisEvaluationContext),
- ContextUtil
- .getSourcePosition(thisEvaluationContext));
+ return DebuggerUtilsEx.findAppropriateCodeFragmentFactory(getEvaluationText(), psiContext).getEvaluatorBuilder()
+ .build(getEvaluationCode(thisEvaluationContext), ContextUtil.getSourcePosition(thisEvaluationContext));
}
});
}
+ catch (UnsupportedExpressionException ex) {
+ if (Registry.is("debugger.compiling.evaluator")) {
+ evaluator = DebuggerInvocationUtil.commitAndRunReadAction(myProject, new EvaluatingComputable<ExpressionEvaluator>() {
+ public ExpressionEvaluator compute() throws EvaluateException {
+ final PsiElement psiContext = PositionUtil.getContextElement(evaluationContext);
+ if (psiContext == null) {
+ return null;
+ }
+ PsiFile psiFile = psiContext.getContainingFile();
+ PsiCodeFragment fragment = createCodeFragment(psiContext);
+ try {
+ ExtractLightMethodObjectHandler.ExtractedData data = ExtractLightMethodObjectHandler.extractLightMethodObject(myProject,
+ psiFile, fragment, CompilingEvaluator.getGeneratedClassName());
+ if (data != null) {
+ return new CompilingEvaluator(getEvaluationText(), getEvaluationCode(thisEvaluationContext), psiContext, data,
+ EvaluationDescriptor.this);
+ }
+ }
+ catch (PrepareFailedException ignored) {
+ }
+ return null;
+ }
+ });
+ }
+ if (evaluator == null) {
+ throw ex;
+ }
+ }
if (!thisEvaluationContext.getDebugProcess().isAttached()) {
throw EvaluateExceptionUtil.PROCESS_EXITED;
@@ -106,7 +125,11 @@ public abstract class EvaluationDescriptor extends ValueDescriptorImpl{
final Value value = evaluator.evaluate(thisEvaluationContext);
if (value instanceof ObjectReference) {
- thisEvaluationContext.getSuspendContext().keep(((ObjectReference)value));
+ ObjectReference objRef = (ObjectReference)value;
+ if (VirtualMachineProxyImpl.isCollected(objRef)) {
+ throw EvaluateExceptionUtil.OBJECT_WAS_COLLECTED;
+ }
+ thisEvaluationContext.getSuspendContext().keep(objRef);
}
myModifier = evaluator.getModifier();
setLvalue(myModifier != null);
@@ -116,6 +139,9 @@ public abstract class EvaluationDescriptor extends ValueDescriptorImpl{
catch (final EvaluateException ex) {
throw new EvaluateException(ex.getLocalizedMessage(), ex);
}
+ catch (ObjectCollectedException ex) {
+ throw EvaluateExceptionUtil.OBJECT_WAS_COLLECTED;
+ }
}
public String calcValueName() {
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/NodeDescriptorFactoryImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/NodeDescriptorFactoryImpl.java
index 3455672fa4dc..0a94548338d4 100644
--- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/NodeDescriptorFactoryImpl.java
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/NodeDescriptorFactoryImpl.java
@@ -93,6 +93,10 @@ public class NodeDescriptorFactoryImpl implements NodeDescriptorFactory {
}
public void deriveHistoryTree(DescriptorTree tree, final StackFrameContext context) {
+ deriveHistoryTree(tree, context.getFrameProxy());
+ }
+
+ public void deriveHistoryTree(DescriptorTree tree, final StackFrameProxy frameProxy) {
final MarkedDescriptorTree descriptorTree = new MarkedDescriptorTree();
final MarkedDescriptorTree displayDescriptorTree = new MarkedDescriptorTree();
@@ -109,13 +113,12 @@ public class NodeDescriptorFactoryImpl implements NodeDescriptorFactory {
myDescriptorSearcher = new DescriptorTreeSearcher(descriptorTree);
myDisplayDescriptorSearcher = new DisplayDescriptorTreeSearcher(displayDescriptorTree);
- myCurrentHistoryTree = createDescriptorTree(context, tree);
+ myCurrentHistoryTree = createDescriptorTree(frameProxy, tree);
}
- private static DescriptorTree createDescriptorTree(final StackFrameContext context, final DescriptorTree fromTree) {
+ private static DescriptorTree createDescriptorTree(final StackFrameProxy frameProxy, final DescriptorTree fromTree) {
int frameCount = -1;
int frameIndex = -1;
- final StackFrameProxy frameProxy = context.getFrameProxy();
if (frameProxy != null) {
try {
final ThreadReferenceProxy threadReferenceProxy = frameProxy.threadProxy();
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/NodeManagerImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/NodeManagerImpl.java
index 53e820da02fd..b76022122594 100644
--- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/NodeManagerImpl.java
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/NodeManagerImpl.java
@@ -75,11 +75,15 @@ public class NodeManagerImpl extends NodeDescriptorFactoryImpl implements NodeMa
}
public void setHistoryByContext(final DebuggerContextImpl context) {
+ setHistoryByContext(context.getFrameProxy());
+ }
+
+ public void setHistoryByContext(StackFrameProxyImpl frameProxy) {
if (myHistoryKey != null) {
myHistories.put(myHistoryKey, getCurrentHistoryTree());
}
- final String historyKey = getContextKey(context.getFrameProxy());
+ final String historyKey = getContextKey(frameProxy);
final DescriptorTree descriptorTree;
if (historyKey != null) {
final DescriptorTree historyTree = myHistories.get(historyKey);
@@ -89,7 +93,7 @@ public class NodeManagerImpl extends NodeDescriptorFactoryImpl implements NodeMa
descriptorTree = new DescriptorTree(true);
}
- deriveHistoryTree(descriptorTree, context);
+ deriveHistoryTree(descriptorTree, frameProxy);
myHistoryKey = historyKey;
}
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/UserExpressionDescriptorImpl.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/UserExpressionDescriptorImpl.java
index c3dbed6c7fbb..35e73c2b6378 100644
--- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/UserExpressionDescriptorImpl.java
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/UserExpressionDescriptorImpl.java
@@ -21,19 +21,18 @@
package com.intellij.debugger.ui.impl.watch;
import com.intellij.debugger.DebuggerBundle;
+import com.intellij.debugger.engine.DebuggerUtils;
import com.intellij.debugger.engine.StackFrameContext;
import com.intellij.debugger.engine.evaluation.EvaluateException;
import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
import com.intellij.debugger.engine.evaluation.TextWithImports;
-import com.intellij.debugger.impl.DebuggerUtilsEx;
import com.intellij.debugger.settings.NodeRendererSettings;
import com.intellij.debugger.ui.tree.UserExpressionDescriptor;
import com.intellij.debugger.ui.tree.render.ClassRenderer;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiCodeFragment;
-import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.StringBuilderSpinAllocator;
import com.sun.jdi.ObjectReference;
import com.sun.jdi.Value;
@@ -78,16 +77,13 @@ public class UserExpressionDescriptorImpl extends EvaluationDescriptor implement
if(value instanceof ObjectReference) {
final String typeName = value.type().name();
- final PsiClass psiClass = DebuggerUtilsEx.findClass(myTypeName, myProject, context.getDebugProcess().getSearchScope());
+ final PsiClass psiClass = DebuggerUtils.findClass(myTypeName, myProject, context.getDebugProcess().getSearchScope());
if (psiClass == null) {
throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.invalid.type.name", typeName));
}
- final PsiCodeFragment fragment =
- getEffectiveCodeFragmentFactory(psiClass).createCodeFragment(getEvaluationText(), psiClass, myProject);
- fragment.forceResolveScope(GlobalSearchScope.allScope(myProject));
- return fragment;
+ return createCodeFragment(psiClass);
}
else {
throw EvaluateExceptionUtil.createEvaluateException(
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/WatchItemDescriptor.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/WatchItemDescriptor.java
index 30f5169fbd1e..f60825cee24c 100644
--- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/WatchItemDescriptor.java
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/WatchItemDescriptor.java
@@ -28,8 +28,6 @@ import com.intellij.debugger.impl.PositionUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.psi.PsiCodeFragment;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.search.GlobalSearchScope;
import com.sun.jdi.Value;
import org.jetbrains.annotations.Nullable;
@@ -85,9 +83,6 @@ public class WatchItemDescriptor extends EvaluationDescriptor {
}
protected PsiCodeFragment getEvaluationCode(StackFrameContext context) throws EvaluateException {
- final PsiElement psiContext = PositionUtil.getContextElement(context);
- final PsiCodeFragment fragment = getEffectiveCodeFragmentFactory(psiContext).createCodeFragment(getEvaluationText(), psiContext, myProject);
- fragment.forceResolveScope(GlobalSearchScope.allScope(myProject));
- return fragment;
+ return createCodeFragment(PositionUtil.getContextElement(context));
}
} \ No newline at end of file
diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ArrayRenderer.java b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ArrayRenderer.java
index 9615aae98233..f7f05fcc496f 100644
--- a/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ArrayRenderer.java
+++ b/java/debugger/impl/src/com/intellij/debugger/ui/tree/render/ArrayRenderer.java
@@ -65,6 +65,8 @@ public class ArrayRenderer extends NodeRendererImpl{
public int ENTRIES_LIMIT = 101;
private final static String MORE_ELEMENTS = "...";
+ private boolean myForced = false;
+
public ArrayRenderer() {
myProperties.setEnabled(true);
}
@@ -97,13 +99,19 @@ public class ArrayRenderer extends NodeRendererImpl{
return ClassRenderer.calcLabel(descriptor);
}
+ public void setForced(boolean forced) {
+ myForced = forced;
+ }
+
public void buildChildren(Value value, ChildrenBuilder builder, EvaluationContext evaluationContext) {
DebuggerManagerThreadImpl.assertIsManagerThread();
List<DebuggerTreeNode> children = new ArrayList<DebuggerTreeNode>();
NodeManagerImpl nodeManager = (NodeManagerImpl)builder.getNodeManager();
NodeDescriptorFactory descriptorFactory = builder.getDescriptorManager();
- builder.initChildrenArrayRenderer(this);
+ if (!myForced) {
+ builder.initChildrenArrayRenderer(this);
+ }
ArrayReference array = (ArrayReference)value;
if (array.length() > 0) {
@@ -182,7 +190,7 @@ public class ArrayRenderer extends NodeRendererImpl{
// children.add(0, nodeManager.createMessageNode(new MessageDescriptor(MORE_ELEMENTS, MessageDescriptor.SPECIAL)));
//}
- if(END_INDEX < array.length() - 1) {
+ if(!myForced && END_INDEX < array.length() - 1) {
//children.add(nodeManager.createMessageNode(new MessageDescriptor(MORE_ELEMENTS, MessageDescriptor.SPECIAL)));
builder.setRemaining(array.length()-END_INDEX);
}
diff --git a/java/debugger/impl/src/org/jetbrains/java/debugger/JavaDebuggerEditorsProvider.java b/java/debugger/impl/src/org/jetbrains/java/debugger/JavaDebuggerEditorsProvider.java
index 8c85e494dea2..c3b19470e6a4 100644
--- a/java/debugger/impl/src/org/jetbrains/java/debugger/JavaDebuggerEditorsProvider.java
+++ b/java/debugger/impl/src/org/jetbrains/java/debugger/JavaDebuggerEditorsProvider.java
@@ -1,11 +1,9 @@
package org.jetbrains.java.debugger;
import com.intellij.debugger.engine.evaluation.CodeFragmentFactory;
-import com.intellij.debugger.engine.evaluation.CodeFragmentFactoryContextWrapper;
import com.intellij.debugger.engine.evaluation.TextWithImports;
import com.intellij.debugger.engine.evaluation.TextWithImportsImpl;
import com.intellij.debugger.impl.DebuggerUtilsEx;
-import com.intellij.debugger.ui.DebuggerEditorImpl;
import com.intellij.ide.highlighter.JavaFileType;
import com.intellij.lang.Language;
import com.intellij.openapi.editor.Document;
@@ -73,16 +71,15 @@ public class JavaDebuggerEditorsProvider extends XDebuggerEditorsProviderBase {
boolean isPhysical) {
TextWithImports text = TextWithImportsImpl.fromXExpression(expression);
if (text != null && context != null) {
- CodeFragmentFactory factory = new CodeFragmentFactoryContextWrapper(DebuggerEditorImpl.findAppropriateFactory(text, context));
+ CodeFragmentFactory factory = DebuggerUtilsEx.findAppropriateCodeFragmentFactory(text, context);
JavaCodeFragment codeFragment = factory.createPresentationCodeFragment(text, context, project);
codeFragment.forceResolveScope(GlobalSearchScope.allScope(project));
- if (context != null) {
- final PsiClass contextClass = PsiTreeUtil.getNonStrictParentOfType(context, PsiClass.class);
- if (contextClass != null) {
- final PsiClassType contextType =
- JavaPsiFacade.getInstance(codeFragment.getProject()).getElementFactory().createType(contextClass);
- codeFragment.setThisType(contextType);
- }
+
+ final PsiClass contextClass = PsiTreeUtil.getNonStrictParentOfType(context, PsiClass.class);
+ if (contextClass != null) {
+ final PsiClassType contextType =
+ JavaPsiFacade.getInstance(codeFragment.getProject()).getElementFactory().createType(contextClass);
+ codeFragment.setThisType(contextType);
}
return codeFragment;
}
diff --git a/java/debugger/openapi/src/com/intellij/debugger/SourcePosition.java b/java/debugger/openapi/src/com/intellij/debugger/SourcePosition.java
index 45f50d34b922..86bdbde18201 100644
--- a/java/debugger/openapi/src/com/intellij/debugger/SourcePosition.java
+++ b/java/debugger/openapi/src/com/intellij/debugger/SourcePosition.java
@@ -233,7 +233,7 @@ public abstract class SourcePosition implements Navigatable{
}
}
- PsiElement element;
+ PsiElement element = null;
int offset = startOffset;
while (true) {
final CharSequence charsSequence = document.getCharsSequence();
@@ -243,6 +243,8 @@ public abstract class SourcePosition implements Navigatable{
break;
}
}
+ if (offset >= charsSequence.length()) break;
+
element = rootElement.findElementAt(offset);
if (element instanceof PsiComment) {
diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/DebugProcess.java b/java/debugger/openapi/src/com/intellij/debugger/engine/DebugProcess.java
index 66fea2d7f38c..7a3624b1d16a 100644
--- a/java/debugger/openapi/src/com/intellij/debugger/engine/DebugProcess.java
+++ b/java/debugger/openapi/src/com/intellij/debugger/engine/DebugProcess.java
@@ -22,6 +22,7 @@ import com.intellij.debugger.engine.jdi.VirtualMachineProxy;
import com.intellij.debugger.engine.managerThread.DebuggerManagerThread;
import com.intellij.debugger.requests.RequestManager;
import com.intellij.execution.ExecutionResult;
+import com.intellij.execution.process.ProcessHandler;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.psi.search.GlobalSearchScope;
@@ -37,7 +38,7 @@ import java.util.List;
public interface DebugProcess {
@NonNls String JAVA_STRATUM = "Java";
- <T> T getUserData(Key<T> key);
+ <T> T getUserData(Key<T> key);
<T> void putUserData(Key<T> key, T value);
Project getProject();
@@ -76,17 +77,17 @@ public interface DebugProcess {
List args) throws EvaluateException;
/**
- * Is equivalent to invokeInstanceMethod(evaluationContext, classType, method, args, 0)
+ * Is equivalent to invokeInstanceMethod(evaluationContext, classType, method, args, 0)
*/
Value invokeMethod(EvaluationContext evaluationContext,
ClassType classType,
Method method,
List args) throws EvaluateException;
- Value invokeInstanceMethod(EvaluationContext evaluationContext,
- ObjectReference objRef,
- Method method,
- List args,
+ Value invokeInstanceMethod(EvaluationContext evaluationContext,
+ ObjectReference objRef,
+ Method method,
+ List args,
int invocationOptions) throws EvaluateException;
ReferenceType findClass(EvaluationContext evaluationContext,
@@ -112,4 +113,8 @@ public interface DebugProcess {
*/
@NotNull
GlobalSearchScope getSearchScope();
+
+ void printToConsole(String text);
+
+ ProcessHandler getProcessHandler();
}
diff --git a/java/debugger/openapi/src/com/intellij/debugger/engine/JSR45PositionManager.java b/java/debugger/openapi/src/com/intellij/debugger/engine/JSR45PositionManager.java
index f188409f607d..d33e9ade7e08 100644
--- a/java/debugger/openapi/src/com/intellij/debugger/engine/JSR45PositionManager.java
+++ b/java/debugger/openapi/src/com/intellij/debugger/engine/JSR45PositionManager.java
@@ -20,7 +20,6 @@ import com.intellij.debugger.NoDataException;
import com.intellij.debugger.PositionManager;
import com.intellij.debugger.SourcePosition;
import com.intellij.debugger.requests.ClassPrepareRequestor;
-import com.intellij.execution.process.ProcessOutputTypes;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileTypes.FileType;
@@ -167,11 +166,11 @@ public abstract class JSR45PositionManager<Scope> implements PositionManager {
}
catch(AbsentInformationException ignored) {
}
- catch(ClassNotPreparedException ignored) {
+ catch(ClassNotPreparedException ignored) {
}
catch (InternalError ignored) {
- myDebugProcess.getExecutionResult().getProcessHandler().notifyTextAvailable(
- DebuggerBundle.message("internal.error.locations.of.line", type.name()), ProcessOutputTypes.SYSTEM);
+ myDebugProcess.printToConsole(
+ DebuggerBundle.message("internal.error.locations.of.line", type.name()));
}
return null;
}
diff --git a/java/execution/impl/src/com/intellij/execution/actions/JavaRerunFailedTestsAction.java b/java/execution/impl/src/com/intellij/execution/actions/JavaRerunFailedTestsAction.java
index 76e7175b87ff..3be2960bfcf7 100644
--- a/java/execution/impl/src/com/intellij/execution/actions/JavaRerunFailedTestsAction.java
+++ b/java/execution/impl/src/com/intellij/execution/actions/JavaRerunFailedTestsAction.java
@@ -22,6 +22,7 @@ package com.intellij.execution.actions;
import com.intellij.execution.testframework.Filter;
import com.intellij.execution.testframework.JavaAwareFilter;
+import com.intellij.execution.testframework.TestConsoleProperties;
import com.intellij.execution.testframework.actions.AbstractRerunFailedTestsAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.ComponentContainer;
@@ -29,9 +30,10 @@ import com.intellij.psi.search.GlobalSearchScope;
import org.jetbrains.annotations.NotNull;
public class JavaRerunFailedTestsAction extends AbstractRerunFailedTestsAction {
-
- protected JavaRerunFailedTestsAction(@NotNull ComponentContainer componentContainer) {
+ public JavaRerunFailedTestsAction(@NotNull ComponentContainer componentContainer, @NotNull TestConsoleProperties consoleProperties) {
super(componentContainer);
+
+ init(consoleProperties);
}
@NotNull
@@ -39,5 +41,4 @@ public class JavaRerunFailedTestsAction extends AbstractRerunFailedTestsAction {
protected Filter getFilter(Project project, GlobalSearchScope searchScope) {
return super.getFilter(project, searchScope).and(JavaAwareFilter.METHOD(project, searchScope));
}
-
}
diff --git a/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java b/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java
index 578d5fbba6ea..b736d9f0b127 100644
--- a/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java
+++ b/java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java
@@ -21,20 +21,16 @@ import com.intellij.execution.configuration.EnvironmentVariablesComponent;
import com.intellij.execution.configurations.*;
import com.intellij.execution.filters.TextConsoleBuilderFactory;
import com.intellij.execution.junit.RefactoringListeners;
-import com.intellij.execution.process.KillableColoredProcessHandler;
-import com.intellij.execution.process.OSProcessHandler;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.util.JavaParametersUtil;
import com.intellij.execution.util.ProgramParametersUtil;
import com.intellij.openapi.components.PathMacroManager;
-import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.options.SettingsEditor;
import com.intellij.openapi.options.SettingsEditorGroup;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.DefaultJDOMExternalizer;
import com.intellij.openapi.util.InvalidDataException;
-import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
@@ -81,7 +77,7 @@ public class ApplicationConfiguration extends ModuleBasedConfiguration<JavaRunCo
@Override
public RunProfileState getState(@NotNull final Executor executor, @NotNull final ExecutionEnvironment env) throws ExecutionException {
- final JavaCommandLineState state = new JavaApplicationCommandLineState(this, env);
+ final JavaCommandLineState state = new JavaApplicationCommandLineState<ApplicationConfiguration>(this, env);
JavaRunConfigurationModule module = getConfigurationModule();
state.setConsoleBuilder(TextConsoleBuilderFactory.getInstance().createBuilder(getProject(), module.getSearchScope()));
return state;
@@ -253,14 +249,9 @@ public class ApplicationConfiguration extends ModuleBasedConfiguration<JavaRunCo
PathMacroManager.getInstance(getProject()).collapsePathsRecursively(element);
}
- public static class JavaApplicationCommandLineState extends JavaCommandLineState {
-
- private final ApplicationConfiguration myConfiguration;
-
- public JavaApplicationCommandLineState(@NotNull final ApplicationConfiguration configuration,
- final ExecutionEnvironment environment) {
- super(environment);
- myConfiguration = configuration;
+ public static class JavaApplicationCommandLineState<T extends ApplicationConfiguration> extends BaseJavaApplicationCommandLineState<T> {
+ public JavaApplicationCommandLineState(@NotNull final T configuration, final ExecutionEnvironment environment) {
+ super(environment, configuration);
}
@Override
@@ -269,37 +260,14 @@ public class ApplicationConfiguration extends ModuleBasedConfiguration<JavaRunCo
final JavaRunConfigurationModule module = myConfiguration.getConfigurationModule();
final int classPathType = JavaParametersUtil.getClasspathType(module,
- myConfiguration.MAIN_CLASS_NAME,
+ myConfiguration.MAIN_CLASS_NAME,
false);
- final String jreHome = myConfiguration.ALTERNATIVE_JRE_PATH_ENABLED ? myConfiguration.ALTERNATIVE_JRE_PATH
- : null;
+ final String jreHome = myConfiguration.ALTERNATIVE_JRE_PATH_ENABLED ? myConfiguration.ALTERNATIVE_JRE_PATH : null;
JavaParametersUtil.configureModule(module, params, classPathType, jreHome);
- JavaParametersUtil.configureConfiguration(params, myConfiguration);
-
params.setMainClass(myConfiguration.MAIN_CLASS_NAME);
- for(RunConfigurationExtension ext: Extensions.getExtensions(RunConfigurationExtension.EP_NAME)) {
- ext.updateJavaParameters(myConfiguration, params, getRunnerSettings());
- }
+ setupJavaParameters(params);
return params;
}
-
- @NotNull
- @Override
- protected OSProcessHandler startProcess() throws ExecutionException {
- OSProcessHandler handler = SystemInfo.isWindows ? super.startProcess() : KillableColoredProcessHandler.create(createCommandLine());
- RunnerSettings runnerSettings = getRunnerSettings();
- JavaRunConfigurationExtensionManager.getInstance().attachExtensionsToProcess(myConfiguration, handler, runnerSettings);
- return handler;
- }
-
- @Override
- protected boolean ansiColoringEnabled() {
- return true;
- }
-
- protected ApplicationConfiguration getConfiguration() {
- return myConfiguration;
- }
}
}
diff --git a/java/execution/impl/src/com/intellij/execution/application/BaseJavaApplicationCommandLineState.java b/java/execution/impl/src/com/intellij/execution/application/BaseJavaApplicationCommandLineState.java
new file mode 100644
index 000000000000..d9caa6ebc149
--- /dev/null
+++ b/java/execution/impl/src/com/intellij/execution/application/BaseJavaApplicationCommandLineState.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.execution.application;
+
+import com.intellij.execution.CommonJavaRunConfigurationParameters;
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.JavaRunConfigurationExtensionManager;
+import com.intellij.execution.RunConfigurationExtension;
+import com.intellij.execution.configurations.JavaCommandLineState;
+import com.intellij.execution.configurations.JavaParameters;
+import com.intellij.execution.configurations.RunConfigurationBase;
+import com.intellij.execution.configurations.RunnerSettings;
+import com.intellij.execution.process.KillableColoredProcessHandler;
+import com.intellij.execution.process.OSProcessHandler;
+import com.intellij.execution.runners.ExecutionEnvironment;
+import com.intellij.execution.util.JavaParametersUtil;
+import com.intellij.openapi.extensions.Extensions;
+import com.intellij.openapi.util.SystemInfo;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author nik
+ */
+public abstract class BaseJavaApplicationCommandLineState<T extends RunConfigurationBase&CommonJavaRunConfigurationParameters> extends JavaCommandLineState {
+ protected final T myConfiguration;
+
+ public BaseJavaApplicationCommandLineState(ExecutionEnvironment environment, @NotNull final T configuration) {
+ super(environment);
+ myConfiguration = configuration;
+ }
+
+ protected void setupJavaParameters(JavaParameters params) throws ExecutionException {
+ JavaParametersUtil.configureConfiguration(params, myConfiguration);
+
+ for(RunConfigurationExtension ext: Extensions.getExtensions(RunConfigurationExtension.EP_NAME)) {
+ ext.updateJavaParameters(getConfiguration(), params, getRunnerSettings());
+ }
+ }
+
+ @NotNull
+ @Override
+ protected OSProcessHandler startProcess() throws ExecutionException {
+ OSProcessHandler handler = SystemInfo.isWindows ? super.startProcess() : KillableColoredProcessHandler.create(createCommandLine());
+ RunnerSettings runnerSettings = getRunnerSettings();
+ JavaRunConfigurationExtensionManager.getInstance().attachExtensionsToProcess(getConfiguration(), handler, runnerSettings);
+ return handler;
+ }
+
+ @Override
+ protected boolean ansiColoringEnabled() {
+ return true;
+ }
+
+ protected T getConfiguration() {
+ return myConfiguration;
+ }
+}
diff --git a/java/execution/impl/src/com/intellij/execution/impl/DefaultJavaProgramRunner.java b/java/execution/impl/src/com/intellij/execution/impl/DefaultJavaProgramRunner.java
index 626a47509144..0b8f32964d59 100644
--- a/java/execution/impl/src/com/intellij/execution/impl/DefaultJavaProgramRunner.java
+++ b/java/execution/impl/src/com/intellij/execution/impl/DefaultJavaProgramRunner.java
@@ -34,7 +34,6 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.Disposer;
import com.intellij.unscramble.AnalyzeStacktraceUtil;
import com.intellij.unscramble.ThreadDumpConsoleFactory;
import com.intellij.unscramble.ThreadDumpParser;
@@ -97,7 +96,6 @@ public class DefaultJavaProgramRunner extends JavaPatchableProgramRunner {
onProcessStarted(env.getRunnerSettings(), executionResult);
final RunContentBuilder contentBuilder = new RunContentBuilder(executionResult, env);
- Disposer.register(env.getProject(), contentBuilder);
if (shouldAddDefaultActions) {
addDefaultActions(contentBuilder);
}
@@ -116,7 +114,7 @@ public class DefaultJavaProgramRunner extends JavaPatchableProgramRunner {
final ExecutionResult executionResult = contentBuilder.getExecutionResult();
final ExecutionConsole executionConsole = executionResult.getExecutionConsole();
final JComponent consoleComponent = executionConsole != null ? executionConsole.getComponent() : null;
- final ControlBreakAction controlBreakAction = new ControlBreakAction(contentBuilder.getProcessHandler());
+ final ControlBreakAction controlBreakAction = new ControlBreakAction(executionResult.getProcessHandler());
if (consoleComponent != null) {
controlBreakAction.registerCustomShortcutSet(controlBreakAction.getShortcutSet(), consoleComponent);
final ProcessHandler processHandler = executionResult.getProcessHandler();
@@ -130,7 +128,7 @@ public class DefaultJavaProgramRunner extends JavaPatchableProgramRunner {
});
}
contentBuilder.addAction(controlBreakAction);
- contentBuilder.addAction(new SoftExitAction(contentBuilder.getProcessHandler()));
+ contentBuilder.addAction(new SoftExitAction(executionResult.getProcessHandler()));
}
@@ -143,7 +141,7 @@ public class DefaultJavaProgramRunner extends JavaPatchableProgramRunner {
}
@Override
- public void update(final AnActionEvent event) {
+ public void update(@NotNull final AnActionEvent event) {
final Presentation presentation = event.getPresentation();
if (!isVisible()) {
presentation.setVisible(false);
@@ -172,7 +170,7 @@ public class DefaultJavaProgramRunner extends JavaPatchableProgramRunner {
}
@Override
- public void actionPerformed(final AnActionEvent e) {
+ public void actionPerformed(@NotNull final AnActionEvent e) {
ProcessProxy proxy = ProcessProxyFactory.getInstance().getAttachedProxy(myProcessHandler);
if (proxy != null) {
final WiseDumpThreadsListener wiseListener = Boolean.TRUE.equals(Boolean.getBoolean(ourWiseThreadDumpProperty)) ?
@@ -254,7 +252,7 @@ public class DefaultJavaProgramRunner extends JavaPatchableProgramRunner {
}
@Override
- public void actionPerformed(final AnActionEvent e) {
+ public void actionPerformed(@NotNull final AnActionEvent e) {
ProcessProxy proxy = ProcessProxyFactory.getInstance().getAttachedProxy(myProcessHandler);
if (proxy != null) {
proxy.sendStop();
diff --git a/java/execution/impl/src/com/intellij/execution/jar/JarApplicationCommandLineState.java b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationCommandLineState.java
new file mode 100644
index 000000000000..c93ab85d4cec
--- /dev/null
+++ b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationCommandLineState.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.execution.jar;
+
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.application.BaseJavaApplicationCommandLineState;
+import com.intellij.execution.configurations.JavaParameters;
+import com.intellij.execution.runners.ExecutionEnvironment;
+import com.intellij.execution.util.JavaParametersUtil;
+import com.intellij.openapi.util.io.FileUtil;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author nik
+ */
+public class JarApplicationCommandLineState extends BaseJavaApplicationCommandLineState<JarApplicationConfiguration> {
+ public JarApplicationCommandLineState(@NotNull final JarApplicationConfiguration configuration, final ExecutionEnvironment environment) {
+ super(environment, configuration);
+ }
+
+ @Override
+ protected JavaParameters createJavaParameters() throws ExecutionException {
+ final JavaParameters params = new JavaParameters();
+ final String jreHome = myConfiguration.isAlternativeJrePathEnabled() ? myConfiguration.getAlternativeJrePath() : null;
+ params.setJdk(JavaParametersUtil.createProjectJdk(myConfiguration.getProject(), jreHome));
+ setupJavaParameters(params);
+ params.setJarPath(FileUtil.toSystemDependentName(myConfiguration.getJarPath()));
+ return params;
+ }
+}
diff --git a/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurable.form b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurable.form
new file mode 100644
index 000000000000..db191dde6fa3
--- /dev/null
+++ b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurable.form
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.execution.jar.JarApplicationConfigurable">
+ <grid id="27dc6" binding="myWholePanel" layout-manager="GridLayoutManager" row-count="5" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+ <margin top="0" left="0" bottom="0" right="0"/>
+ <constraints>
+ <xy x="20" y="20" width="530" height="400"/>
+ </constraints>
+ <properties/>
+ <border type="none"/>
+ <children>
+ <component id="73391" class="com.intellij.execution.ui.CommonJavaParametersPanel" binding="myCommonProgramParameters">
+ <constraints>
+ <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties/>
+ </component>
+ <vspacer id="9634c">
+ <constraints>
+ <grid row="4" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
+ </constraints>
+ </vspacer>
+ <component id="a09fc" class="com.intellij.execution.ui.AlternativeJREPanel" binding="myAlternativeJREPanel">
+ <constraints>
+ <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties/>
+ </component>
+ <component id="cab16" class="com.intellij.openapi.ui.LabeledComponent" binding="myJarPathComponent" custom-create="true">
+ <constraints>
+ <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <labelLocation value="West"/>
+ <text value="Path to &amp;JAR"/>
+ </properties>
+ </component>
+ <component id="6fe96" class="com.intellij.openapi.ui.LabeledComponent" binding="myModuleComponent">
+ <constraints>
+ <grid row="3" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <componentClass value="com.intellij.application.options.ModulesComboBox"/>
+ <labelLocation value="West"/>
+ <text value="Search sources using m&amp;odule's classpath"/>
+ </properties>
+ </component>
+ </children>
+ </grid>
+</form>
diff --git a/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurable.java b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurable.java
new file mode 100644
index 000000000000..03758cd031cb
--- /dev/null
+++ b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurable.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.execution.jar;
+
+import com.intellij.application.options.ModulesComboBox;
+import com.intellij.execution.ui.AlternativeJREPanel;
+import com.intellij.execution.ui.CommonJavaParametersPanel;
+import com.intellij.openapi.fileChooser.FileChooserDescriptor;
+import com.intellij.openapi.options.ConfigurationException;
+import com.intellij.openapi.options.SettingsEditor;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.LabeledComponent;
+import com.intellij.openapi.ui.TextFieldWithBrowseButton;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.ui.PanelWithAnchor;
+import com.intellij.util.ui.UIUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+
+public class JarApplicationConfigurable extends SettingsEditor<JarApplicationConfiguration> implements PanelWithAnchor {
+ private CommonJavaParametersPanel myCommonProgramParameters;
+ private LabeledComponent<TextFieldWithBrowseButton> myJarPathComponent;
+ private LabeledComponent<ModulesComboBox> myModuleComponent;
+ private JPanel myWholePanel;
+
+ private AlternativeJREPanel myAlternativeJREPanel;
+ private final Project myProject;
+ private JComponent myAnchor;
+
+ public JarApplicationConfigurable(final Project project) {
+ myProject = project;
+ myAnchor = UIUtil.mergeComponentsWithAnchor(myJarPathComponent, myCommonProgramParameters, myAlternativeJREPanel);
+ ModulesComboBox modulesComboBox = myModuleComponent.getComponent();
+ modulesComboBox.allowEmptySelection("<whole project>");
+ modulesComboBox.fillModules(project);
+ }
+
+ public void applyEditorTo(final JarApplicationConfiguration configuration) throws ConfigurationException {
+ myCommonProgramParameters.applyTo(configuration);
+ configuration.setAlternativeJrePath(myAlternativeJREPanel.getPath());
+ configuration.setAlternativeJrePathEnabled(myAlternativeJREPanel.isPathEnabled());
+ configuration.setJarPath(FileUtil.toSystemIndependentName(myJarPathComponent.getComponent().getText()));
+ configuration.setModule(myModuleComponent.getComponent().getSelectedModule());
+ }
+
+ public void resetEditorFrom(final JarApplicationConfiguration configuration) {
+ myCommonProgramParameters.reset(configuration);
+ myJarPathComponent.getComponent().setText(FileUtil.toSystemDependentName(configuration.getJarPath()));
+ myAlternativeJREPanel.init(configuration.getAlternativeJrePath(), configuration.isAlternativeJrePathEnabled());
+ myModuleComponent.getComponent().setSelectedModule(configuration.getModule());
+ }
+
+ @NotNull
+ public JComponent createEditor() {
+ return myWholePanel;
+ }
+
+ private void createUIComponents() {
+ myJarPathComponent = new LabeledComponent<TextFieldWithBrowseButton>();
+ TextFieldWithBrowseButton textFieldWithBrowseButton = new TextFieldWithBrowseButton();
+ textFieldWithBrowseButton.addBrowseFolderListener("Choose JAR File", null, myProject,
+ new FileChooserDescriptor(false, false, true, true, false, false));
+ myJarPathComponent.setComponent(textFieldWithBrowseButton);
+ }
+
+ @Override
+ public JComponent getAnchor() {
+ return myAnchor;
+ }
+
+ @Override
+ public void setAnchor(@Nullable JComponent anchor) {
+ myAnchor = anchor;
+ myCommonProgramParameters.setAnchor(anchor);
+ myAlternativeJREPanel.setAnchor(anchor);
+ myJarPathComponent.setAnchor(anchor);
+ }
+}
diff --git a/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfiguration.java b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfiguration.java
new file mode 100644
index 000000000000..c76b5873389a
--- /dev/null
+++ b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfiguration.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.execution.jar;
+
+import com.intellij.diagnostic.logging.LogConfigurationPanel;
+import com.intellij.execution.*;
+import com.intellij.execution.configuration.EnvironmentVariablesComponent;
+import com.intellij.execution.configurations.*;
+import com.intellij.execution.runners.ExecutionEnvironment;
+import com.intellij.execution.util.JavaParametersUtil;
+import com.intellij.execution.util.ProgramParametersUtil;
+import com.intellij.openapi.components.PathMacroManager;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.options.SettingsEditor;
+import com.intellij.openapi.options.SettingsEditorGroup;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.WriteExternalException;
+import com.intellij.util.xmlb.SkipDefaultValuesSerializationFilters;
+import com.intellij.util.xmlb.XmlSerializer;
+import org.jdom.Element;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.File;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * @author nik
+ */
+public class JarApplicationConfiguration extends LocatableConfigurationBase implements CommonJavaRunConfigurationParameters, SearchScopeProvidingRunProfile {
+ private static final SkipDefaultValuesSerializationFilters SERIALIZATION_FILTERS = new SkipDefaultValuesSerializationFilters();
+ private JarApplicationConfigurationBean myBean = new JarApplicationConfigurationBean();
+ private Map<String, String> myEnvs = new LinkedHashMap<String, String>();
+ private JavaRunConfigurationModule myConfigurationModule;
+
+ public JarApplicationConfiguration(Project project, ConfigurationFactory factory, String name) {
+ super(project, factory, name);
+ myConfigurationModule = new JavaRunConfigurationModule(project, true);
+ }
+
+ @NotNull
+ @Override
+ public SettingsEditor<? extends RunConfiguration> getConfigurationEditor() {
+ SettingsEditorGroup<JarApplicationConfiguration> group = new SettingsEditorGroup<JarApplicationConfiguration>();
+ group.addEditor(ExecutionBundle.message("run.configuration.configuration.tab.title"), new JarApplicationConfigurable(getProject()));
+ JavaRunConfigurationExtensionManager.getInstance().appendEditors(this, group);
+ group.addEditor(ExecutionBundle.message("logs.tab.title"), new LogConfigurationPanel<JarApplicationConfiguration>());
+ return group;
+ }
+
+ @Override
+ public void readExternal(Element element) throws InvalidDataException {
+ PathMacroManager.getInstance(getProject()).expandPaths(element);
+ super.readExternal(element);
+ JavaRunConfigurationExtensionManager.getInstance().readExternal(this, element);
+ XmlSerializer.deserializeInto(myBean, element);
+ EnvironmentVariablesComponent.readExternal(element, getEnvs());
+ myConfigurationModule.readExternal(element);
+ }
+
+ public void setModule(Module module) {
+ myConfigurationModule.setModule(module);
+ }
+
+ public Module getModule() {
+ return myConfigurationModule.getModule();
+ }
+
+ @Override
+ public void writeExternal(Element element) throws WriteExternalException {
+ super.writeExternal(element);
+ JavaRunConfigurationExtensionManager.getInstance().writeExternal(this, element);
+ XmlSerializer.serializeInto(myBean, element, SERIALIZATION_FILTERS);
+ EnvironmentVariablesComponent.writeExternal(element, getEnvs());
+ PathMacroManager.getInstance(getProject()).collapsePathsRecursively(element);
+ if (myConfigurationModule.getModule() != null) {
+ myConfigurationModule.writeExternal(element);
+ }
+ }
+
+ @Override
+ public void checkConfiguration() throws RuntimeConfigurationException {
+ JavaParametersUtil.checkAlternativeJRE(this);
+ ProgramParametersUtil.checkWorkingDirectoryExist(this, getProject(), null);
+ File jarFile = new File(getJarPath());
+ if (!jarFile.exists()) {
+ throw new RuntimeConfigurationWarning("JAR file '" + jarFile.getAbsolutePath() + "' doesn't exist");
+ }
+ JavaRunConfigurationExtensionManager.checkConfigurationIsValid(this);
+ }
+
+ @NotNull
+ @Override
+ public Module[] getModules() {
+ Module module = myConfigurationModule.getModule();
+ return module != null ? new Module[] {module}: Module.EMPTY_ARRAY;
+ }
+
+ @Nullable
+ @Override
+ public RunProfileState getState(@NotNull Executor executor, @NotNull ExecutionEnvironment environment) throws ExecutionException {
+ return new JarApplicationCommandLineState(this, environment);
+ }
+
+ public String getJarPath() {
+ return myBean.JAR_PATH;
+ }
+
+ public void setJarPath(String jarPath) {
+ myBean.JAR_PATH = jarPath;
+ }
+
+ @Override
+ public void setVMParameters(String value) {
+ myBean.VM_PARAMETERS = value;
+ }
+
+ @Override
+ public String getVMParameters() {
+ return myBean.VM_PARAMETERS;
+ }
+
+ @Override
+ public boolean isAlternativeJrePathEnabled() {
+ return myBean.ALTERNATIVE_JRE_PATH_ENABLED;
+ }
+
+ @Override
+ public void setAlternativeJrePathEnabled(boolean enabled) {
+ myBean.ALTERNATIVE_JRE_PATH_ENABLED = enabled;
+ }
+
+ @Override
+ public String getAlternativeJrePath() {
+ return myBean.ALTERNATIVE_JRE_PATH;
+ }
+
+ @Override
+ public void setAlternativeJrePath(String path) {
+ myBean.ALTERNATIVE_JRE_PATH = path;
+ }
+
+ @Nullable
+ @Override
+ public String getRunClass() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public String getPackage() {
+ return null;
+ }
+
+ @Override
+ public void setProgramParameters(@Nullable String value) {
+ myBean.PROGRAM_PARAMETERS = value;
+ }
+
+ @Nullable
+ @Override
+ public String getProgramParameters() {
+ return myBean.PROGRAM_PARAMETERS;
+ }
+
+ @Override
+ public void setWorkingDirectory(@Nullable String value) {
+ myBean.WORKING_DIRECTORY = value;
+ }
+
+ @Nullable
+ @Override
+ public String getWorkingDirectory() {
+ return myBean.WORKING_DIRECTORY;
+ }
+
+ @Override
+ public void setEnvs(@NotNull Map<String, String> envs) {
+ myEnvs.clear();
+ myEnvs.putAll(envs);
+ }
+
+ @NotNull
+ @Override
+ public Map<String, String> getEnvs() {
+ return myEnvs;
+ }
+
+ @Override
+ public void setPassParentEnvs(boolean passParentEnvs) {
+ myBean.PASS_PARENT_ENVS = passParentEnvs;
+ }
+
+ @Override
+ public boolean isPassParentEnvs() {
+ return myBean.PASS_PARENT_ENVS;
+ }
+
+ private static class JarApplicationConfigurationBean {
+ public String JAR_PATH = "";
+ public String VM_PARAMETERS = "";
+ public String PROGRAM_PARAMETERS = "";
+ public String WORKING_DIRECTORY = "";
+ public boolean ALTERNATIVE_JRE_PATH_ENABLED;
+ public String ALTERNATIVE_JRE_PATH = "";
+ public boolean PASS_PARENT_ENVS = true;
+ }
+}
diff --git a/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurationProducer.java b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurationProducer.java
new file mode 100644
index 000000000000..b2b9f8fef81c
--- /dev/null
+++ b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurationProducer.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.execution.jar;
+
+import com.intellij.execution.Location;
+import com.intellij.execution.actions.ConfigurationContext;
+import com.intellij.execution.actions.RunConfigurationProducer;
+import com.intellij.openapi.util.Ref;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.io.FileUtilRt;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiElement;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author nik
+ */
+public class JarApplicationConfigurationProducer extends RunConfigurationProducer<JarApplicationConfiguration> {
+ public JarApplicationConfigurationProducer() {
+ super(JarApplicationConfigurationType.getInstance());
+ }
+
+ @Override
+ protected boolean setupConfigurationFromContext(JarApplicationConfiguration configuration,
+ ConfigurationContext context,
+ Ref<PsiElement> sourceElement) {
+ VirtualFile file = getJarFileFromContext(context);
+ if (file != null) {
+ configuration.setName(file.getName());
+ configuration.setJarPath(file.getPath());
+ return true;
+ }
+ return false;
+ }
+
+ @Nullable
+ private static VirtualFile getJarFileFromContext(ConfigurationContext context) {
+ Location location = context.getLocation();
+ if (location == null) return null;
+
+ VirtualFile file = location.getVirtualFile();
+ return file != null && FileUtilRt.extensionEquals(file.getName(), "jar") ? file : null;
+ }
+
+ @Override
+ public boolean isConfigurationFromContext(JarApplicationConfiguration configuration, ConfigurationContext context) {
+ VirtualFile file = getJarFileFromContext(context);
+ return file != null && FileUtil.pathsEqual(file.getPath(), configuration.getJarPath());
+ }
+}
diff --git a/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurationType.java b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurationType.java
new file mode 100644
index 000000000000..8c7fdebc8c52
--- /dev/null
+++ b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationConfigurationType.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.execution.jar;
+
+import com.intellij.execution.ExecutionBundle;
+import com.intellij.execution.configuration.ConfigurationFactoryEx;
+import com.intellij.execution.configurations.ConfigurationType;
+import com.intellij.execution.configurations.ConfigurationTypeBase;
+import com.intellij.execution.configurations.ConfigurationTypeUtil;
+import com.intellij.execution.configurations.RunConfiguration;
+import com.intellij.icons.AllIcons;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.text.StringUtil;
+import org.jetbrains.annotations.NotNull;
+
+public class JarApplicationConfigurationType extends ConfigurationTypeBase implements ConfigurationType {
+ @NotNull
+ public static JarApplicationConfigurationType getInstance() {
+ return ConfigurationTypeUtil.findConfigurationType(JarApplicationConfigurationType.class);
+ }
+
+ public JarApplicationConfigurationType() {
+ super("JarApplication", ExecutionBundle.message("jar.application.configuration.name"),
+ ExecutionBundle.message("jar.application.configuration.description"), AllIcons.FileTypes.Archive);
+ addFactory(new ConfigurationFactoryEx(this) {
+ @Override
+ public void onNewConfigurationCreated(@NotNull RunConfiguration configuration) {
+ JarApplicationConfiguration jarApplicationConfiguration = (JarApplicationConfiguration)configuration;
+ if (StringUtil.isEmpty(jarApplicationConfiguration.getWorkingDirectory())) {
+ String baseDir = FileUtil.toSystemIndependentName(StringUtil.notNullize(configuration.getProject().getBasePath()));
+ jarApplicationConfiguration.setWorkingDirectory(baseDir);
+ }
+ }
+
+ public RunConfiguration createTemplateConfiguration(Project project) {
+ return new JarApplicationConfiguration(project, this, "");
+ }
+ });
+ }
+}
diff --git a/java/execution/impl/src/com/intellij/execution/jar/JarApplicationDebuggerRunner.java b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationDebuggerRunner.java
new file mode 100644
index 000000000000..dc5bfbfb6129
--- /dev/null
+++ b/java/execution/impl/src/com/intellij/execution/jar/JarApplicationDebuggerRunner.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.execution.jar;
+
+import com.intellij.debugger.impl.GenericDebuggerRunner;
+import com.intellij.execution.configurations.RunProfile;
+import com.intellij.execution.executors.DefaultDebugExecutor;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author nik
+ */
+public class JarApplicationDebuggerRunner extends GenericDebuggerRunner {
+ @Override
+ public boolean canRun(@NotNull String executorId, @NotNull RunProfile profile) {
+ return DefaultDebugExecutor.EXECUTOR_ID.equals(executorId) && profile instanceof JarApplicationConfiguration;
+ }
+
+ @NotNull
+ @Override
+ public String getRunnerId() {
+ return "JarDebug";
+ }
+}
diff --git a/java/execution/impl/src/com/intellij/execution/junit/InheritorChooser.java b/java/execution/impl/src/com/intellij/execution/junit/InheritorChooser.java
index d318ad47bb70..fc0e65f9742b 100644
--- a/java/execution/impl/src/com/intellij/execution/junit/InheritorChooser.java
+++ b/java/execution/impl/src/com/intellij/execution/junit/InheritorChooser.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,6 +27,7 @@ import com.intellij.openapi.fileEditor.TextEditor;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.Condition;
+import com.intellij.openapi.util.Conditions;
import com.intellij.psi.*;
import com.intellij.psi.search.searches.ClassInheritorsSearch;
import com.intellij.psi.util.PsiClassUtil;
@@ -59,7 +60,7 @@ public class InheritorChooser {
final Runnable performRunnable,
final PsiMethod psiMethod,
final PsiClass containingClass) {
- return runMethodInAbstractClass(context, performRunnable, psiMethod, containingClass, Condition.TRUE);
+ return runMethodInAbstractClass(context, performRunnable, psiMethod, containingClass, Conditions.<PsiClass>alwaysTrue());
}
public boolean runMethodInAbstractClass(final ConfigurationContext context,
@@ -114,6 +115,7 @@ public class InheritorChooser {
}
}
}
+ final int numberOfInheritors = classes.size();
final PsiClassListCellRenderer renderer = new PsiClassListCellRenderer() {
@Override
protected boolean customizeNonPsiElementLeftRenderer(ColoredListCellRenderer renderer,
@@ -123,7 +125,7 @@ public class InheritorChooser {
boolean selected,
boolean hasFocus) {
if (value == null) {
- renderer.append("All");
+ renderer.append("All (" + numberOfInheritors + ")");
return true;
}
return super.customizeNonPsiElementLeftRenderer(renderer, list, value, index, selected, hasFocus);
diff --git a/java/execution/impl/src/com/intellij/execution/runners/ProcessProxyFactoryImpl.java b/java/execution/impl/src/com/intellij/execution/runners/ProcessProxyFactoryImpl.java
index 6af48770e78d..4b20e2189202 100644
--- a/java/execution/impl/src/com/intellij/execution/runners/ProcessProxyFactoryImpl.java
+++ b/java/execution/impl/src/com/intellij/execution/runners/ProcessProxyFactoryImpl.java
@@ -30,15 +30,16 @@ import java.io.File;
public class ProcessProxyFactoryImpl extends ProcessProxyFactory {
public ProcessProxy createCommandLineProxy(final JavaCommandLine javaCmdLine) throws ExecutionException {
ProcessProxyImpl proxy = null;
- if (ProcessProxyImpl.useLauncher()) {
+ final JavaParameters javaParameters = javaCmdLine.getJavaParameters();
+ String mainClass = javaParameters.getMainClass();
+ if (ProcessProxyImpl.useLauncher() && mainClass != null) {
try {
proxy = new ProcessProxyImpl();
- final JavaParameters javaParameters = javaCmdLine.getJavaParameters();
JavaSdkUtil.addRtJar(javaParameters.getClassPath());
final ParametersList vmParametersList = javaParameters.getVMParametersList();
vmParametersList.defineProperty(ProcessProxyImpl.PROPERTY_PORT_NUMBER, String.valueOf(proxy.getPortNumber()));
vmParametersList.defineProperty(ProcessProxyImpl.PROPERTY_BINPATH, PathManager.getBinPath());
- javaParameters.getProgramParametersList().prepend(javaParameters.getMainClass());
+ javaParameters.getProgramParametersList().prepend(mainClass);
javaParameters.setMainClass(ProcessProxyImpl.LAUNCH_MAIN_CLASS);
}
catch (ProcessProxyImpl.NoMoreSocketsException e) {
diff --git a/java/execution/impl/src/com/intellij/execution/util/JavaParametersUtil.java b/java/execution/impl/src/com/intellij/execution/util/JavaParametersUtil.java
index 18aead7fe7f1..4d948dae8a2d 100644
--- a/java/execution/impl/src/com/intellij/execution/util/JavaParametersUtil.java
+++ b/java/execution/impl/src/com/intellij/execution/util/JavaParametersUtil.java
@@ -27,7 +27,6 @@ import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.JavaSdk;
-import com.intellij.openapi.projectRoots.JavaSdkType;
import com.intellij.openapi.projectRoots.ProjectJdkTable;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.ex.PathUtilEx;
@@ -118,7 +117,7 @@ public class JavaParametersUtil {
return jreHome == null ? JavaParameters.getModuleJdk(module) : createAlternativeJdk(jreHome);
}
- private static Sdk createProjectJdk(final Project project, final String jreHome) throws CantRunException {
+ public static Sdk createProjectJdk(final Project project, final String jreHome) throws CantRunException {
return jreHome == null ? createProjectJdk(project) : createAlternativeJdk(jreHome);
}
diff --git a/java/execution/openapi/src/com/intellij/execution/configurations/CommandLineBuilder.java b/java/execution/openapi/src/com/intellij/execution/configurations/CommandLineBuilder.java
index ac081d04b5c7..8ae0d9bae3e3 100644
--- a/java/execution/openapi/src/com/intellij/execution/configurations/CommandLineBuilder.java
+++ b/java/execution/openapi/src/com/intellij/execution/configurations/CommandLineBuilder.java
@@ -79,7 +79,7 @@ public class CommandLineBuilder {
if (exePath == null) {
throw new CantRunException(ExecutionBundle.message("run.configuration.cannot.find.vm.executable"));
}
- if (javaParameters.getMainClass() == null) {
+ if (javaParameters.getMainClass() == null && javaParameters.getJarPath() == null) {
throw new CantRunException(ExecutionBundle.message("main.class.is.not.specified.error.message"));
}
diff --git a/java/idea-ui/src/com/intellij/facet/impl/ui/libraries/LibraryOptionsPanel.form b/java/idea-ui/src/com/intellij/facet/impl/ui/libraries/LibraryOptionsPanel.form
index a738a96aa50e..9e5dd85f6936 100644
--- a/java/idea-ui/src/com/intellij/facet/impl/ui/libraries/LibraryOptionsPanel.form
+++ b/java/idea-ui/src/com/intellij/facet/impl/ui/libraries/LibraryOptionsPanel.form
@@ -139,7 +139,7 @@
<componentStyle value="SMALL"/>
<enabled value="true"/>
<fontColor value="BRIGHTER"/>
- <text value="&lt;html&gt;{} jars will be downloaded into &lt;b&gt;lib&lt;/b&gt; directory&lt;br&gt; Project level library &lt;b&gt;spring&lt;/b&gt; will be created&lt;/html&gt;"/>
+ <text value="&lt;html&gt;{} JARs will be downloaded into &lt;b&gt;lib&lt;/b&gt; directory&lt;br&gt; Project level library &lt;b&gt;spring&lt;/b&gt; will be created&lt;/html&gt;"/>
</properties>
</component>
<component id="84326" class="javax.swing.JLabel" binding="myHiddenLabel">
diff --git a/java/idea-ui/src/com/intellij/facet/impl/ui/libraries/LibraryOptionsPanel.java b/java/idea-ui/src/com/intellij/facet/impl/ui/libraries/LibraryOptionsPanel.java
index 3bb96adb1141..a890bdad527d 100644
--- a/java/idea-ui/src/com/intellij/facet/impl/ui/libraries/LibraryOptionsPanel.java
+++ b/java/idea-ui/src/com/intellij/facet/impl/ui/libraries/LibraryOptionsPanel.java
@@ -490,7 +490,7 @@ public class LibraryOptionsPanel implements Disposable {
else {
path = PathUtil.getFileName(downloadPath);
}
- return MessageFormat.format("{0} {0, choice, 1#jar|2#jars} will be downloaded into <b>{1}</b> directory<br>" +
+ return MessageFormat.format("{0} {0, choice, 1#JAR|2#JARs} will be downloaded into <b>{1}</b> directory<br>" +
"{2} library <b>{3}</b> will be created",
downloadSettings.getSelectedDownloads().size(),
path,
diff --git a/java/idea-ui/src/com/intellij/ide/RecentProjectsManager.java b/java/idea-ui/src/com/intellij/ide/RecentProjectsManager.java
index 6ac07343357a..e2f93bf16771 100644
--- a/java/idea-ui/src/com/intellij/ide/RecentProjectsManager.java
+++ b/java/idea-ui/src/com/intellij/ide/RecentProjectsManager.java
@@ -16,31 +16,30 @@
package com.intellij.ide;
import com.intellij.ide.impl.ProjectUtil;
-import com.intellij.openapi.components.RoamingType;
-import com.intellij.openapi.components.State;
-import com.intellij.openapi.components.Storage;
-import com.intellij.openapi.components.StoragePathMacros;
+import com.intellij.openapi.components.*;
import com.intellij.openapi.project.Project;
import com.intellij.util.messages.MessageBus;
import org.jetbrains.annotations.NotNull;
@State(
name = "RecentProjectsManager",
- roamingType = RoamingType.DISABLED,
storages = {
- @Storage(
- file = StoragePathMacros.APP_CONFIG + "/other.xml"
- )}
+ @Storage(file = StoragePathMacros.APP_CONFIG + "/other.xml", roamingType = RoamingType.DISABLED),
+ @Storage(file = StoragePathMacros.APP_CONFIG + "/recentProjects.xml", roamingType = RoamingType.DISABLED)
+ },
+ storageChooser = LastStorageChooserForWrite.class
)
public class RecentProjectsManager extends RecentProjectsManagerBase {
public RecentProjectsManager(MessageBus messageBus) {
super(messageBus);
}
+ @Override
protected String getProjectPath(@NotNull Project project) {
return project.getPresentableUrl();
}
+ @Override
protected void doOpenProject(@NotNull String projectPath, Project projectToClose, boolean forceOpenInNewFrame) {
ProjectUtil.openProject(projectPath, projectToClose, forceOpenInNewFrame);
}
diff --git a/java/idea-ui/src/com/intellij/ide/actions/ImportModuleAction.java b/java/idea-ui/src/com/intellij/ide/actions/ImportModuleAction.java
index 3d497b829d50..3f087a998304 100644
--- a/java/idea-ui/src/com/intellij/ide/actions/ImportModuleAction.java
+++ b/java/idea-ui/src/com/intellij/ide/actions/ImportModuleAction.java
@@ -116,7 +116,7 @@ public class ImportModuleAction extends AnAction {
if (lastLocation != null) {
toSelect = LocalFileSystem.getInstance().refreshAndFindFileByPath(lastLocation);
}
- VirtualFile[] files = chooser.choose(toSelect, project);
+ VirtualFile[] files = chooser.choose(project, toSelect);
if (files.length == 0) {
return null;
}
diff --git a/java/idea-ui/src/com/intellij/ide/palette/impl/PaletteManager.java b/java/idea-ui/src/com/intellij/ide/palette/impl/PaletteManager.java
deleted file mode 100644
index 1ad6a1cd858d..000000000000
--- a/java/idea-ui/src/com/intellij/ide/palette/impl/PaletteManager.java
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Copyright 2000-2014 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.intellij.ide.palette.impl;
-
-import com.intellij.icons.AllIcons;
-import com.intellij.ide.IdeBundle;
-import com.intellij.ide.palette.PaletteDragEventListener;
-import com.intellij.ide.palette.PaletteItem;
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.components.ProjectComponent;
-import com.intellij.openapi.fileEditor.FileEditorManager;
-import com.intellij.openapi.fileEditor.FileEditorManagerEvent;
-import com.intellij.openapi.fileEditor.FileEditorManagerListener;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.startup.StartupManager;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.openapi.wm.ToolWindow;
-import com.intellij.openapi.wm.ToolWindowAnchor;
-import com.intellij.openapi.wm.ToolWindowManager;
-import com.intellij.util.containers.ContainerUtil;
-import com.intellij.util.ui.update.MergingUpdateQueue;
-import com.intellij.util.ui.update.Update;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import javax.swing.event.ListSelectionEvent;
-import javax.swing.event.ListSelectionListener;
-import java.awt.event.KeyEvent;
-import java.awt.event.KeyListener;
-import java.util.List;
-
-/**
- * @author yole
- */
-public class PaletteManager implements ProjectComponent {
- private final Project myProject;
- private final FileEditorManager myFileEditorManager;
- private PaletteWindow myPaletteWindow;
- private ToolWindow myPaletteToolWindow;
- private final List<KeyListener> myKeyListeners = ContainerUtil.createLockFreeCopyOnWriteList();
- private final List<PaletteDragEventListener> myDragEventListeners = ContainerUtil.createLockFreeCopyOnWriteList();
- private final List<ListSelectionListener> mySelectionListeners = ContainerUtil.createLockFreeCopyOnWriteList();
-
- public PaletteManager(Project project, FileEditorManager fileEditorManager) {
- myProject = project;
- myFileEditorManager = fileEditorManager;
- }
-
- @Override
- public void projectOpened() {
- if (!ApplicationManager.getApplication().isHeadlessEnvironment()) {
- StartupManager.getInstance(myProject).registerPostStartupActivity(new Runnable() {
- @Override
- public void run() {
- myPaletteWindow = new PaletteWindow(myProject);
- myPaletteToolWindow = ToolWindowManager.getInstance(myProject).
- registerToolWindow(IdeBundle.message("toolwindow.palette"),
- myPaletteWindow,
- ToolWindowAnchor.RIGHT,
- myProject,
- true);
- myPaletteToolWindow.setIcon(AllIcons.Toolwindows.ToolWindowPalette);
- setContent();
- final MyFileEditorManagerListener myListener = new MyFileEditorManagerListener();
- myFileEditorManager.addFileEditorManagerListener(myListener, myProject);
- }
- });
- }
- }
-
- @Override
- public void projectClosed() {
- if (myPaletteWindow != null) {
- myPaletteWindow.dispose();
- ToolWindowManager.getInstance(myProject).unregisterToolWindow(IdeBundle.message("toolwindow.palette"));
- myPaletteWindow = null;
- }
- }
-
- @Override
- @NotNull
- public String getComponentName() {
- return "PaletteManager";
- }
-
- @Override
- public void initComponent() {
- }
-
- @Override
- public void disposeComponent() {
- if (myPaletteWindow != null) {
- myPaletteWindow.dispose();
- }
- }
-
- public static PaletteManager getInstance(final Project project) {
- return project.getComponent(PaletteManager.class);
- }
-
- public void clearActiveItem() {
- if (myPaletteWindow != null) {
- myPaletteWindow.clearActiveItem();
- }
- }
-
- @Nullable
- public PaletteItem getActiveItem() {
- if (myPaletteWindow != null) {
- return myPaletteWindow.getActiveItem();
- }
- return null;
- }
-
- @Nullable
- public <T extends PaletteItem> T getActiveItem(Class<T> cls) {
- PaletteItem item = getActiveItem();
- if (item != null && item.getClass().isInstance(item)) {
- //noinspection unchecked
- return (T)item;
- }
- return null;
- }
-
- public void addKeyListener(KeyListener l) {
- myKeyListeners.add(l);
- }
-
- public void removeKeyListener(KeyListener l) {
- myKeyListeners.remove(l);
- }
-
- public void addDragEventListener(PaletteDragEventListener l) {
- myDragEventListeners.add(l);
- }
-
- public void removeDragEventListener(PaletteDragEventListener l) {
- myDragEventListeners.remove(l);
- }
-
- public void addSelectionListener(ListSelectionListener l) {
- mySelectionListeners.add(l);
- }
-
- public void removeSelectionListener(ListSelectionListener l) {
- mySelectionListeners.remove(l);
- }
-
- private final MergingUpdateQueue myQueue = new MergingUpdateQueue("palette", 200, true, null);
-
- private void processFileEditorChange(@Nullable final VirtualFile selectedFile) {
- myQueue.cancelAllUpdates();
- myQueue.queue(new Update("update") {
- @Override
- public void run() {
- if (myPaletteWindow == null) return;
- myPaletteWindow.refreshPaletteIfChanged(selectedFile);
- setContent();
- }
- });
- }
-
- private void setContent() {
- if (myPaletteWindow.getActiveGroupCount() == 0) {
- myPaletteToolWindow.setAvailable(false, null);
- }
- else {
- myPaletteToolWindow.setAvailable(true, null);
- myPaletteToolWindow.show(null);
- }
- }
-
- void notifyKeyEvent(final KeyEvent e) {
- for (KeyListener l : myKeyListeners) {
- if (e.getID() == KeyEvent.KEY_PRESSED) {
- l.keyPressed(e);
- }
- else if (e.getID() == KeyEvent.KEY_RELEASED) {
- l.keyReleased(e);
- }
- else if (e.getID() == KeyEvent.KEY_TYPED) {
- l.keyTyped(e);
- }
- }
- }
-
- void notifyDropActionChanged(int gestureModifiers) {
- for (PaletteDragEventListener l : myDragEventListeners) {
- l.dropActionChanged(gestureModifiers);
- }
- }
-
- void notifySelectionChanged(final ListSelectionEvent event) {
- for (ListSelectionListener l : mySelectionListeners) {
- l.valueChanged(event);
- }
- }
-
- private class MyFileEditorManagerListener implements FileEditorManagerListener {
- @Override
- public void fileOpened(@NotNull FileEditorManager source, @NotNull VirtualFile file) {
- processFileEditorChange(file);
- }
-
- @Override
- public void fileClosed(@NotNull FileEditorManager source, @NotNull VirtualFile file) {
- processFileEditorChange(null);
- }
-
- @Override
- public void selectionChanged(@NotNull FileEditorManagerEvent event) {
- processFileEditorChange(event.getNewFile());
- }
- }
-}
diff --git a/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.form b/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.form
index 7246f2cfb566..61333a8ed4ec 100644
--- a/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.form
+++ b/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.form
@@ -79,7 +79,14 @@
</constraints>
<properties/>
<border type="none"/>
- <children/>
+ <children>
+ <component id="916d9" class="com.intellij.ui.components.JBLabel" binding="myFrameworksLabel">
+ <constraints border-constraint="North"/>
+ <properties>
+ <text value="Additional Libraries and &amp;Frameworks:"/>
+ </properties>
+ </component>
+ </children>
</grid>
</children>
</grid>
diff --git a/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.java b/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.java
index 10e11f74077f..94e551250aed 100644
--- a/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.java
+++ b/java/idea-ui/src/com/intellij/ide/projectWizard/ProjectTypeStep.java
@@ -54,6 +54,7 @@ import com.intellij.ui.CollectionListModel;
import com.intellij.ui.IdeBorderFactory;
import com.intellij.ui.ListSpeedSearch;
import com.intellij.ui.SingleSelectionModel;
+import com.intellij.ui.components.JBLabel;
import com.intellij.ui.components.JBList;
import com.intellij.ui.popup.list.GroupedItemsListRenderer;
import com.intellij.util.Function;
@@ -81,10 +82,6 @@ import java.util.List;
@SuppressWarnings("unchecked")
public class ProjectTypeStep extends ModuleWizardStep implements SettingsStep, Disposable {
- private static final String TEMPLATES_CARD = "templates card";
- private static final String FRAMEWORKS_CARD = "frameworks card";
-
- private static final String PROJECT_WIZARD_GROUP = "project.wizard.group";
public static final Convertor<FrameworkSupportInModuleProvider,String> PROVIDER_STRING_CONVERTOR =
new Convertor<FrameworkSupportInModuleProvider, String>() {
@Override
@@ -98,23 +95,14 @@ public class ProjectTypeStep extends ModuleWizardStep implements SettingsStep, D
return node.getId();
}
};
-
- private JPanel myPanel;
- private JPanel myOptionsPanel;
- private JBList myProjectTypeList;
- private ProjectTemplateList myTemplatesList;
- private JPanel myFrameworksPanelPlaceholder;
- private JPanel myHeaderPanel;
-
+ private static final String TEMPLATES_CARD = "templates card";
+ private static final String FRAMEWORKS_CARD = "frameworks card";
+ private static final String PROJECT_WIZARD_GROUP = "project.wizard.group";
private final WizardContext myContext;
private final NewProjectWizard myWizard;
private final ModulesProvider myModulesProvider;
private final AddSupportForFrameworksPanel myFrameworksPanel;
private final ModuleBuilder.ModuleConfigurationUpdater myConfigurationUpdater;
- @Nullable
- private ModuleWizardStep mySettingsStep;
-
-
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
private final FactoryMap<ProjectTemplate, ModuleBuilder> myBuilders = new FactoryMap<ProjectTemplate, ModuleBuilder>() {
@Nullable
@@ -125,6 +113,15 @@ public class ProjectTypeStep extends ModuleWizardStep implements SettingsStep, D
};
private final Map<String, ModuleWizardStep> myCustomSteps = new HashMap<String, ModuleWizardStep>();
private final MultiMap<TemplatesGroup,ProjectTemplate> myTemplatesMap;
+ private JPanel myPanel;
+ private JPanel myOptionsPanel;
+ private JBList myProjectTypeList;
+ private ProjectTemplateList myTemplatesList;
+ private JPanel myFrameworksPanelPlaceholder;
+ private JPanel myHeaderPanel;
+ private JBLabel myFrameworksLabel;
+ @Nullable
+ private ModuleWizardStep mySettingsStep;
private String myCurrentCard;
private TemplatesGroup myLastSelectedGroup;
@@ -206,6 +203,8 @@ public class ProjectTypeStep extends ModuleWizardStep implements SettingsStep, D
myFrameworksPanel = new AddSupportForFrameworksPanel(Collections.<FrameworkSupportInModuleProvider>emptyList(), model, true, myHeaderPanel);
Disposer.register(this, myFrameworksPanel);
myFrameworksPanelPlaceholder.add(myFrameworksPanel.getMainPanel());
+ myFrameworksLabel.setLabelFor(myFrameworksPanel.getFrameworksTree());
+ myFrameworksLabel.setBorder(IdeBorderFactory.createEmptyBorder(3));
myConfigurationUpdater = new ModuleBuilder.ModuleConfigurationUpdater() {
@Override
@@ -258,6 +257,20 @@ public class ProjectTypeStep extends ModuleWizardStep implements SettingsStep, D
myTemplatesList.restoreSelection();
}
+ private static ModuleType getModuleType(TemplatesGroup group) {
+ ModuleBuilder moduleBuilder = group.getModuleBuilder();
+ return moduleBuilder == null ? null : moduleBuilder.getModuleType();
+ }
+
+ private static boolean matchFramework(ProjectCategory projectCategory, FrameworkSupportInModuleProvider framework) {
+
+ FrameworkRole[] roles = framework.getRoles();
+ if (roles.length == 0) return true;
+
+ List<FrameworkRole> acceptable = Arrays.asList(projectCategory.getAcceptableFrameworkRoles());
+ return ContainerUtil.intersects(Arrays.asList(roles), acceptable);
+ }
+
private boolean isFrameworksMode() {
return FRAMEWORKS_CARD.equals(myCurrentCard) && getSelectedBuilder().equals(myContext.getProjectBuilder());
}
@@ -356,11 +369,6 @@ public class ProjectTypeStep extends ModuleWizardStep implements SettingsStep, D
return groups;
}
- private static ModuleType getModuleType(TemplatesGroup group) {
- ModuleBuilder moduleBuilder = group.getModuleBuilder();
- return moduleBuilder == null ? null : moduleBuilder.getModuleType();
- }
-
// new TemplatesGroup selected
public void projectTypeChanged() {
TemplatesGroup group = getSelectedGroup();
@@ -438,15 +446,6 @@ public class ProjectTypeStep extends ModuleWizardStep implements SettingsStep, D
showCard(TEMPLATES_CARD);
}
- private static boolean matchFramework(ProjectCategory projectCategory, FrameworkSupportInModuleProvider framework) {
-
- FrameworkRole[] roles = framework.getRoles();
- if (roles.length == 0) return true;
-
- List<FrameworkRole> acceptable = Arrays.asList(projectCategory.getAcceptableFrameworkRoles());
- return ContainerUtil.intersects(Arrays.asList(roles), acceptable);
- }
-
private void setTemplatesList(TemplatesGroup group, Collection<ProjectTemplate> templates, boolean preserveSelection) {
List<ProjectTemplate> list = new ArrayList<ProjectTemplate>(templates);
ModuleBuilder moduleBuilder = group.getModuleBuilder();
diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JavaResourceRootEditHandler.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JavaResourceRootEditHandler.java
index bf1efc89b0d5..0c7f20eb3313 100644
--- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JavaResourceRootEditHandler.java
+++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/JavaResourceRootEditHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
package com.intellij.openapi.roots.ui.configuration;
import com.intellij.icons.AllIcons;
+import com.intellij.ui.JBColor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.model.java.JavaResourceRootType;
@@ -51,7 +52,7 @@ public class JavaResourceRootEditHandler extends JavaResourceRootEditHandlerBase
@NotNull
@Override
public Color getRootsGroupColor() {
- return new Color(0x812DF3);
+ return new JBColor(new Color(0x812DF3), new Color(127, 96, 144));
}
@NotNull
diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModuleEditor.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModuleEditor.java
index 10df2939f6e7..a10265607029 100644
--- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModuleEditor.java
+++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ModuleEditor.java
@@ -206,7 +206,9 @@ public abstract class ModuleEditor implements Place.Navigator, Disposable {
myEditors.add(new ModuleConfigurableWrapper(moduleConfigurable));
}
for(ModuleConfigurableEP extension : myModule.getExtensions(MODULE_CONFIGURABLES)) {
- myEditors.add(new ModuleConfigurableWrapper(extension.createConfigurable()));
+ if (extension.canCreateConfigurable()) {
+ myEditors.add(new ModuleConfigurableWrapper(extension.createConfigurable()));
+ }
}
}
diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectStructureConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectStructureConfigurable.java
index a5867d66d176..12ab9b4c0de6 100644
--- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectStructureConfigurable.java
+++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectStructureConfigurable.java
@@ -197,9 +197,9 @@ public class ProjectStructureConfigurable extends BaseConfigurable implements Se
myToolbarComponent = toolbar.getComponent();
if (Registry.is("ide.new.project.settings")) {
left.setBackground(UIUtil.getSidePanelColor());
- } else {
- left.add(myToolbarComponent, BorderLayout.NORTH);
+ myToolbarComponent.setBackground(UIUtil.getSidePanelColor());
}
+ left.add(myToolbarComponent, BorderLayout.NORTH);
left.add(mySidePanel, BorderLayout.CENTER);
mySplitter.setFirstComponent(left);
diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/libraryEditor/DefaultLibraryRootsComponentDescriptor.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/libraryEditor/DefaultLibraryRootsComponentDescriptor.java
index eb87df2a47e7..5b3e9302a14b 100644
--- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/libraryEditor/DefaultLibraryRootsComponentDescriptor.java
+++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/libraryEditor/DefaultLibraryRootsComponentDescriptor.java
@@ -17,6 +17,7 @@ package com.intellij.openapi.roots.ui.configuration.libraryEditor;
import com.intellij.codeInsight.ExternalAnnotationsManager;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
+import com.intellij.openapi.fileChooser.FileElement;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.progress.ProgressIndicator;
@@ -29,7 +30,9 @@ import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.libraries.ui.*;
import com.intellij.openapi.roots.ui.OrderRootTypeUIFactory;
import com.intellij.openapi.roots.ui.configuration.PathUIUtils;
+import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileVisitor;
@@ -45,6 +48,14 @@ import java.util.*;
* @author nik
*/
public class DefaultLibraryRootsComponentDescriptor extends LibraryRootsComponentDescriptor {
+ private static final Set<String> NATIVE_LIBRARY_EXTENSIONS = ContainerUtil.newTroveSet(FileUtil.PATH_HASHING_STRATEGY, "dll", "so", "dylib");
+ public static final Condition<VirtualFile> LIBRARY_ROOT_CONDITION = new Condition<VirtualFile>() {
+ @Override
+ public boolean value(VirtualFile file) {
+ return FileElement.isArchive(file) || isNativeLibrary(file);
+ }
+ };
+
@Override
public OrderRootTypePresentation getRootTypePresentation(@NotNull OrderRootType type) {
return getDefaultPresentation(type);
@@ -67,10 +78,17 @@ public class DefaultLibraryRootsComponentDescriptor extends LibraryRootsComponen
new AnnotationsRootFilter(), new NativeLibraryRootFilter());
}
+ private static boolean isNativeLibrary(VirtualFile file) {
+ String extension = file.getExtension();
+ return extension != null && NATIVE_LIBRARY_EXTENSIONS.contains(extension);
+ }
+
@NotNull
@Override
public FileChooserDescriptor createAttachFilesChooserDescriptor(@Nullable String libraryName) {
- FileChooserDescriptor descriptor = super.createAttachFilesChooserDescriptor(libraryName);
+ final FileChooserDescriptor descriptor = new FileChooserDescriptor(true, true, true, false, true, true).withFileFilter(LIBRARY_ROOT_CONDITION);
+ descriptor.setTitle(StringUtil.isEmpty(libraryName) ? ProjectBundle.message("library.attach.files.action")
+ : ProjectBundle.message("library.attach.files.to.library.action", libraryName));
descriptor.setDescription(ProjectBundle.message("library.java.attach.files.description"));
return descriptor;
}
@@ -119,24 +137,25 @@ public class DefaultLibraryRootsComponentDescriptor extends LibraryRootsComponen
}
}
- private static class NativeLibraryRootFilter extends RootFilter {
- private static final Set<String> NATIVE_LIBRARY_EXTENSIONS = ContainerUtil.newTroveSet(FileUtil.PATH_HASHING_STRATEGY, "dll", "so", "dylib");
-
+ private static class NativeLibraryRootFilter extends RootDetector {
private NativeLibraryRootFilter() {
- super(NativeLibraryOrderRootType.getInstance(), false, "external annotations");
+ super(NativeLibraryOrderRootType.getInstance(), false, "native library location");
}
+ @NotNull
@Override
- public boolean isAccepted(@NotNull VirtualFile rootCandidate, @NotNull ProgressIndicator progressIndicator) {
+ public Collection<VirtualFile> detectRoots(@NotNull VirtualFile rootCandidate, @NotNull ProgressIndicator progressIndicator) {
if (rootCandidate.isDirectory()) {
for (VirtualFile file : rootCandidate.getChildren()) {
- String extension = file.getExtension();
- if (extension != null && NATIVE_LIBRARY_EXTENSIONS.contains(extension)) {
- return true;
+ if (isNativeLibrary(file)) {
+ return Collections.singleton(rootCandidate);
}
}
}
- return false;
+ else if (isNativeLibrary(rootCandidate)) {
+ return Collections.singleton(rootCandidate.getParent());
+ }
+ return Collections.emptyList();
}
}
diff --git a/java/java-analysis-api/src/com/intellij/openapi/roots/LanguageLevelModuleExtension.java b/java/java-analysis-api/src/com/intellij/openapi/roots/LanguageLevelModuleExtension.java
index 76ab3643cb79..c7068ec43482 100644
--- a/java/java-analysis-api/src/com/intellij/openapi/roots/LanguageLevelModuleExtension.java
+++ b/java/java-analysis-api/src/com/intellij/openapi/roots/LanguageLevelModuleExtension.java
@@ -76,6 +76,9 @@ public class LanguageLevelModuleExtension extends ModuleExtension<LanguageLevelM
//bad value was stored
}
}
+ else {
+ myLanguageLevel = null;
+ }
}
@Override
diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/InferredAnnotationsManagerImpl.java b/java/java-analysis-impl/src/com/intellij/codeInsight/InferredAnnotationsManagerImpl.java
index 813ff25caee2..c9230625eecd 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInsight/InferredAnnotationsManagerImpl.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInsight/InferredAnnotationsManagerImpl.java
@@ -20,6 +20,7 @@ import com.intellij.codeInspection.dataFlow.ContractInference;
import com.intellij.codeInspection.dataFlow.MethodContract;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiAnnotation;
+import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiModifierListOwner;
import com.intellij.psi.util.PsiUtil;
@@ -32,9 +33,17 @@ import java.util.List;
import static com.intellij.codeInspection.dataFlow.ControlFlowAnalyzer.ORG_JETBRAINS_ANNOTATIONS_CONTRACT;
public class InferredAnnotationsManagerImpl extends InferredAnnotationsManager {
+
+ @NotNull
+ private static PsiModifierListOwner preferCompiledElement(@NotNull PsiModifierListOwner element) {
+ PsiElement original = element.getOriginalElement();
+ return original instanceof PsiModifierListOwner ? (PsiModifierListOwner)original : element;
+ }
+
@Nullable
@Override
public PsiAnnotation findInferredAnnotation(@NotNull PsiModifierListOwner listOwner, @NotNull String annotationFQN) {
+ listOwner = preferCompiledElement(listOwner);
PsiAnnotation fromBytecode = ProjectBytecodeAnalysis.getInstance(listOwner.getProject()).findInferredAnnotation(listOwner, annotationFQN);
if (fromBytecode != null) {
return fromBytecode;
@@ -57,6 +66,7 @@ public class InferredAnnotationsManagerImpl extends InferredAnnotationsManager {
@NotNull
@Override
public PsiAnnotation[] findInferredAnnotations(@NotNull PsiModifierListOwner listOwner) {
+ listOwner = preferCompiledElement(listOwner);
List<PsiAnnotation> result = ContainerUtil.newArrayList();
PsiAnnotation[] fromBytecode = ProjectBytecodeAnalysis.getInstance(listOwner.getProject()).findInferredAnnotations(listOwner);
for (PsiAnnotation annotation : fromBytecode) {
diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java
index 118c98efc9d2..83af5606d8c8 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java
@@ -1026,7 +1026,7 @@ public class HighlightMethodUtil {
description = JavaErrorMessages.message("extension.method.should.have.a.body");
additionalFixes.add(QUICK_FIX_FACTORY.createAddMethodBodyFix(method));
}
- else if (isInterface && isStatic) {
+ else if (isInterface && isStatic && languageLevel.isAtLeast(LanguageLevel.JDK_1_8)) {
description = "Static methods in interfaces should have a body";
}
}
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/RedundantLambdaCodeBlockInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/RedundantLambdaCodeBlockInspection.java
index 0dfa5df979bc..d65abf63dda3 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/RedundantLambdaCodeBlockInspection.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/RedundantLambdaCodeBlockInspection.java
@@ -19,12 +19,23 @@ import com.intellij.codeInsight.daemon.GroupNames;
import com.intellij.codeInsight.intention.HighPriorityAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
+import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
+import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession;
+import com.intellij.psi.infos.CandidateInfo;
+import com.intellij.psi.infos.MethodCandidateInfo;
+import com.intellij.psi.scope.conflictResolvers.JavaMethodsConflictResolver;
import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.util.PsiUtil;
+import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
/**
* User: anna
*/
@@ -67,6 +78,26 @@ public class RedundantLambdaCodeBlockInspection extends BaseJavaBatchLocalInspec
if (body instanceof PsiCodeBlock) {
PsiExpression psiExpression = getExpression((PsiCodeBlock)body);
if (psiExpression != null) {
+ if (!expression.isVoidCompatible() && LambdaUtil.isExpressionStatementExpression(psiExpression)) {
+ final PsiElement parent = PsiUtil.skipParenthesizedExprUp(expression.getParent());
+ if (parent instanceof PsiExpressionList) {
+ final PsiElement gParent = parent.getParent();
+ if (gParent instanceof PsiCallExpression) {
+ final CandidateInfo[] candidates = PsiResolveHelper.SERVICE.getInstance(gParent.getProject())
+ .getReferencedMethodCandidates((PsiCallExpression)gParent, false);
+ if (candidates.length > 1) {
+ final List<CandidateInfo> info = new ArrayList<CandidateInfo>(Arrays.asList(candidates));
+ final LanguageLevel level = PsiUtil.getLanguageLevel(parent);
+ final JavaMethodsConflictResolver conflictResolver = new JavaMethodsConflictResolver((PsiExpressionList)parent, level);
+ final int applicability = conflictResolver.checkApplicability(info);
+ conflictResolver.checkSpecifics(info, applicability, level);
+ if (info.size() > 1) {
+ return;
+ }
+ }
+ }
+ }
+ }
final PsiElement errorElement;
final PsiElement parent = psiExpression.getParent();
if (parent instanceof PsiReturnStatement) {
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Analysis.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Analysis.java
index 01993d5e9dd0..61d018f2f5ae 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Analysis.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Analysis.java
@@ -28,6 +28,8 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.Frame;
import java.util.*;
+import static com.intellij.codeInspection.bytecodeAnalysis.Direction.*;
+
class AbstractValues {
static final class ParamValue extends BasicValue {
ParamValue(Type tp) {
@@ -274,10 +276,8 @@ abstract class Analysis<Res> {
}
for (int i = 0; i < args.length; i++) {
BasicValue value;
- if (direction instanceof InOut && ((InOut)direction).paramIndex == i) {
- value = new AbstractValues.ParamValue(args[i]);
- }
- else if (direction instanceof In && ((In)direction).paramIndex == i) {
+ if (direction instanceof InOut && ((InOut)direction).paramIndex == i ||
+ direction instanceof In && ((In)direction).paramIndex == i) {
value = new AbstractValues.ParamValue(args[i]);
}
else {
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisConverter.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisConverter.java
index 84a5851e847d..91f1b685faa8 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisConverter.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisConverter.java
@@ -28,6 +28,7 @@ import java.security.NoSuchAlgorithmException;
import java.util.*;
import static com.intellij.codeInspection.bytecodeAnalysis.ProjectBytecodeAnalysis.LOG;
+import static com.intellij.codeInspection.bytecodeAnalysis.Direction.*;
/**
* @author lambdamix
@@ -272,25 +273,35 @@ public class BytecodeAnalysisConverter {
return null;
}
- private static int mkDirectionKey(Direction dir) {
- if (dir instanceof Out) {
+
+ static int mkDirectionKey(Direction dir) {
+ if (dir == Out) {
return 0;
- } else if (dir instanceof In) {
+ }
+ else if (dir == NullableOut) {
+ return 1;
+ }
+ else if (dir instanceof In) {
In in = (In)dir;
// nullity mask is 0/1
- return 8 * in.paramId() + 1 + in.nullityMask;
- } else {
+ return 2 + 8 * in.paramId() + in.nullityMask;
+ }
+ else {
InOut inOut = (InOut)dir;
- return 8 * inOut.paramId() + 3 + inOut.valueId();
+ return 4 + 8 * inOut.paramId() + inOut.valueId();
}
}
@NotNull
private static Direction extractDirection(int directionKey) {
if (directionKey == 0) {
- return new Out();
+ return Out;
+ }
+ else if (directionKey == 1) {
+ return NullableOut;
}
else {
+ directionKey--;
int paramId = directionKey / 8;
int subDirection = directionKey % 8;
if (subDirection <= 2) {
@@ -344,7 +355,7 @@ public class BytecodeAnalysisConverter {
continue;
}
Direction direction = extractDirection(key.dirKey);
- if (value == Value.NotNull && direction instanceof Out && methodKey.equals(key)) {
+ if (value == Value.NotNull && direction == Out && methodKey.equals(key)) {
notNulls.add(key);
}
else if (direction instanceof InOut) {
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisIndex.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisIndex.java
index a7070b882431..4311dd39c2c0 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisIndex.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisIndex.java
@@ -40,7 +40,7 @@ public class BytecodeAnalysisIndex extends FileBasedIndexExtension<Bytes, HEquat
private static final ClassDataIndexer INDEXER = new ClassDataIndexer();
private static final HKeyDescriptor KEY_DESCRIPTOR = new HKeyDescriptor();
- private static final int ourInternalVersion = 1;
+ private static final int ourInternalVersion = 2;
private static boolean ourEnabled = SystemProperties.getBooleanProperty("idea.enable.bytecode.contract.inference", true);
@NotNull
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/ClassDataIndexer.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/ClassDataIndexer.java
index 316307896467..f06ad3fa8987 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/ClassDataIndexer.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/ClassDataIndexer.java
@@ -18,8 +18,6 @@ package com.intellij.codeInspection.bytecodeAnalysis;
import com.intellij.codeInspection.bytecodeAnalysis.asm.*;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressManager;
-import com.intellij.openapi.util.NotNullLazyValue;
-import com.intellij.openapi.util.NullableLazyValue;
import com.intellij.openapi.util.Pair;
import com.intellij.util.indexing.DataIndexer;
import com.intellij.util.indexing.FileContent;
@@ -31,6 +29,7 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException;
import java.security.MessageDigest;
import java.util.*;
+import static com.intellij.codeInspection.bytecodeAnalysis.Direction.*;
import static com.intellij.codeInspection.bytecodeAnalysis.ProjectBytecodeAnalysis.LOG;
/**
@@ -125,7 +124,7 @@ public class ClassDataIndexer implements DataIndexer<Bytes, HEquations, FileCont
final Method method = new Method(className, methodNode.name, methodNode.desc);
final boolean stable = stableClass || (methodNode.access & STABLE_FLAGS) != 0 || "<init>".equals(methodNode.name);
- Key primaryKey = new Key(method, new Out(), stable);
+ Key primaryKey = new Key(method, Out, stable);
if (argumentTypes.length == 0 && !isInterestingResult) {
return Pair.create(primaryKey, EMPTY_EQUATIONS);
}
@@ -172,15 +171,15 @@ public class ClassDataIndexer implements DataIndexer<Bytes, HEquations, FileCont
}
private List<Equation<Key, Value>> processBranchingMethod(final Method method,
- final MethodNode methodNode,
- final RichControlFlow richControlFlow,
- Type[] argumentTypes,
- boolean isReferenceResult,
- boolean isInterestingResult,
- final boolean stable,
- boolean jsr) throws AnalyzerException {
-
- List<Equation<Key, Value>> result = new ArrayList<Equation<Key, Value>>(argumentTypes.length * 4 + 1);
+ final MethodNode methodNode,
+ final RichControlFlow richControlFlow,
+ Type[] argumentTypes,
+ boolean isReferenceResult,
+ boolean isInterestingResult,
+ final boolean stable,
+ boolean jsr) throws AnalyzerException {
+
+ List<Equation<Key, Value>> result = new ArrayList<Equation<Key, Value>>(argumentTypes.length * 4 + 2);
boolean maybeLeakingParameter = isInterestingResult;
for (Type argType : argumentTypes) {
if (ASMUtils.isReferenceType(argType) || (isReferenceResult && ASMUtils.isBooleanType(argType))) {
@@ -191,41 +190,25 @@ public class ClassDataIndexer implements DataIndexer<Bytes, HEquations, FileCont
final LeakingParameters leakingParametersAndFrames =
maybeLeakingParameter ? leakingParametersAndFrames(method, methodNode, argumentTypes, jsr) : null;
+
boolean[] leakingParameters =
leakingParametersAndFrames != null ? leakingParametersAndFrames.parameters : null;
boolean[] leakingNullableParameters =
leakingParametersAndFrames != null ? leakingParametersAndFrames.nullableParameters : null;
- final NullableLazyValue<boolean[]> origins = new NullableLazyValue<boolean[]>() {
- @Override
- protected boolean[] compute() {
- try {
- return OriginsAnalysis.resultOrigins(leakingParametersAndFrames.frames, methodNode.instructions, richControlFlow.controlFlow);
- }
- catch (AnalyzerException e) {
- LOG.debug("when processing " + method + " in " + presentableUrl, e);
- return null;
- }
- }
- };
+ final boolean[] origins =
+ isInterestingResult ?
+ OriginsAnalysis.resultOrigins(leakingParametersAndFrames.frames, methodNode.instructions, richControlFlow.controlFlow) :
+ null;
- NotNullLazyValue<Equation<Key, Value>> outEquation = new NotNullLazyValue<Equation<Key, Value>>() {
- @NotNull
- @Override
- protected Equation<Key, Value> compute() {
- if (origins.getValue() != null) {
- try {
- return new InOutAnalysis(richControlFlow, new Out(), origins.getValue(), stable).analyze();
- }
- catch (AnalyzerException ignored) {
- }
- }
- return new Equation<Key, Value>(new Key(method, new Out(), stable), FINAL_TOP);
- }
- };
+ Equation<Key, Value> outEquation =
+ isInterestingResult ?
+ new InOutAnalysis(richControlFlow, Out, origins, stable).analyze() :
+ null;
if (isReferenceResult) {
- result.add(outEquation.getValue());
+ result.add(outEquation);
+ result.add(new Equation<Key, Value>(new Key(method, NullableOut, stable), NullableMethodAnalysis.analyze(methodNode, origins, jsr)));
}
for (int i = 0; i < argumentTypes.length; i++) {
@@ -259,47 +242,31 @@ public class ClassDataIndexer implements DataIndexer<Bytes, HEquations, FileCont
}
if (isReferenceArg && isInterestingResult) {
if (leakingParameters[i]) {
- if (origins.getValue() != null) {
- // result origins analysis was ok
- if (!notNullParam) {
- // may be null on some branch, running "null->..." analysis
- result.add(new InOutAnalysis(richControlFlow, new InOut(i, Value.Null), origins.getValue(), stable).analyze());
- }
- else {
- // @NotNull, so "null->fail"
- result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.Null), stable), FINAL_BOT));
- }
- result.add(new InOutAnalysis(richControlFlow, new InOut(i, Value.NotNull), origins.getValue(), stable).analyze());
+ if (!notNullParam) {
+ // may be null on some branch, running "null->..." analysis
+ result.add(new InOutAnalysis(richControlFlow, new InOut(i, Value.Null), origins, stable).analyze());
}
else {
- // result origins analysis failed, approximating to Top
- result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.Null), stable), FINAL_TOP));
- result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.NotNull), stable), FINAL_TOP));
+ // @NotNull, so "null->fail"
+ result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.Null), stable), FINAL_BOT));
}
+ result.add(new InOutAnalysis(richControlFlow, new InOut(i, Value.NotNull), origins, stable).analyze());
}
else {
// parameter is not leaking, so a contract is the same as for the whole method
- result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.Null), stable), outEquation.getValue().rhs));
- result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.NotNull), stable), outEquation.getValue().rhs));
+ result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.Null), stable), outEquation.rhs));
+ result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.NotNull), stable), outEquation.rhs));
}
}
if (ASMUtils.isBooleanType(argumentTypes[i]) && isInterestingResult) {
if (leakingParameters[i]) {
- if (origins.getValue() != null) {
- // result origins analysis was ok
- result.add(new InOutAnalysis(richControlFlow, new InOut(i, Value.False), origins.getValue(), stable).analyze());
- result.add(new InOutAnalysis(richControlFlow, new InOut(i, Value.True), origins.getValue(), stable).analyze());
- }
- else {
- // result origins analysis failed, approximating to Top
- result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.False), stable), FINAL_TOP));
- result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.True), stable), FINAL_TOP));
- }
+ result.add(new InOutAnalysis(richControlFlow, new InOut(i, Value.False), origins, stable).analyze());
+ result.add(new InOutAnalysis(richControlFlow, new InOut(i, Value.True), origins, stable).analyze());
}
else {
// parameter is not leaking, so a contract is the same as for the whole method
- result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.False), stable), outEquation.getValue().rhs));
- result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.True), stable), outEquation.getValue().rhs));
+ result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.False), stable), outEquation.rhs));
+ result.add(new Equation<Key, Value>(new Key(method, new InOut(i, Value.True), stable), outEquation.rhs));
}
}
}
@@ -307,16 +274,17 @@ public class ClassDataIndexer implements DataIndexer<Bytes, HEquations, FileCont
}
private List<Equation<Key, Value>> processNonBranchingMethod(Method method,
- Type[] argumentTypes,
- ControlFlowGraph graph,
- boolean isReferenceResult,
- boolean isBooleanResult,
- boolean stable) throws AnalyzerException {
- List<Equation<Key, Value>> result = new ArrayList<Equation<Key, Value>>(argumentTypes.length * 4 + 1);
- CombinedSingleAnalysis analyzer = new CombinedSingleAnalysis(method, graph);
+ Type[] argumentTypes,
+ ControlFlowGraph graph,
+ boolean isReferenceResult,
+ boolean isBooleanResult,
+ boolean stable) throws AnalyzerException {
+ List<Equation<Key, Value>> result = new ArrayList<Equation<Key, Value>>(argumentTypes.length * 4 + 2);
+ CombinedAnalysis analyzer = new CombinedAnalysis(method, graph);
analyzer.analyze();
if (isReferenceResult) {
result.add(analyzer.outContractEquation(stable));
+ result.add(analyzer.nullableResultEquation(stable));
}
for (int i = 0; i < argumentTypes.length; i++) {
Type argType = argumentTypes[i];
@@ -338,13 +306,14 @@ public class ClassDataIndexer implements DataIndexer<Bytes, HEquations, FileCont
}
private List<Equation<Key, Value>> topEquations(Method method,
- Type[] argumentTypes,
- boolean isReferenceResult,
- boolean isInterestingResult,
- boolean stable) {
- List<Equation<Key, Value>> result = new ArrayList<Equation<Key, Value>>(argumentTypes.length * 3 + 1);
+ Type[] argumentTypes,
+ boolean isReferenceResult,
+ boolean isInterestingResult,
+ boolean stable) {
+ List<Equation<Key, Value>> result = new ArrayList<Equation<Key, Value>>(argumentTypes.length * 4 + 2);
if (isReferenceResult) {
- result.add(new Equation<Key, Value>(new Key(method, new Out(), stable), FINAL_TOP));
+ result.add(new Equation<Key, Value>(new Key(method, Out, stable), FINAL_TOP));
+ result.add(new Equation<Key, Value>(new Key(method, NullableOut, stable), FINAL_BOT));
}
for (int i = 0; i < argumentTypes.length; i++) {
Type argType = argumentTypes[i];
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Combined.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Combined.java
index 645c00260af1..dd10492785e7 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Combined.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Combined.java
@@ -34,64 +34,116 @@ import java.util.Set;
import static com.intellij.codeInspection.bytecodeAnalysis.AbstractValues.*;
import static org.jetbrains.org.objectweb.asm.Opcodes.*;
+import static com.intellij.codeInspection.bytecodeAnalysis.Direction.*;
+import static com.intellij.codeInspection.bytecodeAnalysis.CombinedData.*;
-final class ParamKey {
- final Method method;
- final int i;
- final boolean stable;
+// additional data structures for combined analysis
+interface CombinedData {
+ final class ParamKey {
+ final Method method;
+ final int i;
+ final boolean stable;
- ParamKey(Method method, int i, boolean stable) {
- this.method = method;
- this.i = i;
- this.stable = stable;
- }
+ ParamKey(Method method, int i, boolean stable) {
+ this.method = method;
+ this.i = i;
+ this.stable = stable;
+ }
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
- ParamKey paramKey = (ParamKey)o;
+ ParamKey paramKey = (ParamKey)o;
- if (i != paramKey.i) return false;
- if (stable != paramKey.stable) return false;
- if (!method.equals(paramKey.method)) return false;
+ if (i != paramKey.i) return false;
+ if (stable != paramKey.stable) return false;
+ if (!method.equals(paramKey.method)) return false;
- return true;
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = method.hashCode();
+ result = 31 * result + i;
+ result = 31 * result + (stable ? 1 : 0);
+ return result;
+ }
}
- @Override
- public int hashCode() {
- int result = method.hashCode();
- result = 31 * result + i;
- result = 31 * result + (stable ? 1 : 0);
- return result;
+ // value knowing at which instruction it was created
+ interface Trackable {
+ int getOriginInsnIndex();
}
-}
-final class CombinedCall extends BasicValue {
- final Method method;
- final boolean stableCall;
- final List<? extends BasicValue> args;
+ final class TrackableCallValue extends BasicValue implements Trackable {
+ private final int originInsnIndex;
+ final Method method;
+ final List<? extends BasicValue> args;
+ final boolean stableCall;
+ final boolean thisCall;
+
+ TrackableCallValue(int originInsnIndex, Type tp, Method method, List<? extends BasicValue> args, boolean stableCall, boolean thisCall) {
+ super(tp);
+ this.originInsnIndex = originInsnIndex;
+ this.method = method;
+ this.args = args;
+ this.stableCall = stableCall;
+ this.thisCall = thisCall;
+ }
- CombinedCall(Type tp, Method method, boolean stableCall, List<? extends BasicValue> args) {
- super(tp);
- this.method = method;
- this.stableCall = stableCall;
- this.args = args;
+ @Override
+ public int getOriginInsnIndex() {
+ return originInsnIndex;
+ }
}
-}
-final class NParamValue extends BasicValue {
- final int n;
- public NParamValue(Type type, int n) {
- super(type);
- this.n = n;
+ final class NthParamValue extends BasicValue {
+ final int n;
+
+ public NthParamValue(Type type, int n) {
+ super(type);
+ this.n = n;
+ }
+ }
+
+ final class TrackableNullValue extends BasicValue implements Trackable {
+ static final Type NullType = Type.getObjectType("null");
+ private final int originInsnIndex;
+ public TrackableNullValue(int originInsnIndex) {
+ super(NullType);
+ this.originInsnIndex = originInsnIndex;
+ }
+
+ @Override
+ public int getOriginInsnIndex() {
+ return originInsnIndex;
+ }
}
+
+ final class TrackableValue extends BasicValue implements Trackable {
+ private final int originInsnIndex;
+
+ public TrackableValue(int originInsnIndex, Type type) {
+ super(type);
+ this.originInsnIndex = originInsnIndex;
+ }
+
+ @Override
+ public int getOriginInsnIndex() {
+ return originInsnIndex;
+ }
+ }
+
+ BasicValue ThisValue = new BasicValue(Type.getObjectType("java/lang/Object"));
}
-final class CombinedSingleAnalysis {
+// specialized class for analyzing methods without branching in single pass
+final class CombinedAnalysis {
+
private final ControlFlowGraph controlFlow;
private final Method method;
private final CombinedInterpreter interpreter;
@@ -99,11 +151,11 @@ final class CombinedSingleAnalysis {
private boolean exception;
private final MethodNode methodNode;
- CombinedSingleAnalysis(Method method, ControlFlowGraph controlFlow) {
+ CombinedAnalysis(Method method, ControlFlowGraph controlFlow) {
this.method = method;
this.controlFlow = controlFlow;
methodNode = controlFlow.methodNode;
- interpreter = new CombinedInterpreter(Type.getArgumentTypes(methodNode.desc).length);
+ interpreter = new CombinedInterpreter(methodNode.instructions, Type.getArgumentTypes(methodNode.desc).length);
}
final void analyze() throws AnalyzerException {
@@ -144,11 +196,11 @@ final class CombinedSingleAnalysis {
final Equation<Key, Value> notNullParamEquation(int i, boolean stable) {
final Key key = new Key(method, new In(i, In.NOT_NULL), stable);
final Result<Key, Value> result;
- if (interpreter.dereferenced[i]) {
+ if (interpreter.dereferencedParams[i]) {
result = new Final<Key, Value>(Value.NotNull);
}
else {
- Set<ParamKey> calls = interpreter.callDerefs[i];
+ Set<ParamKey> calls = interpreter.parameterFlow[i];
if (calls == null || calls.isEmpty()) {
result = new Final<Key, Value>(Value.Top);
}
@@ -166,11 +218,11 @@ final class CombinedSingleAnalysis {
final Equation<Key, Value> nullableParamEquation(int i, boolean stable) {
final Key key = new Key(method, new In(i, In.NULLABLE), stable);
final Result<Key, Value> result;
- if (interpreter.dereferenced[i] || interpreter.notNullable[i] || returnValue instanceof NParamValue && ((NParamValue)returnValue).n == i) {
+ if (interpreter.dereferencedParams[i] || interpreter.notNullableParams[i] || returnValue instanceof NthParamValue && ((NthParamValue)returnValue).n == i) {
result = new Final<Key, Value>(Value.Top);
}
else {
- Set<ParamKey> calls = interpreter.callDerefs[i];
+ Set<ParamKey> calls = interpreter.parameterFlow[i];
if (calls == null || calls.isEmpty()) {
result = new Final<Key, Value>(Value.Null);
}
@@ -188,7 +240,7 @@ final class CombinedSingleAnalysis {
final Equation<Key, Value> contractEquation(int i, Value inValue, boolean stable) {
final Key key = new Key(method, new InOut(i, inValue), stable);
final Result<Key, Value> result;
- if (exception || (inValue == Value.Null && interpreter.dereferenced[i])) {
+ if (exception || (inValue == Value.Null && interpreter.dereferencedParams[i])) {
result = new Final<Key, Value>(Value.Bot);
}
else if (FalseValue == returnValue) {
@@ -197,29 +249,29 @@ final class CombinedSingleAnalysis {
else if (TrueValue == returnValue) {
result = new Final<Key, Value>(Value.True);
}
- else if (NullValue == returnValue) {
+ else if (returnValue instanceof TrackableNullValue) {
result = new Final<Key, Value>(Value.Null);
}
- else if (returnValue instanceof NotNullValue) {
+ else if (returnValue instanceof NotNullValue || ThisValue == returnValue) {
result = new Final<Key, Value>(Value.NotNull);
}
- else if (returnValue instanceof NParamValue && ((NParamValue)returnValue).n == i) {
+ else if (returnValue instanceof NthParamValue && ((NthParamValue)returnValue).n == i) {
result = new Final<Key, Value>(inValue);
}
- else if (returnValue instanceof CombinedCall) {
- CombinedCall call = (CombinedCall)returnValue;
+ else if (returnValue instanceof TrackableCallValue) {
+ TrackableCallValue call = (TrackableCallValue)returnValue;
HashSet<Key> keys = new HashSet<Key>();
for (int argI = 0; argI < call.args.size(); argI++) {
BasicValue arg = call.args.get(argI);
- if (arg instanceof NParamValue) {
- NParamValue npv = (NParamValue)arg;
+ if (arg instanceof NthParamValue) {
+ NthParamValue npv = (NthParamValue)arg;
if (npv.n == i) {
keys.add(new Key(call.method, new InOut(argI, inValue), call.stableCall));
}
}
}
if (ASMUtils.isReferenceType(call.getType())) {
- keys.add(new Key(call.method, new Out(), call.stableCall));
+ keys.add(new Key(call.method, Out, call.stableCall));
}
if (keys.isEmpty()) {
result = new Final<Key, Value>(Value.Top);
@@ -234,7 +286,7 @@ final class CombinedSingleAnalysis {
}
final Equation<Key, Value> outContractEquation(boolean stable) {
- final Key key = new Key(method, new Out(), stable);
+ final Key key = new Key(method, Out, stable);
final Result<Key, Value> result;
if (exception) {
result = new Final<Key, Value>(Value.Bot);
@@ -245,15 +297,15 @@ final class CombinedSingleAnalysis {
else if (TrueValue == returnValue) {
result = new Final<Key, Value>(Value.True);
}
- else if (NullValue == returnValue) {
+ else if (returnValue instanceof TrackableNullValue) {
result = new Final<Key, Value>(Value.Null);
}
- else if (returnValue instanceof NotNullValue) {
+ else if (returnValue instanceof NotNullValue || returnValue == ThisValue) {
result = new Final<Key, Value>(Value.NotNull);
}
- else if (returnValue instanceof CombinedCall) {
- CombinedCall call = (CombinedCall)returnValue;
- Key callKey = new Key(call.method, new Out(), call.stableCall);
+ else if (returnValue instanceof TrackableCallValue) {
+ TrackableCallValue call = (TrackableCallValue)returnValue;
+ Key callKey = new Key(call.method, Out, call.stableCall);
Set<Key> keys = new SingletonSet<Key>(callKey);
result = new Pending<Key, Value>(new SingletonSet<Product<Key, Value>>(new Product<Key, Value>(Value.Top, keys)));
}
@@ -263,6 +315,28 @@ final class CombinedSingleAnalysis {
return new Equation<Key, Value>(key, result);
}
+ final Equation<Key, Value> nullableResultEquation(boolean stable) {
+ final Key key = new Key(method, NullableOut, stable);
+ final Result<Key, Value> result;
+ if (exception ||
+ returnValue instanceof Trackable && interpreter.dereferencedValues[((Trackable)returnValue).getOriginInsnIndex()]) {
+ result = new Final<Key, Value>(Value.Bot);
+ }
+ else if (returnValue instanceof TrackableCallValue) {
+ TrackableCallValue call = (TrackableCallValue)returnValue;
+ Key callKey = new Key(call.method, NullableOut, call.stableCall || call.thisCall);
+ Set<Key> keys = new SingletonSet<Key>(callKey);
+ result = new Pending<Key, Value>(new SingletonSet<Product<Key, Value>>(new Product<Key, Value>(Value.Null, keys)));
+ }
+ else if (returnValue instanceof TrackableNullValue) {
+ result = new Final<Key, Value>(Value.Null);
+ }
+ else {
+ result = new Final<Key, Value>(Value.Bot);
+ }
+ return new Equation<Key, Value>(key, result);
+ }
+
final Frame<BasicValue> createStartFrame() {
Frame<BasicValue> frame = new Frame<BasicValue>(methodNode.maxLocals, methodNode.maxStack);
Type returnType = Type.getReturnType(methodNode.desc);
@@ -272,10 +346,10 @@ final class CombinedSingleAnalysis {
Type[] args = Type.getArgumentTypes(methodNode.desc);
int local = 0;
if ((methodNode.access & Opcodes.ACC_STATIC) == 0) {
- frame.setLocal(local++, new AbstractValues.NotNullValue(Type.getObjectType(controlFlow.className)));
+ frame.setLocal(local++, ThisValue);
}
for (int i = 0; i < args.length; i++) {
- BasicValue value = new NParamValue(args[i], i);
+ BasicValue value = new NthParamValue(args[i], i);
frame.setLocal(local++, value);
if (args[i].getSize() == 2) {
frame.setLocal(local++, BasicValue.UNINITIALIZED_VALUE);
@@ -289,25 +363,47 @@ final class CombinedSingleAnalysis {
}
final class CombinedInterpreter extends BasicInterpreter {
- final boolean[] dereferenced;
- final boolean[] notNullable;
- final Set<ParamKey>[] callDerefs;
-
- CombinedInterpreter(int arity) {
- dereferenced = new boolean[arity];
- notNullable = new boolean[arity];
- callDerefs = new Set[arity];
+ // Parameters dereferenced during execution of a method, tracked by parameter's indices.
+ // Dereferenced parameters are @NotNull.
+ final boolean[] dereferencedParams;
+ // Parameters, that are written to something or passed to an interface methods.
+ // This parameters cannot be @Nullable.
+ final boolean[] notNullableParams;
+ // parameterFlow(i) for i-th parameter stores a set parameter positions it is passed to
+ // parameter is @NotNull if any of its usages are @NotNull
+ final Set<ParamKey>[] parameterFlow;
+
+ // Trackable values that were dereferenced during execution of a method
+ // Values are are identified by `origin` index
+ final boolean[] dereferencedValues;
+ private final InsnList insns;
+
+ CombinedInterpreter(InsnList insns, int arity) {
+ dereferencedParams = new boolean[arity];
+ notNullableParams = new boolean[arity];
+ parameterFlow = new Set[arity];
+ this.insns = insns;
+ dereferencedValues = new boolean[insns.size()];
+ }
+
+ private int insnIndex(AbstractInsnNode insn) {
+ return insns.indexOf(insn);
+ }
+
+ private static BasicValue track(int origin, BasicValue basicValue) {
+ return basicValue == null ? null : new TrackableValue(origin, basicValue.getType());
}
@Override
public BasicValue newOperation(AbstractInsnNode insn) throws AnalyzerException {
+ int origin = insnIndex(insn);
switch (insn.getOpcode()) {
case ICONST_0:
return FalseValue;
case ICONST_1:
return TrueValue;
case ACONST_NULL:
- return NullValue;
+ return new TrackableNullValue(origin);
case LDC:
Object cst = ((LdcInsnNode)insn).cst;
if (cst instanceof Type) {
@@ -330,22 +426,26 @@ final class CombinedInterpreter extends BasicInterpreter {
return new NotNullValue(Type.getObjectType(((TypeInsnNode)insn).desc));
default:
}
- return super.newOperation(insn);
+ return track(origin, super.newOperation(insn));
}
@Override
public BasicValue unaryOperation(AbstractInsnNode insn, BasicValue value) throws AnalyzerException {
+ int origin = insnIndex(insn);
switch (insn.getOpcode()) {
case GETFIELD:
case ARRAYLENGTH:
case MONITORENTER:
- if (value instanceof NParamValue) {
- dereferenced[((NParamValue)value).n] = true;
+ if (value instanceof NthParamValue) {
+ dereferencedParams[((NthParamValue)value).n] = true;
}
- return super.unaryOperation(insn, value);
+ if (value instanceof Trackable) {
+ dereferencedValues[((Trackable)value).getOriginInsnIndex()] = true;
+ }
+ return track(origin, super.unaryOperation(insn, value));
case CHECKCAST:
- if (value instanceof NParamValue) {
- return new NParamValue(Type.getObjectType(((TypeInsnNode)insn).desc), ((NParamValue)value).n);
+ if (value instanceof NthParamValue) {
+ return new NthParamValue(Type.getObjectType(((TypeInsnNode)insn).desc), ((NthParamValue)value).n);
}
break;
case NEWARRAY:
@@ -353,12 +453,23 @@ final class CombinedInterpreter extends BasicInterpreter {
return new NotNullValue(super.unaryOperation(insn, value).getType());
default:
}
- return super.unaryOperation(insn, value);
+ return track(origin, super.unaryOperation(insn, value));
}
@Override
public BasicValue binaryOperation(AbstractInsnNode insn, BasicValue value1, BasicValue value2) throws AnalyzerException {
switch (insn.getOpcode()) {
+ case PUTFIELD:
+ if (value1 instanceof NthParamValue) {
+ dereferencedParams[((NthParamValue)value1).n] = true;
+ }
+ if (value1 instanceof Trackable) {
+ dereferencedValues[((Trackable)value1).getOriginInsnIndex()] = true;
+ }
+ if (value2 instanceof NthParamValue) {
+ notNullableParams[((NthParamValue)value2).n] = true;
+ }
+ break;
case IALOAD:
case LALOAD:
case FALOAD:
@@ -367,21 +478,16 @@ final class CombinedInterpreter extends BasicInterpreter {
case BALOAD:
case CALOAD:
case SALOAD:
- if (value1 instanceof NParamValue) {
- dereferenced[((NParamValue)value1).n] = true;
- }
- break;
- case PUTFIELD:
- if (value1 instanceof NParamValue) {
- dereferenced[((NParamValue)value1).n] = true;
+ if (value1 instanceof NthParamValue) {
+ dereferencedParams[((NthParamValue)value1).n] = true;
}
- if (value2 instanceof NParamValue) {
- notNullable[((NParamValue)value2).n] = true;
+ if (value1 instanceof Trackable) {
+ dereferencedValues[((Trackable)value1).getOriginInsnIndex()] = true;
}
break;
default:
}
- return super.binaryOperation(insn, value1, value2);
+ return track(insnIndex(insn), super.binaryOperation(insn, value1, value2));
}
@Override
@@ -395,35 +501,46 @@ final class CombinedInterpreter extends BasicInterpreter {
case BASTORE:
case CASTORE:
case SASTORE:
- if (value1 instanceof NParamValue) {
- dereferenced[((NParamValue)value1).n] = true;
+ if (value1 instanceof NthParamValue) {
+ dereferencedParams[((NthParamValue)value1).n] = true;
+ }
+ if (value1 instanceof Trackable) {
+ dereferencedValues[((Trackable)value1).getOriginInsnIndex()] = true;
}
break;
case AASTORE:
- if (value1 instanceof NParamValue) {
- dereferenced[((NParamValue)value1).n] = true;
+ if (value1 instanceof NthParamValue) {
+ dereferencedParams[((NthParamValue)value1).n] = true;
+ }
+ if (value1 instanceof Trackable) {
+ dereferencedValues[((Trackable)value1).getOriginInsnIndex()] = true;
}
- if (value3 instanceof NParamValue) {
- notNullable[((NParamValue)value3).n] = true;
+ if (value3 instanceof NthParamValue) {
+ notNullableParams[((NthParamValue)value3).n] = true;
}
break;
default:
}
- return super.ternaryOperation(insn, value1, value2, value3);
+ return null;
}
@Override
public BasicValue naryOperation(AbstractInsnNode insn, List<? extends BasicValue> values) throws AnalyzerException {
int opCode = insn.getOpcode();
int shift = opCode == INVOKESTATIC ? 0 : 1;
-
+ int origin = insnIndex(insn);
switch (opCode) {
case INVOKESPECIAL:
case INVOKEINTERFACE:
case INVOKEVIRTUAL:
- if (values.get(0) instanceof NParamValue) {
- dereferenced[((NParamValue)values.get(0)).n] = true;
+ BasicValue receiver = values.get(0);
+ if (receiver instanceof NthParamValue) {
+ dereferencedParams[((NthParamValue)receiver).n] = true;
+ }
+ if (receiver instanceof Trackable) {
+ dereferencedValues[((Trackable)receiver).getOriginInsnIndex()] = true;
}
+ default:
}
switch (opCode) {
@@ -437,29 +554,31 @@ final class CombinedInterpreter extends BasicInterpreter {
Type retType = Type.getReturnType(mNode.desc);
for (int i = shift; i < values.size(); i++) {
- if (values.get(i) instanceof NParamValue) {
- int n = ((NParamValue)values.get(i)).n;
+ if (values.get(i) instanceof NthParamValue) {
+ int n = ((NthParamValue)values.get(i)).n;
if (opCode == INVOKEINTERFACE) {
- notNullable[n] = true;
+ notNullableParams[n] = true;
}
else {
- Set<ParamKey> npKeys = callDerefs[n];
+ Set<ParamKey> npKeys = parameterFlow[n];
if (npKeys == null) {
npKeys = new HashSet<ParamKey>();
- callDerefs[n] = npKeys;
+ parameterFlow[n] = npKeys;
}
npKeys.add(new ParamKey(method, i - shift, stable));
}
}
}
+ BasicValue receiver = null;
if (shift == 1) {
- values.remove(0);
+ receiver = values.remove(0);
}
- return new CombinedCall(retType, method, stable, values);
+ boolean thisCall = (opCode == INVOKEINTERFACE || opCode == INVOKEVIRTUAL) && receiver == ThisValue;
+ return new TrackableCallValue(origin, retType, method, values, stable, thisCall);
case MULTIANEWARRAY:
return new NotNullValue(super.naryOperation(insn, values).getType());
default:
}
- return super.naryOperation(insn, values);
+ return track(origin, super.naryOperation(insn, values));
}
}
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Contracts.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Contracts.java
index c382148abb05..73972871ee7b 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Contracts.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Contracts.java
@@ -34,6 +34,7 @@ import java.util.Set;
import static com.intellij.codeInspection.bytecodeAnalysis.AbstractValues.*;
import static org.jetbrains.org.objectweb.asm.Opcodes.*;
+import static com.intellij.codeInspection.bytecodeAnalysis.Direction.*;
class InOutAnalysis extends Analysis<Result<Key, Value>> {
@@ -396,7 +397,7 @@ class InOutInterpreter extends BasicInterpreter {
}
default:
}
- return super.ternaryOperation(insn, value1, value2, value3);
+ return null;
}
@Override
@@ -436,7 +437,7 @@ class InOutInterpreter extends BasicInterpreter {
}
}
if (isRefRetType) {
- keys.add(new Key(method, new Out(), stable));
+ keys.add(new Key(method, Out, stable));
}
if (!keys.isEmpty()) {
return new CallResultValue(retType, keys);
@@ -444,7 +445,7 @@ class InOutInterpreter extends BasicInterpreter {
}
else if (isRefRetType) {
HashSet<Key> keys = new HashSet<Key>();
- keys.add(new Key(method, new Out(), stable));
+ keys.add(new Key(method, Out, stable));
return new CallResultValue(retType, keys);
}
}
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Data.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Data.java
index 55a842af684c..b76e31197482 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Data.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Data.java
@@ -52,103 +52,109 @@ enum Value {
Bot, NotNull, Null, True, False, Top
}
-interface Direction {}
-
-final class In implements Direction {
- static final int NOT_NULL = 0;
- static final int NULLABLE = 1;
- final int paramIndex;
- final int nullityMask;
-
- In(int paramIndex, int nullityMask) {
- this.paramIndex = paramIndex;
- this.nullityMask = nullityMask;
- }
-
- @Override
- public String toString() {
- return "In " + paramIndex;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- In in = (In) o;
- if (paramIndex != in.paramIndex) return false;
- if (nullityMask != in.nullityMask) return false;
- return true;
- }
-
- @Override
- public int hashCode() {
- return 31*paramIndex + nullityMask;
- }
-
- public int paramId() {
- return paramIndex;
- }
-
-}
-
-final class InOut implements Direction {
- final int paramIndex;
- final Value inValue;
-
- InOut(int paramIndex, Value inValue) {
- this.paramIndex = paramIndex;
- this.inValue = inValue;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
- InOut inOut = (InOut) o;
-
- if (paramIndex != inOut.paramIndex) return false;
- if (inValue != inOut.inValue) return false;
-
- return true;
- }
-
- @Override
- public int hashCode() {
- int result = paramIndex;
- result = 31 * result + inValue.ordinal();
- return result;
- }
-
- @Override
- public String toString() {
- return "InOut " + paramIndex + " " + inValue.toString();
- }
-
- public int paramId() {
- return paramIndex;
- }
-
- public int valueId() {
- return inValue.ordinal();
- }
-}
-
-final class Out implements Direction {
- @Override
- public String toString() {
- return "Out";
- }
-
- @Override
- public int hashCode() {
- return 1;
- }
-
- @Override
- public boolean equals(Object obj) {
- return obj instanceof Out;
- }
+interface Direction {
+ final class In implements Direction {
+ static final int NOT_NULL = 0;
+ static final int NULLABLE = 1;
+ final int paramIndex;
+ final int nullityMask;
+
+ In(int paramIndex, int nullityMask) {
+ this.paramIndex = paramIndex;
+ this.nullityMask = nullityMask;
+ }
+
+ @Override
+ public String toString() {
+ return "In " + paramIndex;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ In in = (In)o;
+ if (paramIndex != in.paramIndex) return false;
+ if (nullityMask != in.nullityMask) return false;
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * paramIndex + nullityMask;
+ }
+
+ public int paramId() {
+ return paramIndex;
+ }
+ }
+
+ final class InOut implements Direction {
+ final int paramIndex;
+ final Value inValue;
+
+ InOut(int paramIndex, Value inValue) {
+ this.paramIndex = paramIndex;
+ this.inValue = inValue;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ InOut inOut = (InOut)o;
+
+ if (paramIndex != inOut.paramIndex) return false;
+ if (inValue != inOut.inValue) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = paramIndex;
+ result = 31 * result + inValue.ordinal();
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "InOut " + paramIndex + " " + inValue.toString();
+ }
+
+ public int paramId() {
+ return paramIndex;
+ }
+
+ public int valueId() {
+ return inValue.ordinal();
+ }
+ }
+
+ Direction Out = new Direction() {
+ @Override
+ public String toString() {
+ return "Out";
+ }
+
+ @Override
+ public int hashCode() {
+ return -1;
+ }
+ };
+
+ Direction NullableOut = new Direction() {
+ @Override
+ public String toString() {
+ return "NullableOut";
+ }
+
+ @Override
+ public int hashCode() {
+ return -2;
+ }
+ };
}
final class Key {
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/NullableMethodAnalysis.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/NullableMethodAnalysis.java
new file mode 100644
index 000000000000..cf2e8d7a1da4
--- /dev/null
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/NullableMethodAnalysis.java
@@ -0,0 +1,423 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInspection.bytecodeAnalysis;
+
+import com.intellij.codeInspection.bytecodeAnalysis.asm.AnalyzerExt;
+import com.intellij.codeInspection.bytecodeAnalysis.asm.InterpreterExt;
+import com.intellij.codeInspection.bytecodeAnalysis.asm.LiteAnalyzerExt;
+import org.jetbrains.org.objectweb.asm.Opcodes;
+import org.jetbrains.org.objectweb.asm.Type;
+import org.jetbrains.org.objectweb.asm.tree.*;
+import org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException;
+import org.jetbrains.org.objectweb.asm.tree.analysis.BasicInterpreter;
+import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue;
+import org.jetbrains.org.objectweb.asm.tree.analysis.Frame;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import static com.intellij.codeInspection.bytecodeAnalysis.NullableMethodAnalysisData.*;
+
+interface NullableMethodAnalysisData {
+ Type NullType = Type.getObjectType("null");
+ Type ThisType = Type.getObjectType("this");
+ Type CallType = Type.getObjectType("/Call");
+
+ final class LabeledNull extends BasicValue {
+ final int origins;
+
+ public LabeledNull(int origins) {
+ super(NullType);
+ this.origins = origins;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ LabeledNull that = (LabeledNull)o;
+ return origins == that.origins;
+ }
+
+ @Override
+ public int hashCode() {
+ return origins;
+ }
+ }
+
+ final class Calls extends BasicValue {
+ final int mergedLabels;
+
+ public Calls(int mergedLabels) {
+ super(CallType);
+ this.mergedLabels = mergedLabels;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == null || getClass() != o.getClass()) return false;
+ Calls calls = (Calls)o;
+ return mergedLabels == calls.mergedLabels;
+ }
+
+ @Override
+ public int hashCode() {
+ return mergedLabels;
+ }
+ }
+
+ final class Constraint {
+ final static Constraint EMPTY = new Constraint(0, 0);
+
+ final int calls;
+ final int nulls;
+
+ public Constraint(int calls, int nulls) {
+ this.calls = calls;
+ this.nulls = nulls;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ Constraint that = (Constraint)o;
+
+ if (calls != that.calls) return false;
+ if (nulls != that.nulls) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = calls;
+ result = 31 * result + nulls;
+ return result;
+ }
+ }
+
+ BasicValue ThisValue = new BasicValue(ThisType);
+}
+
+class NullableMethodAnalysis {
+
+ static Result<Key, Value> FinalNull = new Final<Key, Value>(Value.Null);
+ static Result<Key, Value> FinalBot = new Final<Key, Value>(Value.Bot);
+ static BasicValue lNull = new LabeledNull(0);
+
+ static Result<Key, Value> analyze(MethodNode methodNode, boolean[] origins, boolean jsr) throws AnalyzerException {
+ InsnList insns = methodNode.instructions;
+ Constraint[] data = new Constraint[insns.size()];
+ int[] originsMapping = mapOrigins(origins);
+
+ NullableMethodInterpreter interpreter = new NullableMethodInterpreter(insns, origins, originsMapping);
+ Frame<BasicValue>[] frames =
+ jsr ?
+ new AnalyzerExt<BasicValue, Constraint, NullableMethodInterpreter>(interpreter, data, Constraint.EMPTY).analyze("this", methodNode) :
+ new LiteAnalyzerExt<BasicValue, Constraint, NullableMethodInterpreter>(interpreter, data, Constraint.EMPTY).analyze("this", methodNode);
+
+ BasicValue result = BasicValue.REFERENCE_VALUE;
+ for (int i = 0; i < frames.length; i++) {
+ Frame<BasicValue> frame = frames[i];
+ if (frame != null && insns.get(i).getOpcode() == Opcodes.ARETURN) {
+ BasicValue stackTop = frame.pop();
+ result = combine(result, stackTop, data[i]);
+ }
+ }
+ if (result instanceof LabeledNull) {
+ return FinalNull;
+ }
+ if (result instanceof Calls) {
+ Calls calls = ((Calls)result);
+ int mergedMappedLabels = calls.mergedLabels;
+ if (mergedMappedLabels != 0) {
+ Set<Product<Key, Value>> sum = new HashSet<Product<Key, Value>>();
+ Key[] createdKeys = interpreter.keys;
+ for (int origin = 0; origin < originsMapping.length; origin++) {
+ int mappedOrigin = originsMapping[origin];
+ Key createdKey = createdKeys[origin];
+ if (createdKey != null && (mergedMappedLabels & (1 << mappedOrigin)) != 0) {
+ sum.add(new Product<Key, Value>(Value.Null, Collections.singleton(createdKey)));
+ }
+ }
+ if (!sum.isEmpty()) {
+ return new Pending<Key, Value>(sum);
+ }
+ }
+ }
+ return FinalBot;
+ }
+
+ private static int[] mapOrigins(boolean[] origins) {
+ int[] originsMapping = new int[origins.length];
+ int mapped = 0;
+ for (int i = 0; i < origins.length; i++) {
+ originsMapping[i] = origins[i] ? mapped++ : -1;
+ }
+ return originsMapping;
+ }
+
+ static BasicValue combine(BasicValue v1, BasicValue v2, Constraint constraint) {
+ if (v1 instanceof LabeledNull) {
+ return lNull;
+ }
+ else if (v2 instanceof LabeledNull) {
+ int v2Origins = ((LabeledNull)v2).origins;
+ int constraintOrigins = constraint.nulls;
+ int intersect = v2Origins & constraintOrigins;
+ return intersect == v2Origins ? v1 : lNull;
+ }
+ else if (v1 instanceof Calls) {
+ if (v2 instanceof Calls) {
+ Calls calls1 = (Calls)v1;
+ Calls calls2 = (Calls)v2;
+ int labels2 = calls2.mergedLabels;
+ int aliveLabels2 = labels2 - (labels2 & constraint.calls);
+ return new Calls(calls1.mergedLabels | aliveLabels2);
+ } else {
+ return v1;
+ }
+ }
+ else if (v2 instanceof Calls) {
+ Calls calls2 = (Calls)v2;
+ int labels2 = calls2.mergedLabels;
+ int aliveLabels2 = labels2 - (labels2 & constraint.calls);
+ return new Calls(aliveLabels2);
+ }
+ return BasicValue.REFERENCE_VALUE;
+ }
+}
+
+class NullableMethodInterpreter extends BasicInterpreter implements InterpreterExt<Constraint> {
+ final InsnList insns;
+ final boolean[] origins;
+ private final int[] originsMapping;
+ final Key[] keys;
+
+ Constraint constraint = null;
+ int delta = 0;
+ int nullsDelta = 0;
+ int notNullInsn = -1;
+ int notNullCall = 0;
+ int notNullNull = 0;
+
+ NullableMethodInterpreter(InsnList insns, boolean[] origins, int[] originsMapping) {
+ this.insns = insns;
+ this.origins = origins;
+ this.originsMapping = originsMapping;
+ keys = new Key[originsMapping.length];
+ }
+
+ @Override
+ public BasicValue newValue(Type type) {
+ return ThisType.equals(type) ? ThisValue : super.newValue(type);
+ }
+
+ @Override
+ public BasicValue newOperation(AbstractInsnNode insn) throws AnalyzerException {
+ if (insn.getOpcode() == Opcodes.ACONST_NULL) {
+ int insnIndex = insns.indexOf(insn);
+ if (origins[insnIndex]) {
+ return new LabeledNull(1 << originsMapping[insnIndex]);
+ }
+ }
+ return super.newOperation(insn);
+ }
+
+ @Override
+ public BasicValue unaryOperation(AbstractInsnNode insn, BasicValue value) throws AnalyzerException {
+ switch (insn.getOpcode()) {
+ case GETFIELD:
+ case ARRAYLENGTH:
+ case MONITORENTER:
+ if (value instanceof Calls) {
+ delta = ((Calls)value).mergedLabels;
+ }
+ break;
+ case IFNULL:
+ if (value instanceof Calls) {
+ notNullInsn = insns.indexOf(insn) + 1;
+ notNullCall = ((Calls)value).mergedLabels;
+ }
+ else if (value instanceof LabeledNull) {
+ notNullInsn = insns.indexOf(insn) + 1;
+ notNullNull = ((LabeledNull)value).origins;
+ }
+ break;
+ case IFNONNULL:
+ if (value instanceof Calls) {
+ notNullInsn = insns.indexOf(((JumpInsnNode)insn).label);
+ notNullCall = ((Calls)value).mergedLabels;
+ }
+ else if (value instanceof LabeledNull) {
+ notNullInsn = insns.indexOf(((JumpInsnNode)insn).label);
+ notNullNull = ((LabeledNull)value).origins;
+ }
+ break;
+ default:
+
+ }
+ return super.unaryOperation(insn, value);
+ }
+
+ @Override
+ public BasicValue binaryOperation(AbstractInsnNode insn, BasicValue value1, BasicValue value2) throws AnalyzerException {
+ switch (insn.getOpcode()) {
+ case PUTFIELD:
+ case IALOAD:
+ case LALOAD:
+ case FALOAD:
+ case DALOAD:
+ case AALOAD:
+ case BALOAD:
+ case CALOAD:
+ case SALOAD:
+ if (value1 instanceof Calls) {
+ delta = ((Calls)value1).mergedLabels;
+ }
+ if (value1 instanceof LabeledNull){
+ nullsDelta = ((LabeledNull)value1).origins;
+ }
+ break;
+ default:
+ }
+ return super.binaryOperation(insn, value1, value2);
+ }
+
+ @Override
+ public BasicValue ternaryOperation(AbstractInsnNode insn, BasicValue value1, BasicValue value2, BasicValue value3)
+ throws AnalyzerException {
+ if (value1 instanceof Calls) {
+ delta = ((Calls)value1).mergedLabels;
+ }
+ if (value1 instanceof LabeledNull){
+ nullsDelta = ((LabeledNull)value1).origins;
+ }
+ return null;
+ }
+
+ @Override
+ public BasicValue naryOperation(AbstractInsnNode insn, List<? extends BasicValue> values) throws AnalyzerException {
+ int opCode = insn.getOpcode();
+ switch (opCode) {
+ case INVOKESPECIAL:
+ case INVOKEINTERFACE:
+ case INVOKEVIRTUAL:
+ BasicValue receiver = values.get(0);
+ if (receiver instanceof Calls) {
+ delta = ((Calls)receiver).mergedLabels;
+ }
+ if (receiver instanceof LabeledNull){
+ nullsDelta = ((LabeledNull)receiver).origins;
+ }
+ break;
+ default:
+ }
+
+ switch (opCode) {
+ case INVOKESTATIC:
+ case INVOKESPECIAL:
+ case INVOKEVIRTUAL:
+ int insnIndex = insns.indexOf(insn);
+ if (origins[insnIndex]) {
+ boolean stable = (opCode == INVOKESTATIC) ||
+ (opCode == INVOKESPECIAL) ||
+ (values.get(0) == ThisValue);
+ MethodInsnNode mNode = ((MethodInsnNode)insn);
+ Method method = new Method(mNode.owner, mNode.name, mNode.desc);
+ int label = 1 << originsMapping[insnIndex];
+ if (keys[insnIndex] == null) {
+ keys[insnIndex] = new Key(method, Direction.NullableOut, stable);
+ }
+ return new Calls(label);
+ }
+ break;
+ default:
+ }
+ return super.naryOperation(insn, values);
+ }
+
+ @Override
+ public BasicValue merge(BasicValue v1, BasicValue v2) {
+ if (v1 instanceof LabeledNull) {
+ if (v2 instanceof LabeledNull) {
+ return new LabeledNull(((LabeledNull)v1).origins | ((LabeledNull)v2).origins);
+ }
+ else {
+ return v1;
+ }
+ }
+ else if (v2 instanceof LabeledNull) {
+ return v2;
+ }
+ else if (v1 instanceof Calls) {
+ if (v2 instanceof Calls) {
+ Calls calls1 = (Calls)v1;
+ Calls calls2 = (Calls)v2;
+ return new Calls(calls1.mergedLabels | calls2.mergedLabels);
+ }
+ else {
+ return v1;
+ }
+ }
+ else if (v2 instanceof Calls) {
+ return v2;
+ }
+ return super.merge(v1, v2);
+ }
+
+ // ---------- InterpreterExt<Constraint> --------------
+
+ @Override
+ public void init(Constraint previous) {
+ constraint = previous;
+ delta = 0;
+ nullsDelta = 0;
+
+ notNullInsn = -1;
+ notNullCall = 0;
+ notNullNull = 0;
+ }
+
+ @Override
+ public Constraint getAfterData(int insn) {
+ Constraint afterData = mkAfterData();
+ if (notNullInsn == insn) {
+ return new Constraint(afterData.calls | notNullCall, afterData.nulls | notNullNull);
+ }
+ return afterData;
+ }
+
+ private Constraint mkAfterData() {
+ if (delta == 0 && nullsDelta == 0 && notNullInsn == -1) {
+ return constraint;
+ }
+ return new Constraint(constraint.calls | delta, constraint.nulls | nullsDelta);
+ }
+
+ @Override
+ public Constraint merge(Constraint data1, Constraint data2) {
+ if (data1.equals(data2)) {
+ return data1;
+ } else {
+ return new Constraint(data1.calls | data2.calls, data1.nulls | data2.nulls);
+ }
+ }
+}
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Parameters.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Parameters.java
index a7c25782d48b..6102c44792bf 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Parameters.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Parameters.java
@@ -37,6 +37,7 @@ import static com.intellij.codeInspection.bytecodeAnalysis.AbstractValues.Instan
import static com.intellij.codeInspection.bytecodeAnalysis.AbstractValues.ParamValue;
import static com.intellij.codeInspection.bytecodeAnalysis.PResults.*;
import static org.jetbrains.org.objectweb.asm.Opcodes.*;
+import static com.intellij.codeInspection.bytecodeAnalysis.Direction.*;
abstract class PResults {
// SoP = sum of products
@@ -706,7 +707,7 @@ abstract class NullityInterpreter extends BasicInterpreter {
break;
default:
}
- return super.ternaryOperation(insn, value1, value2, value3);
+ return null;
}
@Override
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/ProjectBytecodeAnalysis.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/ProjectBytecodeAnalysis.java
index aa44951961ad..610a6fecdaf5 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/ProjectBytecodeAnalysis.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/ProjectBytecodeAnalysis.java
@@ -23,6 +23,7 @@ import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.ModificationTracker;
+import com.intellij.openapi.util.registry.Registry;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.ProjectScope;
@@ -39,14 +40,18 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
+import static com.intellij.codeInspection.bytecodeAnalysis.Direction.*;
+
/**
* @author lambdamix
*/
public class ProjectBytecodeAnalysis {
public static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.bytecodeAnalysis");
public static final Key<Boolean> INFERRED_ANNOTATION = Key.create("INFERRED_ANNOTATION");
+ public static final String NULLABLE_METHOD_TRANSITIVITY = "java.annotations.inference.nullable.method.transitivity";
public static final int EQUATIONS_LIMIT = 1000;
private final Project myProject;
+ private final boolean nullableMethodTransitivity;
public static ProjectBytecodeAnalysis getInstance(@NotNull Project project) {
return ServiceManager.getService(project, ProjectBytecodeAnalysis.class);
@@ -54,6 +59,7 @@ public class ProjectBytecodeAnalysis {
public ProjectBytecodeAnalysis(Project project) {
myProject = project;
+ nullableMethodTransitivity = Registry.is(NULLABLE_METHOD_TRANSITIVITY);
}
@Nullable
@@ -101,6 +107,7 @@ public class ProjectBytecodeAnalysis {
ArrayList<HKey> allKeys = contractKeys((PsiMethod)listOwner, primaryKey);
MethodAnnotations methodAnnotations = loadMethodAnnotations((PsiMethod)listOwner, primaryKey, allKeys);
boolean notNull = methodAnnotations.notNulls.contains(primaryKey);
+ boolean nullable = methodAnnotations.nullables.contains(primaryKey);
String contractValue = methodAnnotations.contracts.get(primaryKey);
if (notNull && contractValue != null) {
return new PsiAnnotation[]{
@@ -108,11 +115,22 @@ public class ProjectBytecodeAnalysis {
createAnnotationFromText("@" + ControlFlowAnalyzer.ORG_JETBRAINS_ANNOTATIONS_CONTRACT + "(" + contractValue + ")")
};
}
+ if (nullable && contractValue != null) {
+ return new PsiAnnotation[]{
+ getNullableAnnotation(),
+ createAnnotationFromText("@" + ControlFlowAnalyzer.ORG_JETBRAINS_ANNOTATIONS_CONTRACT + "(" + contractValue + ")")
+ };
+ }
else if (notNull) {
return new PsiAnnotation[]{
getNotNullAnnotation()
};
}
+ else if (nullable) {
+ return new PsiAnnotation[]{
+ getNullableAnnotation()
+ };
+ }
else if (contractValue != null) {
return new PsiAnnotation[]{
createAnnotationFromText("@" + ControlFlowAnalyzer.ORG_JETBRAINS_ANNOTATIONS_CONTRACT + "(" + contractValue + ")")
@@ -172,7 +190,7 @@ public class ProjectBytecodeAnalysis {
public static HKey getKey(@NotNull PsiModifierListOwner owner, MessageDigest md) {
LOG.assertTrue(owner instanceof PsiCompiledElement, owner);
if (owner instanceof PsiMethod) {
- return BytecodeAnalysisConverter.psiKey((PsiMethod)owner, new Out(), md);
+ return BytecodeAnalysisConverter.psiKey((PsiMethod)owner, Out, md);
}
if (owner instanceof PsiParameter) {
PsiElement parent = owner.getParent();
@@ -196,16 +214,18 @@ public class ProjectBytecodeAnalysis {
private ParameterAnnotations loadParameterAnnotations(@NotNull HKey notNullKey)
throws EquationsLimitException {
- final Solver notNullSolver = new Solver(new ELattice<Value>(Value.NotNull, Value.Top));
- collectEquations(Collections.singletonList(notNullKey), notNullSolver);
+ Map<Bytes, List<HEquations>> equationsCache = new HashMap<Bytes, List<HEquations>>();
+
+ final Solver notNullSolver = new Solver(new ELattice<Value>(Value.NotNull, Value.Top), Value.Top);
+ collectEquations(Collections.singletonList(notNullKey), notNullSolver, equationsCache);
HashMap<HKey, Value> notNullSolutions = notNullSolver.solve();
boolean notNull =
(Value.NotNull == notNullSolutions.get(notNullKey)) || (Value.NotNull == notNullSolutions.get(notNullKey.mkUnstable()));
- final Solver nullableSolver = new Solver(new ELattice<Value>(Value.Null, Value.Top));
+ final Solver nullableSolver = new Solver(new ELattice<Value>(Value.Null, Value.Top), Value.Top);
final HKey nullableKey = new HKey(notNullKey.key, notNullKey.dirKey + 1, true);
- collectEquations(Collections.singletonList(nullableKey), nullableSolver);
+ collectEquations(Collections.singletonList(nullableKey), nullableSolver, equationsCache);
HashMap<HKey, Value> nullableSolutions = nullableSolver.solve();
boolean nullable =
(Value.Null == nullableSolutions.get(nullableKey)) || (Value.Null == nullableSolutions.get(nullableKey.mkUnstable()));
@@ -215,15 +235,32 @@ public class ProjectBytecodeAnalysis {
private MethodAnnotations loadMethodAnnotations(@NotNull PsiMethod owner, @NotNull HKey key, ArrayList<HKey> allKeys)
throws EquationsLimitException {
MethodAnnotations result = new MethodAnnotations();
- final Solver solver = new Solver(new ELattice<Value>(Value.Bot, Value.Top));
- collectEquations(allKeys, solver);
- HashMap<HKey, Value> solutions = solver.solve();
+ Map<Bytes, List<HEquations>> equationsCache = new HashMap<Bytes, List<HEquations>>();
+
+ final Solver outSolver = new Solver(new ELattice<Value>(Value.Bot, Value.Top), Value.Top);
+ collectEquations(allKeys, outSolver, equationsCache);
+ HashMap<HKey, Value> solutions = outSolver.solve();
int arity = owner.getParameterList().getParameters().length;
BytecodeAnalysisConverter.addMethodAnnotations(solutions, result, key, arity);
+
+ final Solver nullableMethodSolver = new Solver(new ELattice<Value>(Value.Bot, Value.Null), Value.Bot);
+ HKey nullableKey = key.updateDirection(BytecodeAnalysisConverter.mkDirectionKey(NullableOut));
+ if (nullableMethodTransitivity) {
+ collectEquations(Collections.singletonList(nullableKey), nullableMethodSolver, equationsCache);
+ }
+ else {
+ collectSingleEquation(nullableKey, nullableMethodSolver, equationsCache);
+ }
+
+ HashMap<HKey, Value> nullableSolutions = nullableMethodSolver.solve();
+ if (nullableSolutions.get(nullableKey) == Value.Null || nullableSolutions.get(nullableKey.negate()) == Value.Null) {
+ result.nullables.add(key);
+ }
return result;
}
- private void collectEquations(List<HKey> keys, Solver solver) throws EquationsLimitException {
+ private void collectEquations(List<HKey> keys, Solver solver, @NotNull Map<Bytes, List<HEquations>> cache) throws EquationsLimitException {
+
GlobalSearchScope librariesScope = ProjectScope.getLibrariesScope(myProject);
HashSet<HKey> queued = new HashSet<HKey>();
Stack<HKey> queue = new Stack<HKey>();
@@ -233,7 +270,6 @@ public class ProjectBytecodeAnalysis {
queued.add(key);
}
- HashMap<Bytes, List<HEquations>> cache = new HashMap<Bytes, List<HEquations>>();
FileBasedIndex index = FileBasedIndex.getInstance();
while (!queue.empty()) {
@@ -275,6 +311,32 @@ public class ProjectBytecodeAnalysis {
}
}
+ private void collectSingleEquation(HKey hKey, Solver solver, @NotNull Map<Bytes, List<HEquations>> cache) throws EquationsLimitException {
+ GlobalSearchScope librariesScope = ProjectScope.getLibrariesScope(myProject);
+
+ FileBasedIndex index = FileBasedIndex.getInstance();
+
+ ProgressManager.checkCanceled();
+ Bytes bytes = new Bytes(hKey.key);
+
+ List<HEquations> hEquationss = cache.get(bytes);
+ if (hEquationss == null) {
+ hEquationss = index.getValues(BytecodeAnalysisIndex.NAME, bytes, librariesScope);
+ cache.put(bytes, hEquationss);
+ }
+
+ for (HEquations hEquations : hEquationss) {
+ boolean stable = hEquations.stable;
+ for (DirectionResultPair pair : hEquations.results) {
+ int dirKey = pair.directionKey;
+ if (dirKey == hKey.dirKey) {
+ HResult result = pair.hResult;
+ solver.addEquation(new HEquation(new HKey(bytes.bytes, dirKey, stable), result));
+ }
+ }
+ }
+ }
+
@NotNull
private PsiAnnotation createAnnotationFromText(@NotNull final String text) throws IncorrectOperationException {
PsiAnnotation annotation = JavaPsiFacade.getElementFactory(myProject).createAnnotationFromText(text, null);
@@ -286,6 +348,8 @@ public class ProjectBytecodeAnalysis {
class MethodAnnotations {
// @NotNull keys
final HashSet<HKey> notNulls = new HashSet<HKey>();
+ // @Nullable keys
+ final HashSet<HKey> nullables = new HashSet<HKey>();
// @Contracts
final HashMap<HKey, String> contracts = new HashMap<HKey, String>();
}
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Solver.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Solver.java
index 21e749e12b29..1bc2c3a020e9 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Solver.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/Solver.java
@@ -265,9 +265,11 @@ final class Solver {
private final HResultUtil resultUtil;
private final HashMap<CoreHKey, HEquation> equations = new HashMap<CoreHKey, HEquation>();
+ private final Value unstableValue;
- Solver(ELattice<Value> lattice) {
+ Solver(ELattice<Value> lattice, Value unstableValue) {
this.lattice = lattice;
+ this.unstableValue = unstableValue;
resultUtil = new HResultUtil(lattice);
}
@@ -324,7 +326,7 @@ final class Solver {
Value value = solved.get(id);
HKey[] pIds = id.stable ? new HKey[]{id, id.negate()} : new HKey[]{id.negate(), id};
- Value[] pVals = id.stable ? new Value[]{value, value} : new Value[]{value, lattice.top};
+ Value[] pVals = id.stable ? new Value[]{value, value} : new Value[]{value, unstableValue};
for (int i = 0; i < pIds.length; i++) {
HKey pId = pIds[i];
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/AnalyzerExt.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/AnalyzerExt.java
new file mode 100644
index 000000000000..0fae8d9d4c6c
--- /dev/null
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/AnalyzerExt.java
@@ -0,0 +1,446 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInspection.bytecodeAnalysis.asm;
+
+import org.jetbrains.org.objectweb.asm.Opcodes;
+import org.jetbrains.org.objectweb.asm.Type;
+import org.jetbrains.org.objectweb.asm.tree.*;
+import org.jetbrains.org.objectweb.asm.tree.analysis.*;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Extended version of {@link org.jetbrains.org.objectweb.asm.tree.analysis.Analyzer}.
+ * It handles frames <b>and</b> additional data.
+ *
+ * @author lambdamix
+ */
+public class AnalyzerExt<V extends Value, Data, MyInterpreter extends Interpreter<V> & InterpreterExt<Data>> implements Opcodes {
+
+ private final MyInterpreter interpreter;
+
+ private int n;
+
+ private InsnList insns;
+
+ private List<TryCatchBlockNode>[] handlers;
+
+ private Frame<V>[] frames;
+
+ private Subroutine[] subroutines;
+
+ private boolean[] queued;
+
+ private int[] queue;
+
+ private int top;
+
+ public Data[] getData() {
+ return data;
+ }
+
+ private Data[] data;
+
+ public AnalyzerExt(final MyInterpreter interpreter, Data[] data, Data startData) {
+ this.interpreter = interpreter;
+ this.data = data;
+ if (data.length > 0) {
+ data[0] = startData;
+ }
+ }
+
+ public Frame<V>[] analyze(final String owner, final MethodNode m) throws AnalyzerException {
+ if ((m.access & (ACC_ABSTRACT | ACC_NATIVE)) != 0) {
+ frames = (Frame<V>[]) new Frame<?>[0];
+ return frames;
+ }
+ final V refV = (V) BasicValue.REFERENCE_VALUE;
+
+ n = m.instructions.size();
+ insns = m.instructions;
+ handlers = (List<TryCatchBlockNode>[]) new List<?>[n];
+ frames = (Frame<V>[]) new Frame<?>[n];
+ subroutines = new Subroutine[n];
+ queued = new boolean[n];
+ queue = new int[n];
+ top = 0;
+
+ // computes exception handlers for each instruction
+ for (int i = 0; i < m.tryCatchBlocks.size(); ++i) {
+ TryCatchBlockNode tcb = m.tryCatchBlocks.get(i);
+ int begin = insns.indexOf(tcb.start);
+ int end = insns.indexOf(tcb.end);
+ for (int j = begin; j < end; ++j) {
+ List<TryCatchBlockNode> insnHandlers = handlers[j];
+ if (insnHandlers == null) {
+ insnHandlers = new ArrayList<TryCatchBlockNode>();
+ handlers[j] = insnHandlers;
+ }
+ insnHandlers.add(tcb);
+ }
+ }
+
+ // computes the subroutine for each instruction:
+ Subroutine main = new Subroutine(null, m.maxLocals, null);
+ List<AbstractInsnNode> subroutineCalls = new ArrayList<AbstractInsnNode>();
+ Map<LabelNode, Subroutine> subroutineHeads = new HashMap<LabelNode, Subroutine>();
+ findSubroutine(0, main, subroutineCalls);
+ while (!subroutineCalls.isEmpty()) {
+ JumpInsnNode jsr = (JumpInsnNode) subroutineCalls.remove(0);
+ Subroutine sub = subroutineHeads.get(jsr.label);
+ if (sub == null) {
+ sub = new Subroutine(jsr.label, m.maxLocals, jsr);
+ subroutineHeads.put(jsr.label, sub);
+ findSubroutine(insns.indexOf(jsr.label), sub, subroutineCalls);
+ } else {
+ sub.callers.add(jsr);
+ }
+ }
+ for (int i = 0; i < n; ++i) {
+ if (subroutines[i] != null && subroutines[i].start == null) {
+ subroutines[i] = null;
+ }
+ }
+
+ // initializes the data structures for the control flow analysis
+ Frame<V> current = newFrame(m.maxLocals, m.maxStack);
+ Frame<V> handler = newFrame(m.maxLocals, m.maxStack);
+ current.setReturn(interpreter.newValue(Type.getReturnType(m.desc)));
+ Type[] args = Type.getArgumentTypes(m.desc);
+ int local = 0;
+ if ((m.access & ACC_STATIC) == 0) {
+ Type ctype = Type.getObjectType(owner);
+ current.setLocal(local++, interpreter.newValue(ctype));
+ }
+ for (int i = 0; i < args.length; ++i) {
+ current.setLocal(local++, interpreter.newValue(args[i]));
+ if (args[i].getSize() == 2) {
+ current.setLocal(local++, interpreter.newValue(null));
+ }
+ }
+ while (local < m.maxLocals) {
+ current.setLocal(local++, interpreter.newValue(null));
+ }
+
+ interpreter.init(data[0]);
+ merge(0, current, null);
+
+ init(owner, m);
+
+ // control flow analysis
+ while (top > 0) {
+ int insn = queue[--top];
+ Frame<V> f = frames[insn];
+ Subroutine subroutine = subroutines[insn];
+ queued[insn] = false;
+
+ AbstractInsnNode insnNode = null;
+ try {
+ insnNode = m.instructions.get(insn);
+ int insnOpcode = insnNode.getOpcode();
+ int insnType = insnNode.getType();
+
+ if (insnType == AbstractInsnNode.LABEL
+ || insnType == AbstractInsnNode.LINE
+ || insnType == AbstractInsnNode.FRAME) {
+ interpreter.init(data[insn]);
+ merge(insn + 1, f, subroutine);
+ newControlFlowEdge(insn, insn + 1);
+ } else {
+ // delta
+ interpreter.init(data[insn]);
+ current.init(f).execute(insnNode, interpreter);
+ subroutine = subroutine == null ? null : subroutine.copy();
+
+ if (insnNode instanceof JumpInsnNode) {
+ JumpInsnNode j = (JumpInsnNode) insnNode;
+ if (insnOpcode != GOTO && insnOpcode != JSR) {
+ merge(insn + 1, current, subroutine);
+ newControlFlowEdge(insn, insn + 1);
+ }
+ int jump = insns.indexOf(j.label);
+ if (insnOpcode == JSR) {
+ merge(jump, current, new Subroutine(j.label,
+ m.maxLocals, j));
+ } else {
+ merge(jump, current, subroutine);
+ }
+ newControlFlowEdge(insn, jump);
+ } else if (insnNode instanceof LookupSwitchInsnNode) {
+ LookupSwitchInsnNode lsi = (LookupSwitchInsnNode) insnNode;
+ int jump = insns.indexOf(lsi.dflt);
+ merge(jump, current, subroutine);
+ newControlFlowEdge(insn, jump);
+ for (int j = 0; j < lsi.labels.size(); ++j) {
+ LabelNode label = lsi.labels.get(j);
+ jump = insns.indexOf(label);
+ merge(jump, current, subroutine);
+ newControlFlowEdge(insn, jump);
+ }
+ } else if (insnNode instanceof TableSwitchInsnNode) {
+ TableSwitchInsnNode tsi = (TableSwitchInsnNode) insnNode;
+ int jump = insns.indexOf(tsi.dflt);
+ merge(jump, current, subroutine);
+ newControlFlowEdge(insn, jump);
+ for (int j = 0; j < tsi.labels.size(); ++j) {
+ LabelNode label = tsi.labels.get(j);
+ jump = insns.indexOf(label);
+ merge(jump, current, subroutine);
+ newControlFlowEdge(insn, jump);
+ }
+ } else if (insnOpcode == RET) {
+ if (subroutine == null) {
+ throw new AnalyzerException(insnNode,
+ "RET instruction outside of a sub routine");
+ }
+ for (int i = 0; i < subroutine.callers.size(); ++i) {
+ JumpInsnNode caller = subroutine.callers.get(i);
+ int call = insns.indexOf(caller);
+ if (frames[call] != null) {
+ merge(call + 1, frames[call], current,
+ subroutines[call], subroutine.access);
+ newControlFlowEdge(insn, call + 1);
+ }
+ }
+ } else if (insnOpcode != ATHROW && (insnOpcode < IRETURN || insnOpcode > RETURN)) {
+ if (subroutine != null) {
+ if (insnNode instanceof VarInsnNode) {
+ int var = ((VarInsnNode) insnNode).var;
+ subroutine.access[var] = true;
+ if (insnOpcode == LLOAD || insnOpcode == DLOAD
+ || insnOpcode == LSTORE
+ || insnOpcode == DSTORE) {
+ subroutine.access[var + 1] = true;
+ }
+ } else if (insnNode instanceof IincInsnNode) {
+ int var = ((IincInsnNode) insnNode).var;
+ subroutine.access[var] = true;
+ }
+ }
+ merge(insn + 1, current, subroutine);
+ newControlFlowEdge(insn, insn + 1);
+ }
+ }
+
+ List<TryCatchBlockNode> insnHandlers = handlers[insn];
+ if (insnHandlers != null) {
+ for (int i = 0; i < insnHandlers.size(); ++i) {
+ TryCatchBlockNode tcb = insnHandlers.get(i);
+ int jump = insns.indexOf(tcb.handler);
+ if (newControlFlowExceptionEdge(insn, tcb)) {
+ handler.init(f);
+ handler.clearStack();
+ handler.push(refV);
+ merge(jump, handler, subroutine);
+ }
+ }
+ }
+ } catch (AnalyzerException e) {
+ throw new AnalyzerException(e.node, "Error at instruction "
+ + insn + ": " + e.getMessage(), e);
+ } catch (Exception e) {
+ throw new AnalyzerException(insnNode, "Error at instruction "
+ + insn + ": " + e.getMessage(), e);
+ }
+ }
+
+ return frames;
+ }
+
+ private void findSubroutine(int insn, final Subroutine sub,
+ final List<AbstractInsnNode> calls) throws AnalyzerException {
+ while (true) {
+ if (insn < 0 || insn >= n) {
+ throw new AnalyzerException(null,
+ "Execution can fall off end of the code");
+ }
+ if (subroutines[insn] != null) {
+ return;
+ }
+ subroutines[insn] = sub.copy();
+ AbstractInsnNode node = insns.get(insn);
+
+ // calls findSubroutine recursively on normal successors
+ if (node instanceof JumpInsnNode) {
+ if (node.getOpcode() == JSR) {
+ // do not follow a JSR, it leads to another subroutine!
+ calls.add(node);
+ } else {
+ JumpInsnNode jnode = (JumpInsnNode) node;
+ findSubroutine(insns.indexOf(jnode.label), sub, calls);
+ }
+ } else if (node instanceof TableSwitchInsnNode) {
+ TableSwitchInsnNode tsnode = (TableSwitchInsnNode) node;
+ findSubroutine(insns.indexOf(tsnode.dflt), sub, calls);
+ for (int i = tsnode.labels.size() - 1; i >= 0; --i) {
+ LabelNode l = tsnode.labels.get(i);
+ findSubroutine(insns.indexOf(l), sub, calls);
+ }
+ } else if (node instanceof LookupSwitchInsnNode) {
+ LookupSwitchInsnNode lsnode = (LookupSwitchInsnNode) node;
+ findSubroutine(insns.indexOf(lsnode.dflt), sub, calls);
+ for (int i = lsnode.labels.size() - 1; i >= 0; --i) {
+ LabelNode l = lsnode.labels.get(i);
+ findSubroutine(insns.indexOf(l), sub, calls);
+ }
+ }
+
+ // calls findSubroutine recursively on exception handler successors
+ List<TryCatchBlockNode> insnHandlers = handlers[insn];
+ if (insnHandlers != null) {
+ for (int i = 0; i < insnHandlers.size(); ++i) {
+ TryCatchBlockNode tcb = insnHandlers.get(i);
+ findSubroutine(insns.indexOf(tcb.handler), sub, calls);
+ }
+ }
+
+ // if insn does not falls through to the next instruction, return.
+ switch (node.getOpcode()) {
+ case GOTO:
+ case RET:
+ case TABLESWITCH:
+ case LOOKUPSWITCH:
+ case IRETURN:
+ case LRETURN:
+ case FRETURN:
+ case DRETURN:
+ case ARETURN:
+ case RETURN:
+ case ATHROW:
+ return;
+ }
+ insn++;
+ }
+ }
+
+ public Frame<V>[] getFrames() {
+ return frames;
+ }
+
+ public List<TryCatchBlockNode> getHandlers(final int insn) {
+ return handlers[insn];
+ }
+
+ protected void init(String owner, MethodNode m) throws AnalyzerException {
+ }
+
+ protected Frame<V> newFrame(final int nLocals, final int nStack) {
+ return new Frame<V>(nLocals, nStack);
+ }
+
+ protected Frame<V> newFrame(final Frame<? extends V> src) {
+ return new Frame<V>(src);
+ }
+
+ protected void newControlFlowEdge(final int insn, final int successor) {
+ }
+
+ protected boolean newControlFlowExceptionEdge(final int insn,
+ final int successor) {
+ return true;
+ }
+
+ protected boolean newControlFlowExceptionEdge(final int insn,
+ final TryCatchBlockNode tcb) {
+ return newControlFlowExceptionEdge(insn, insns.indexOf(tcb.handler));
+ }
+
+ // -------------------------------------------------------------------------
+
+ private void merge(final int insn, final Frame<V> frame,
+ final Subroutine subroutine) throws AnalyzerException {
+ Frame<V> oldFrame = frames[insn];
+ Subroutine oldSubroutine = subroutines[insn];
+ boolean changes;
+
+ if (oldFrame == null) {
+ frames[insn] = newFrame(frame);
+ changes = true;
+ } else {
+ changes = oldFrame.merge(frame, interpreter);
+ }
+
+ if (oldSubroutine == null) {
+ if (subroutine != null) {
+ subroutines[insn] = subroutine.copy();
+ changes = true;
+ }
+ } else {
+ if (subroutine != null) {
+ changes |= oldSubroutine.merge(subroutine);
+ }
+ }
+ if (changes && !queued[insn]) {
+ queued[insn] = true;
+ queue[top++] = insn;
+ }
+
+ // delta
+ mergeData(insn, interpreter);
+ }
+
+ private void merge(final int insn, final Frame<V> beforeJSR,
+ final Frame<V> afterRET, final Subroutine subroutineBeforeJSR,
+ final boolean[] access) throws AnalyzerException {
+ Frame<V> oldFrame = frames[insn];
+ Subroutine oldSubroutine = subroutines[insn];
+ boolean changes;
+
+ afterRET.merge(beforeJSR, access);
+
+ if (oldFrame == null) {
+ frames[insn] = newFrame(afterRET);
+ changes = true;
+ } else {
+ changes = oldFrame.merge(afterRET, interpreter);
+ }
+
+ if (oldSubroutine != null && subroutineBeforeJSR != null) {
+ changes |= oldSubroutine.merge(subroutineBeforeJSR);
+ }
+ if (changes && !queued[insn]) {
+ queued[insn] = true;
+ queue[top++] = insn;
+ }
+
+ // delta
+ mergeData(insn, interpreter);
+ }
+
+ private void mergeData(int insn, MyInterpreter interpreter) {
+ boolean changes = false;
+
+ Data oldData = data[insn];
+ Data newData = interpreter.getAfterData(insn);
+
+ if (oldData == null) {
+ data[insn] = newData;
+ changes = true;
+ } else if (newData != null) {
+ Data mergedData = interpreter.merge(oldData, newData);
+ data[insn] = mergedData;
+ changes = !oldData.equals(mergedData);
+ }
+
+ if (changes && !queued[insn]) {
+ queued[insn] = true;
+ queue[top++] = insn;
+ }
+ }
+}
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/FramelessAnalyzer.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/FramelessAnalyzer.java
index 5804723e9ec1..ae1c7b819cb8 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/FramelessAnalyzer.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/FramelessAnalyzer.java
@@ -31,52 +31,6 @@ import java.util.Map;
* So, the main point here is handling of subroutines (jsr) and try-catch-finally blocks.
*/
public class FramelessAnalyzer implements Opcodes {
- static class Subroutine {
-
- LabelNode start;
- boolean[] access;
- List<JumpInsnNode> callers;
-
- private Subroutine() {
- }
-
- Subroutine(@Nullable final LabelNode start, final int maxLocals,
- @Nullable final JumpInsnNode caller) {
- this.start = start;
- this.access = new boolean[maxLocals];
- this.callers = new ArrayList<JumpInsnNode>();
- callers.add(caller);
- }
-
- public Subroutine copy() {
- Subroutine result = new Subroutine();
- result.start = start;
- result.access = new boolean[access.length];
- System.arraycopy(access, 0, result.access, 0, access.length);
- result.callers = new ArrayList<JumpInsnNode>(callers);
- return result;
- }
-
- public boolean merge(final Subroutine subroutine) throws AnalyzerException {
- boolean changes = false;
- for (int i = 0; i < access.length; ++i) {
- if (subroutine.access[i] && !access[i]) {
- access[i] = true;
- changes = true;
- }
- }
- if (subroutine.start == start) {
- for (int i = 0; i < subroutine.callers.size(); ++i) {
- JumpInsnNode caller = subroutine.callers.get(i);
- if (!callers.contains(caller)) {
- callers.add(caller);
- changes = true;
- }
- }
- }
- return changes;
- }
- }
private int n;
private InsnList insns;
private List<TryCatchBlockNode>[] handlers;
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/InterpreterExt.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/InterpreterExt.java
new file mode 100644
index 000000000000..5b284a074882
--- /dev/null
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/InterpreterExt.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInspection.bytecodeAnalysis.asm;
+
+/**
+ * @author lambdamix
+ */
+public interface InterpreterExt<Data> { // self: Interpreter[_] =>
+
+ // init interpreter state by passing entry data
+ void init(Data previous);
+
+ // exit data after execution for edge to insn
+ // there are may be different outcomes for different edges if an instruction was branching one
+ Data getAfterData(int insn);
+
+ // merge two states
+ Data merge(Data data1, Data data2);
+}
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/LeakingParameters.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/LeakingParameters.java
index 1a7ab15722f9..97b129b9c774 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/LeakingParameters.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/LeakingParameters.java
@@ -262,7 +262,7 @@ class ParametersUsage extends Interpreter<ParamsValue> {
@Override
public ParamsValue ternaryOperation(AbstractInsnNode insn, ParamsValue value1, ParamsValue value2, ParamsValue value3) {
- return val1;
+ return null;
}
@Override
@@ -458,7 +458,7 @@ class IParametersUsage extends Interpreter<IParamsValue> {
break;
default:
}
- return val1;
+ return null;
}
@Override
@@ -560,6 +560,7 @@ class LeakingParametersCollector extends ParametersUsage {
@Override
public ParamsValue ternaryOperation(AbstractInsnNode insn, ParamsValue value1, ParamsValue value2, ParamsValue value3) {
+ boolean[] params;
switch (insn.getOpcode()) {
case IASTORE:
case LASTORE:
@@ -568,7 +569,7 @@ class LeakingParametersCollector extends ParametersUsage {
case BASTORE:
case CASTORE:
case SASTORE:
- boolean[] params = value1.params;
+ params = value1.params;
for (int i = 0; i < arity; i++) {
leaking[i] |= params[i];
}
@@ -585,7 +586,7 @@ class LeakingParametersCollector extends ParametersUsage {
break;
default:
}
- return super.ternaryOperation(insn, value1, value2, value3);
+ return null;
}
@Override
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/LiteAnalyzerExt.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/LiteAnalyzerExt.java
new file mode 100644
index 000000000000..06dd39ffab96
--- /dev/null
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/LiteAnalyzerExt.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInspection.bytecodeAnalysis.asm;
+
+import org.jetbrains.org.objectweb.asm.Opcodes;
+import org.jetbrains.org.objectweb.asm.Type;
+import org.jetbrains.org.objectweb.asm.tree.*;
+import org.jetbrains.org.objectweb.asm.tree.analysis.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Extended version of {@link com.intellij.codeInspection.bytecodeAnalysis.asm.LiteAnalyzer}.
+ * It handles frames <b>and</b> additional data.
+ *
+ * @author lambdamix
+ */
+public class LiteAnalyzerExt<V extends Value, Data, MyInterpreter extends Interpreter<V> & InterpreterExt<Data>> implements Opcodes {
+
+ private final MyInterpreter interpreter;
+ private Frame<V>[] frames;
+ private boolean[] queued;
+ private int[] queue;
+ private int top;
+
+ public Data[] getData() {
+ return data;
+ }
+
+ private Data[] data;
+
+ public LiteAnalyzerExt(final MyInterpreter interpreter, Data[] data, Data startData) {
+ this.interpreter = interpreter;
+ this.data = data;
+ if (data.length > 0) {
+ data[0] = startData;
+ }
+ }
+
+ public Frame<V>[] analyze(final String owner, final MethodNode m) throws AnalyzerException {
+ if ((m.access & (ACC_ABSTRACT | ACC_NATIVE)) != 0) {
+ frames = (Frame<V>[]) new Frame<?>[0];
+ return frames;
+ }
+
+ final V refV = (V) BasicValue.REFERENCE_VALUE;
+
+ int n = m.instructions.size();
+ InsnList insns = m.instructions;
+ List<TryCatchBlockNode>[] handlers = (List<TryCatchBlockNode>[]) new List<?>[n];
+ frames = (Frame<V>[]) new Frame<?>[n];
+ queued = new boolean[n];
+ queue = new int[n];
+ top = 0;
+
+ // computes exception handlers for each instruction
+ for (int i = 0; i < m.tryCatchBlocks.size(); ++i) {
+ TryCatchBlockNode tcb = m.tryCatchBlocks.get(i);
+ int begin = insns.indexOf(tcb.start);
+ int end = insns.indexOf(tcb.end);
+ for (int j = begin; j < end; ++j) {
+ List<TryCatchBlockNode> insnHandlers = handlers[j];
+ if (insnHandlers == null) {
+ insnHandlers = new ArrayList<TryCatchBlockNode>();
+ handlers[j] = insnHandlers;
+ }
+ insnHandlers.add(tcb);
+ }
+ }
+
+ // initializes the data structures for the control flow analysis
+ Frame<V> current = newFrame(m.maxLocals, m.maxStack);
+ Frame<V> handler = newFrame(m.maxLocals, m.maxStack);
+ current.setReturn(interpreter.newValue(Type.getReturnType(m.desc)));
+ Type[] args = Type.getArgumentTypes(m.desc);
+ int local = 0;
+ if ((m.access & ACC_STATIC) == 0) {
+ Type ctype = Type.getObjectType(owner);
+ current.setLocal(local++, interpreter.newValue(ctype));
+ }
+ for (int i = 0; i < args.length; ++i) {
+ current.setLocal(local++, interpreter.newValue(args[i]));
+ if (args[i].getSize() == 2) {
+ current.setLocal(local++, interpreter.newValue(null));
+ }
+ }
+ while (local < m.maxLocals) {
+ current.setLocal(local++, interpreter.newValue(null));
+ }
+
+ interpreter.init(data[0]);
+ merge(0, current);
+
+ // control flow analysis
+ while (top > 0) {
+ int insn = queue[--top];
+ Frame<V> f = frames[insn];
+ queued[insn] = false;
+
+ AbstractInsnNode insnNode = null;
+ try {
+ insnNode = m.instructions.get(insn);
+ int insnOpcode = insnNode.getOpcode();
+ int insnType = insnNode.getType();
+
+ if (insnType == AbstractInsnNode.LABEL || insnType == AbstractInsnNode.LINE || insnType == AbstractInsnNode.FRAME) {
+ interpreter.init(data[insn]);
+ merge(insn + 1, f);
+ } else {
+ // delta
+ interpreter.init(data[insn]);
+ current.init(f).execute(insnNode, interpreter);
+
+ if (insnNode instanceof JumpInsnNode) {
+ JumpInsnNode j = (JumpInsnNode) insnNode;
+ if (insnOpcode != GOTO && insnOpcode != JSR) {
+ merge(insn + 1, current);
+ }
+ int jump = insns.indexOf(j.label);
+ merge(jump, current);
+ } else if (insnNode instanceof LookupSwitchInsnNode) {
+ LookupSwitchInsnNode lsi = (LookupSwitchInsnNode) insnNode;
+ int jump = insns.indexOf(lsi.dflt);
+ merge(jump, current);
+ for (int j = 0; j < lsi.labels.size(); ++j) {
+ LabelNode label = lsi.labels.get(j);
+ jump = insns.indexOf(label);
+ merge(jump, current);
+ }
+ } else if (insnNode instanceof TableSwitchInsnNode) {
+ TableSwitchInsnNode tsi = (TableSwitchInsnNode) insnNode;
+ int jump = insns.indexOf(tsi.dflt);
+ merge(jump, current);
+ for (int j = 0; j < tsi.labels.size(); ++j) {
+ LabelNode label = tsi.labels.get(j);
+ jump = insns.indexOf(label);
+ merge(jump, current);
+ }
+ } else if (insnOpcode != ATHROW
+ && (insnOpcode < IRETURN || insnOpcode > RETURN)) {
+ merge(insn + 1, current);
+ }
+ }
+
+ List<TryCatchBlockNode> insnHandlers = handlers[insn];
+ if (insnHandlers != null) {
+ for (int i = 0; i < insnHandlers.size(); ++i) {
+ TryCatchBlockNode tcb = insnHandlers.get(i);
+ int jump = insns.indexOf(tcb.handler);
+ handler.init(f);
+ handler.clearStack();
+ handler.push(refV);
+ merge(jump, handler);
+ }
+ }
+ } catch (AnalyzerException e) {
+ throw new AnalyzerException(e.node, "Error at instruction " + insn + ": " + e.getMessage(), e);
+ } catch (Exception e) {
+ throw new AnalyzerException(insnNode, "Error at instruction " + insn + ": " + e.getMessage(), e);
+ }
+ }
+
+ return frames;
+ }
+
+ public Frame<V>[] getFrames() {
+ return frames;
+ }
+
+ protected Frame<V> newFrame(final int nLocals, final int nStack) {
+ return new Frame<V>(nLocals, nStack);
+ }
+
+ protected Frame<V> newFrame(final Frame<? extends V> src) {
+ return new Frame<V>(src);
+ }
+
+ // -------------------------------------------------------------------------
+
+ private void merge(final int insn, final Frame<V> frame) throws AnalyzerException {
+ Frame<V> oldFrame = frames[insn];
+ boolean changes;
+
+ if (oldFrame == null) {
+ frames[insn] = newFrame(frame);
+ changes = true;
+ } else {
+ changes = oldFrame.merge(frame, interpreter);
+ }
+
+ Data oldData = data[insn];
+ Data newData = interpreter.getAfterData(insn);
+
+ if (oldData == null) {
+ data[insn] = newData;
+ changes = true;
+ } else if (newData != null) {
+ Data mergedData = interpreter.merge(oldData, newData);
+ data[insn] = mergedData;
+ changes |= !oldData.equals(mergedData);
+ }
+
+ if (changes && !queued[insn]) {
+ queued[insn] = true;
+ queue[top++] = insn;
+ }
+ }
+}
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/LiteFramelessAnalyzer.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/LiteFramelessAnalyzer.java
index 0a9721018862..3cfb1ae51feb 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/LiteFramelessAnalyzer.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/LiteFramelessAnalyzer.java
@@ -29,11 +29,11 @@ import java.util.List;
public class LiteFramelessAnalyzer extends FramelessAnalyzer {
@Override
- protected void findSubroutine(int insn, FramelessAnalyzer.Subroutine sub, List<AbstractInsnNode> calls) throws AnalyzerException {
+ protected void findSubroutine(int insn, Subroutine sub, List<AbstractInsnNode> calls) throws AnalyzerException {
}
@Override
- protected void merge(final int insn, final FramelessAnalyzer.Subroutine subroutine) throws AnalyzerException {
+ protected void merge(final int insn, final Subroutine subroutine) throws AnalyzerException {
if (!wasQueued[insn]) {
wasQueued[insn] = true;
if (!queued[insn]) {
@@ -44,7 +44,7 @@ public class LiteFramelessAnalyzer extends FramelessAnalyzer {
}
@Override
- protected void merge(final int insn, final FramelessAnalyzer.Subroutine subroutineBeforeJSR, final boolean[] access) throws AnalyzerException {
+ protected void merge(final int insn, final Subroutine subroutineBeforeJSR, final boolean[] access) throws AnalyzerException {
if (!wasQueued[insn]) {
wasQueued[insn] = true;
if (!queued[insn]) {
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/Subroutine.java b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/Subroutine.java
new file mode 100644
index 000000000000..a484b1b1fdb1
--- /dev/null
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/bytecodeAnalysis/asm/Subroutine.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInspection.bytecodeAnalysis.asm;
+
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.org.objectweb.asm.tree.JumpInsnNode;
+import org.jetbrains.org.objectweb.asm.tree.LabelNode;
+import org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author lambdamix
+ */
+public class Subroutine {
+
+ LabelNode start;
+ boolean[] access;
+ List<JumpInsnNode> callers;
+
+ private Subroutine() {
+ }
+
+ Subroutine(@Nullable final LabelNode start, final int maxLocals,
+ @Nullable final JumpInsnNode caller) {
+ this.start = start;
+ this.access = new boolean[maxLocals];
+ this.callers = new ArrayList<JumpInsnNode>();
+ callers.add(caller);
+ }
+
+ public Subroutine copy() {
+ Subroutine result = new Subroutine();
+ result.start = start;
+ result.access = new boolean[access.length];
+ System.arraycopy(access, 0, result.access, 0, access.length);
+ result.callers = new ArrayList<JumpInsnNode>(callers);
+ return result;
+ }
+
+ public boolean merge(final Subroutine subroutine) throws AnalyzerException {
+ boolean changes = false;
+ for (int i = 0; i < access.length; ++i) {
+ if (subroutine.access[i] && !access[i]) {
+ access[i] = true;
+ changes = true;
+ }
+ }
+ if (subroutine.start == start) {
+ for (int i = 0; i < subroutine.callers.size(); ++i) {
+ JumpInsnNode caller = subroutine.callers.get(i);
+ if (!callers.contains(caller)) {
+ callers.add(caller);
+ changes = true;
+ }
+ }
+ }
+ return changes;
+ }
+}
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInference.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInference.java
index 7037fac8cfea..f919ac5f8796 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInference.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ContractInference.java
@@ -31,6 +31,7 @@ import com.siyeh.ig.psiutils.SideEffectChecker;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -59,12 +60,27 @@ public class ContractInference {
class ContractInferenceInterpreter {
private final PsiMethod myMethod;
+ private final ValueConstraint[] myEmptyConstraints;
public ContractInferenceInterpreter(PsiMethod method) {
myMethod = method;
+ myEmptyConstraints = MethodContract.createConstraintArray(myMethod.getParameterList().getParametersCount());
}
List<MethodContract> inferContracts() {
+ final boolean notNull = NullableNotNullManager.isNotNull(myMethod);
+ return ContainerUtil.filter(doInferContracts(), new Condition<MethodContract>() {
+ @Override
+ public boolean value(MethodContract contract) {
+ if (notNull && contract.returnValue == NOT_NULL_VALUE && Arrays.equals(contract.arguments, myEmptyConstraints)) {
+ return false;
+ }
+ return true;
+ }
+ });
+ }
+
+ private List<MethodContract> doInferContracts() {
PsiCodeBlock body = myMethod.getBody();
PsiStatement[] statements = body == null ? PsiStatement.EMPTY_ARRAY : body.getStatements();
if (statements.length == 0) return Collections.emptyList();
@@ -101,8 +117,7 @@ class ContractInferenceInterpreter {
}
}
- ValueConstraint[] emptyState = MethodContract.createConstraintArray(myMethod.getParameterList().getParametersCount());
- return visitStatements(Collections.singletonList(emptyState), statements);
+ return visitStatements(Collections.singletonList(myEmptyConstraints), statements);
}
@Nullable
@@ -130,12 +145,12 @@ class ContractInferenceInterpreter {
return RecursionManager.doPreventingRecursion(myMethod, true, new Computable<List<MethodContract>>() {
@Override
public List<MethodContract> compute() {
- List<MethodContract> delegateContracts = ControlFlowAnalyzer.getMethodContracts(targetMethod);
- return ContainerUtil.mapNotNull(delegateContracts, new NullableFunction<MethodContract, MethodContract>() {
+ final boolean notNull = NullableNotNullManager.isNotNull(targetMethod);
+ List<MethodContract> fromDelegate = ContainerUtil.mapNotNull(ControlFlowAnalyzer.getMethodContracts(targetMethod), new NullableFunction<MethodContract, MethodContract>() {
@Nullable
@Override
public MethodContract fun(MethodContract delegateContract) {
- ValueConstraint[] answer = MethodContract.createConstraintArray(myMethod.getParameterList().getParametersCount());
+ ValueConstraint[] answer = myEmptyConstraints;
for (int i = 0; i < delegateContract.arguments.length; i++) {
if (i >= arguments.length) return null;
@@ -155,9 +170,17 @@ class ContractInferenceInterpreter {
}
}
}
- return answer == null ? null : new MethodContract(answer, negated ? negateConstraint(delegateContract.returnValue) : delegateContract.returnValue);
+ ValueConstraint returnValue = negated ? negateConstraint(delegateContract.returnValue) : delegateContract.returnValue;
+ if (notNull && returnValue != THROW_EXCEPTION) {
+ returnValue = NOT_NULL_VALUE;
+ }
+ return answer == null ? null : new MethodContract(answer, returnValue);
}
});
+ if (notNull) {
+ return ContainerUtil.concat(fromDelegate, Arrays.asList(new MethodContract(myEmptyConstraints, NOT_NULL_VALUE)));
+ }
+ return fromDelegate;
}
});
}
@@ -370,12 +393,6 @@ class ContractInferenceInterpreter {
else if (statement instanceof PsiDoWhileStatement) {
result.addAll(visitStatements(states, ((PsiDoWhileStatement)statement).getBody()));
}
- else if (statement instanceof PsiTryStatement) {
- PsiCodeBlock block = ((PsiTryStatement)statement).getTryBlock();
- if (block != null) {
- result.addAll(visitStatements(states, block.getStatements()));
- }
- }
break; // visit only the first statement unless it's 'if' whose 'then' always returns and the next statement is effectively 'else'
}
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java
index 7539d7195701..92777dd659e0 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/ControlFlowAnalyzer.java
@@ -1434,6 +1434,10 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
final PsiAnnotation contractAnno = findContractAnnotation(method);
final int paramCount = method.getParameterList().getParametersCount();
if (contractAnno != null) {
+ if (AnnotationUtil.isInferredAnnotation(contractAnno) && PsiUtil.canBeOverriden(method)) {
+ return Collections.emptyList();
+ }
+
return CachedValuesManager.getCachedValue(contractAnno, new CachedValueProvider<List<MethodContract>>() {
@Nullable
@Override
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java
index 36449128b494..96102b53f5d4 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/StandardInstructionVisitor.java
@@ -70,7 +70,9 @@ public class StandardInstructionVisitor extends InstructionVisitor {
DfaValueFactory factory = runner.getFactory();
if (dfaSource instanceof DfaVariableValue && factory.getVarFactory().getAllQualifiedBy(var).contains(dfaSource)) {
- dfaSource = factory.createTypeValue(((DfaVariableValue)dfaSource).getVariableType(), ((DfaVariableValue)dfaSource).getInherentNullability());
+ Nullness nullability = memState.isNotNull(dfaSource) ? Nullness.NOT_NULL
+ : ((DfaVariableValue)dfaSource).getInherentNullability();
+ dfaSource = factory.createTypeValue(((DfaVariableValue)dfaSource).getVariableType(), nullability);
}
if (var.getInherentNullability() == Nullness.NOT_NULL) {
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaExpressionFactory.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaExpressionFactory.java
index 7ebce779c3a8..9b32f8a4c000 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaExpressionFactory.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaExpressionFactory.java
@@ -19,6 +19,7 @@ import com.intellij.codeInspection.dataFlow.DfaPsiUtil;
import com.intellij.codeInspection.dataFlow.Nullness;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Condition;
+import com.intellij.openapi.util.Conditions;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.psi.*;
import com.intellij.psi.impl.JavaConstantExpressionEvaluator;
@@ -50,8 +51,7 @@ public class DfaExpressionFactory {
}
catch (Exception e) {
LOG.error(e);
- //noinspection unchecked
- return Condition.FALSE;
+ return Conditions.alwaysFalse();
}
}
diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/equalsAndHashcode/EqualsAndHashcode.java b/java/java-analysis-impl/src/com/intellij/codeInspection/equalsAndHashcode/EqualsAndHashcodeBase.java
index 4c41d90a9afa..6a5f0627d5e1 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInspection/equalsAndHashcode/EqualsAndHashcode.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInspection/equalsAndHashcode/EqualsAndHashcodeBase.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2011 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,10 +15,7 @@
*/
package com.intellij.codeInspection.equalsAndHashcode;
-import com.intellij.codeInspection.BaseJavaBatchLocalInspectionTool;
-import com.intellij.codeInspection.InspectionsBundle;
-import com.intellij.codeInspection.LocalQuickFix;
-import com.intellij.codeInspection.ProblemsHolder;
+import com.intellij.codeInspection.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectRootManager;
@@ -36,10 +33,10 @@ import org.jetbrains.annotations.Nullable;
/**
* @author max
*/
-public class EqualsAndHashcode extends BaseJavaBatchLocalInspectionTool {
+public class EqualsAndHashcodeBase extends BaseJavaBatchLocalInspectionTool {
@Override
@NotNull
- public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
+ public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, final boolean isOnTheFly) {
final Project project = holder.getProject();
Pair<PsiMethod, PsiMethod> pair = CachedValuesManager.getManager(project).getCachedValue(project, new CachedValueProvider<Pair<PsiMethod, PsiMethod>>() {
@Override
@@ -92,7 +89,7 @@ public class EqualsAndHashcode extends BaseJavaBatchLocalInspectionTool {
hasEquals[0]
? InspectionsBundle.message("inspection.equals.hashcode.only.one.defined.problem.descriptor", "<code>equals()</code>", "<code>hashCode()</code>")
: InspectionsBundle.message("inspection.equals.hashcode.only.one.defined.problem.descriptor","<code>hashCode()</code>", "<code>equals()</code>"),
- (LocalQuickFix[])null);
+ buildFixes(isOnTheFly, hasEquals[0]));
}
}
};
@@ -130,4 +127,8 @@ public class EqualsAndHashcode extends BaseJavaBatchLocalInspectionTool {
public String getShortName() {
return "EqualsAndHashcode";
}
+
+ protected LocalQuickFix[] buildFixes(boolean isOnTheFly, boolean hasEquals) {
+ return LocalQuickFix.EMPTY_ARRAY;
+ }
}
diff --git a/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java b/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java
index 08a071231410..0bf1c1cd7218 100644
--- a/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java
+++ b/java/java-impl/src/com/intellij/codeInsight/ExpectedTypesProvider.java
@@ -31,7 +31,10 @@ import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PsiShortNamesCache;
import com.intellij.psi.search.searches.DeepestSuperMethodsSearch;
import com.intellij.psi.tree.IElementType;
-import com.intellij.psi.util.*;
+import com.intellij.psi.util.PropertyUtil;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.util.PsiUtil;
+import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.NullableFunction;
import com.intellij.util.Processor;
@@ -126,10 +129,6 @@ public class ExpectedTypesProvider {
final boolean voidable, boolean usedAfter) {
if (expr == null) return ExpectedTypeInfo.EMPTY_ARRAY;
PsiElement parent = expr.getParent();
- while (parent instanceof PsiParenthesizedExpression) {
- expr = (PsiExpression)parent;
- parent = parent.getParent();
- }
MyParentVisitor visitor = new MyParentVisitor(expr, forCompletion, classProvider, voidable, usedAfter);
if (parent != null) {
parent.accept(visitor);
@@ -243,6 +242,25 @@ public class ExpectedTypesProvider {
}
@Override
+ public void visitParenthesizedExpression(PsiParenthesizedExpression expression) {
+ PsiElement parent = expression.getParent();
+ if (parent != null) {
+ final MyParentVisitor visitor = new MyParentVisitor(expression, myForCompletion, myClassProvider, myVoidable, myUsedAfter);
+ parent.accept(visitor);
+ for (final ExpectedTypeInfo info : visitor.myResult) {
+ myResult.add(createInfoImpl(info.getType(), info.getKind(), info.getDefaultType(), TailTypes.RPARENTH, info.getCalledMethod(),
+ new NullableComputable<String>() {
+ @Nullable
+ @Override
+ public String compute() {
+ return ((ExpectedTypeInfoImpl)info).getExpectedName();
+ }
+ }));
+ }
+ }
+ }
+
+ @Override
public void visitAnnotationMethod(@NotNull final PsiAnnotationMethod method) {
if (myExpr == method.getDefaultValue()) {
final PsiType type = method.getReturnType();
diff --git a/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsLineMarkerProvider.java b/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsLineMarkerProvider.java
index e373207222ea..8605a8f91a83 100644
--- a/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsLineMarkerProvider.java
+++ b/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsLineMarkerProvider.java
@@ -51,14 +51,14 @@ public class ExternalAnnotationsLineMarkerProvider implements LineMarkerProvider
if (!(element instanceof PsiModifierListOwner)) return null;
if (element instanceof PsiParameter || element instanceof PsiLocalVariable) return null;
- if (!shouldShowSignature(preferCompiledElement((PsiModifierListOwner)element))) {
+ if (!shouldShowSignature((PsiModifierListOwner)element)) {
return null;
}
final Function<PsiModifierListOwner, String> annotationsCollector = new Function<PsiModifierListOwner, String>() {
@Override
public String fun(PsiModifierListOwner owner) {
- return XmlStringUtil.wrapInHtml(JavaDocInfoGenerator.generateSignature(preferCompiledElement(owner)));
+ return XmlStringUtil.wrapInHtml(JavaDocInfoGenerator.generateSignature(owner));
}
};
return new LineMarkerInfo<PsiModifierListOwner>((PsiModifierListOwner)element, element.getTextOffset(), AllIcons.Gutter.ExtAnnotation,
@@ -67,11 +67,6 @@ public class ExternalAnnotationsLineMarkerProvider implements LineMarkerProvider
GutterIconRenderer.Alignment.LEFT);
}
- private static PsiModifierListOwner preferCompiledElement(PsiModifierListOwner element) {
- PsiElement original = element.getOriginalElement();
- return original instanceof PsiModifierListOwner ? (PsiModifierListOwner)original : element;
- }
-
private static boolean shouldShowSignature(PsiModifierListOwner owner) {
if (hasNonCodeAnnotations(owner)) {
return true;
@@ -111,7 +106,7 @@ public class ExternalAnnotationsLineMarkerProvider implements LineMarkerProvider
if (ref == null) return true;
PsiElement target = ref.resolve();
- return !(target instanceof PsiClass) || JavaDocInfoGenerator.isDocumentedAnnotationType((PsiClass)target);
+ return !(target instanceof PsiClass) || JavaDocInfoGenerator.isDocumentedAnnotationType(target);
}
@Override
diff --git a/java/java-impl/src/com/intellij/codeInsight/TailTypes.java b/java/java-impl/src/com/intellij/codeInsight/TailTypes.java
index 923dd8213019..244067bd3f36 100644
--- a/java/java-impl/src/com/intellij/codeInsight/TailTypes.java
+++ b/java/java-impl/src/com/intellij/codeInsight/TailTypes.java
@@ -28,6 +28,12 @@ public class TailTypes {
return styleSettings.SPACE_WITHIN_METHOD_CALL_PARENTHESES && editor.getDocument().getCharsSequence().charAt(tailOffset - 1) != '(';
}
};
+ public static final TailType RPARENTH = new RParenthTailType(){
+ @Override
+ protected boolean isSpaceWithinParentheses(final CommonCodeStyleSettings styleSettings, final Editor editor, final int tailOffset) {
+ return styleSettings.SPACE_WITHIN_PARENTHESES;
+ }
+ };
public static final TailType IF_RPARENTH = new RParenthTailType(){
@Override
protected boolean isSpaceWithinParentheses(final CommonCodeStyleSettings styleSettings, final Editor editor, final int tailOffset) {
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java
index 8cc9d06aed04..112b243e0ea3 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java
+++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaCompletionUtil.java
@@ -544,7 +544,7 @@ public class JavaCompletionUtil {
return JavaClassNameCompletionContributor.createClassLookupItems((PsiClass)completion,
JavaClassNameCompletionContributor.AFTER_NEW.accepts(reference),
JavaClassNameInsertHandler.JAVA_CLASS_INSERT_HANDLER,
- Condition.TRUE);
+ Conditions.<PsiClass>alwaysTrue());
}
}
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/JavaDocCompletionContributor.java b/java/java-impl/src/com/intellij/codeInsight/completion/JavaDocCompletionContributor.java
index 2a9fc2f4a79f..978e5b24d2e8 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/JavaDocCompletionContributor.java
+++ b/java/java-impl/src/com/intellij/codeInsight/completion/JavaDocCompletionContributor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,7 +28,7 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.*;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
-import com.intellij.openapi.util.Condition;
+import com.intellij.openapi.util.Conditions;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.patterns.PsiJavaPatterns;
import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
@@ -43,7 +43,10 @@ import com.intellij.psi.javadoc.*;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.TypeConversionUtil;
-import com.intellij.util.*;
+import com.intellij.util.IncorrectOperationException;
+import com.intellij.util.ProcessingContext;
+import com.intellij.util.Processor;
+import com.intellij.util.SystemProperties;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.text.CharArrayUtil;
import org.jetbrains.annotations.NonNls;
@@ -81,7 +84,7 @@ public class JavaDocCompletionContributor extends CompletionContributor {
if (ref instanceof PsiJavaReference) {
result.stopHere();
- final JavaCompletionProcessor processor = new JavaCompletionProcessor(position, TrueFilter.INSTANCE, JavaCompletionProcessor.Options.CHECK_NOTHING, Condition.TRUE);
+ final JavaCompletionProcessor processor = new JavaCompletionProcessor(position, TrueFilter.INSTANCE, JavaCompletionProcessor.Options.CHECK_NOTHING, Conditions.<String>alwaysTrue());
((PsiJavaReference) ref).processVariants(processor);
for (final CompletionElement _item : processor.getResults()) {
diff --git a/java/java-impl/src/com/intellij/codeInsight/completion/PreferByKindWeigher.java b/java/java-impl/src/com/intellij/codeInsight/completion/PreferByKindWeigher.java
index ad53d9484959..cc67ca51de58 100644
--- a/java/java-impl/src/com/intellij/codeInsight/completion/PreferByKindWeigher.java
+++ b/java/java-impl/src/com/intellij/codeInsight/completion/PreferByKindWeigher.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@ import com.intellij.codeInsight.completion.scope.JavaCompletionProcessor;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementWeigher;
import com.intellij.openapi.util.Condition;
+import com.intellij.openapi.util.Conditions;
import com.intellij.patterns.ElementPattern;
import com.intellij.psi.*;
import com.intellij.psi.filters.getters.MembersGetter;
@@ -127,8 +128,7 @@ public class PreferByKindWeigher extends LookupElementWeigher {
};
}
- //noinspection unchecked
- return Condition.FALSE;
+ return Conditions.alwaysFalse();
}
enum MyResult {
diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ChangeMethodSignatureFromUsageFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ChangeMethodSignatureFromUsageFix.java
index dbf454207cca..d753875208c3 100644
--- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ChangeMethodSignatureFromUsageFix.java
+++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/ChangeMethodSignatureFromUsageFix.java
@@ -333,6 +333,9 @@ public class ChangeMethodSignatureFromUsageFix implements IntentionAction/*, Hig
else {
PsiType exprType = RefactoringUtil.getTypeByExpression(expression);
if (exprType == null) return null;
+ if (exprType instanceof PsiDisjunctionType) {
+ exprType = ((PsiDisjunctionType)exprType).getLeastUpperBound();
+ }
final ParameterInfoImpl changedParameterInfo = new ParameterInfoImpl(i, parameter.getName(), exprType);
result.add(changedParameterInfo);
changedParams.add(changedParameterInfo);
@@ -403,6 +406,9 @@ public class ChangeMethodSignatureFromUsageFix implements IntentionAction/*, Hig
if (varargParam != null && pi >= parameters.length) return false;
PsiType exprType = RefactoringUtil.getTypeByExpression(expression);
if (exprType == null) return false;
+ if (exprType instanceof PsiDisjunctionType) {
+ exprType = ((PsiDisjunctionType)exprType).getLeastUpperBound();
+ }
JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(expression.getProject());
String name = suggestUniqueParameterName(codeStyleManager, expression, exprType, existingNames);
final ParameterInfoImpl newParameterInfo = new ParameterInfoImpl(-1, name, exprType, expression.getText().replace('\n', ' '));
diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateMethodFromUsageFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateMethodFromUsageFix.java
index 8e93a6a0c817..ad3d3fc8010a 100644
--- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateMethodFromUsageFix.java
+++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateMethodFromUsageFix.java
@@ -182,7 +182,7 @@ public class CreateMethodFromUsageFix extends CreateFromUsageBaseFix {
context);
}
- protected static PsiMethod createMethod(PsiClass targetClass,
+ public static PsiMethod createMethod(PsiClass targetClass,
PsiClass parentClass,
PsiMember enclosingContext,
String methodName) {
diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateStaticMethodQuickFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateStaticMethodQuickFix.java
new file mode 100644
index 000000000000..8268ee58d44a
--- /dev/null
+++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateStaticMethodQuickFix.java
@@ -0,0 +1,81 @@
+package com.intellij.codeInsight.daemon.impl.quickfix;
+
+import com.intellij.codeInsight.ExpectedTypeInfo;
+import com.intellij.codeInsight.daemon.QuickFixBundle;
+import com.intellij.codeInspection.LocalQuickFix;
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Pair;
+import com.intellij.psi.*;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.util.PsiUtil;
+import com.intellij.util.Function;
+import com.intellij.util.containers.ContainerUtil;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+
+public class CreateStaticMethodQuickFix implements LocalQuickFix {
+ @NotNull
+ private final PsiClass targetClass;
+ @NotNull
+ private final String methodName;
+ @NotNull
+ private final List<String> types;
+
+
+ public CreateStaticMethodQuickFix(@NotNull PsiClass aClass,
+ @NotNull String name,
+ @NotNull List<String> types) {
+ targetClass = aClass;
+ methodName = name;
+ this.types = types;
+ }
+
+
+ @NotNull
+ @Override
+ public String getName() {
+ return QuickFixBundle.message("create.method.from.usage.family");
+ }
+
+ @NotNull
+ @Override
+ public String getFamilyName() {
+ return QuickFixBundle.message("create.method.from.usage.family");
+ }
+
+ @Override
+ public void applyFix(@NotNull final Project project, @NotNull ProblemDescriptor descriptor) {
+ boolean java8Interface = false;
+ if (targetClass.isInterface()) {
+ if (PsiUtil.isLanguageLevel8OrHigher(targetClass)) {
+ java8Interface = true;
+ } else {
+ return;
+ }
+ }
+
+ PsiMethod method = CreateMethodFromUsageFix.createMethod(targetClass, null, null, methodName);
+ if (method == null) {
+ return;
+ }
+
+ if (!java8Interface) {
+ PsiUtil.setModifierProperty(method, PsiModifier.PUBLIC, true);
+ }
+ PsiUtil.setModifierProperty(method, PsiModifier.STATIC, true);
+
+ List<Pair<PsiExpression,PsiType>> args = ContainerUtil.map(types, new Function<String, Pair<PsiExpression, PsiType>>() {
+ @Override
+ public Pair<PsiExpression, PsiType> fun(String s) {
+ return new Pair<PsiExpression, PsiType>(null, PsiType.getTypeByName(s, project, GlobalSearchScope.allScope(project)));
+ }
+ });
+ CreateMethodFromUsageFix.doCreate(targetClass, method, false,
+ args,
+ PsiSubstitutor.UNKNOWN,
+ ExpectedTypeInfo.EMPTY_ARRAY,
+ null);
+ }
+}
diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MoveClassToModuleFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MoveClassToModuleFix.java
index d8caac1d59a6..9c1d38853b2c 100644
--- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MoveClassToModuleFix.java
+++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/MoveClassToModuleFix.java
@@ -42,12 +42,12 @@ import com.intellij.refactoring.RefactoringActionHandler;
import com.intellij.refactoring.RefactoringActionHandlerFactory;
import com.intellij.ui.components.JBList;
import com.intellij.util.IncorrectOperationException;
-import org.codehaus.groovy.util.ListHashMap;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.model.java.JavaModuleSourceRootTypes;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -55,7 +55,7 @@ import java.util.Map;
* @author cdr
*/
public class MoveClassToModuleFix implements IntentionAction {
- private final Map<PsiClass, Module> myModules = new ListHashMap<PsiClass, Module>();
+ private final Map<PsiClass, Module> myModules = new LinkedHashMap<PsiClass, Module>();
private final String myReferenceName;
private final Module myCurrentModule;
private final PsiDirectory mySourceRoot;
diff --git a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithTryFinallySurrounder.java b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithTryFinallySurrounder.java
index e757ddeacc17..28732a65390b 100644
--- a/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithTryFinallySurrounder.java
+++ b/java/java-impl/src/com/intellij/codeInsight/generation/surroundWith/JavaWithTryFinallySurrounder.java
@@ -19,10 +19,8 @@ import com.intellij.codeInsight.CodeInsightBundle;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
-import com.intellij.openapi.editor.EditorModificationUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
-import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.util.IncorrectOperationException;
@@ -65,16 +63,14 @@ class JavaWithTryFinallySurrounder extends JavaStatementsSurrounder{
if (finallyBlock == null) {
return null;
}
- int offset = finallyBlock.getTextRange().getStartOffset() + 2;
- editor.getCaretModel().moveToOffset(offset);
- final Document document = editor.getDocument();
+ Document document = editor.getDocument();
PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(document);
+ TextRange finallyBlockRange = finallyBlock.getTextRange();
+ int newLineOffset = finallyBlockRange.getStartOffset() + 2;
+ editor.getCaretModel().moveToOffset(newLineOffset);
editor.getSelectionModel().removeSelection();
- final PsiStatement[] tryBlockStatements = tryBlock.getStatements();
- LOG.assertTrue(tryBlockStatements.length > 0, tryBlock.getText());
- final PsiStatement firstTryStmt = tryBlockStatements[0];
- final int indent = firstTryStmt.getTextOffset() - document.getLineStartOffset(document.getLineNumber(firstTryStmt.getTextOffset()));
- EditorModificationUtil.insertStringAtCaret(editor, StringUtil.repeat(" ", indent), false, true);
+ CodeStyleManager.getInstance(project).adjustLineIndent(document, newLineOffset);
+ PsiDocumentManager.getInstance(project).commitDocument(document);
return new TextRange(editor.getCaretModel().getOffset(), editor.getCaretModel().getOffset());
}
} \ No newline at end of file
diff --git a/java/java-impl/src/com/intellij/codeInsight/highlighting/HighlightExceptionsHandlerFactory.java b/java/java-impl/src/com/intellij/codeInsight/highlighting/HighlightExceptionsHandlerFactory.java
index c7bd10cc2b39..a1f206b4ba8e 100644
--- a/java/java-impl/src/com/intellij/codeInsight/highlighting/HighlightExceptionsHandlerFactory.java
+++ b/java/java-impl/src/com/intellij/codeInsight/highlighting/HighlightExceptionsHandlerFactory.java
@@ -19,6 +19,7 @@ import com.intellij.codeInsight.ExceptionUtil;
import com.intellij.featureStatistics.FeatureUsageTracker;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.util.Condition;
+import com.intellij.openapi.util.Conditions;
import com.intellij.psi.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -57,7 +58,7 @@ public class HighlightExceptionsHandlerFactory extends HighlightUsagesHandlerFac
final PsiCodeBlock tryBlock = tryStatement.getTryBlock();
if (tryBlock == null) return null;
final Collection<PsiClassType> psiClassTypes = ExceptionUtil.collectUnhandledExceptions(tryBlock, tryBlock);
- return new HighlightExceptionsHandler(editor, file, target, psiClassTypes.toArray(new PsiClassType[psiClassTypes.size()]), tryBlock, Condition.TRUE);
+ return new HighlightExceptionsHandler(editor, file, target, psiClassTypes.toArray(new PsiClassType[psiClassTypes.size()]), tryBlock, Conditions.<PsiType>alwaysTrue());
}
@Nullable
@@ -112,6 +113,6 @@ public class HighlightExceptionsHandlerFactory extends HighlightUsagesHandlerFac
final Collection<PsiClassType> psiClassTypes = ExceptionUtil.collectUnhandledExceptions(method.getBody(), method.getBody());
- return new HighlightExceptionsHandler(editor, file, target, psiClassTypes.toArray(new PsiClassType[psiClassTypes.size()]), method.getBody(), Condition.TRUE);
+ return new HighlightExceptionsHandler(editor, file, target, psiClassTypes.toArray(new PsiClassType[psiClassTypes.size()]), method.getBody(), Conditions.<PsiType>alwaysTrue());
}
}
diff --git a/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddAnnotationIntention.java b/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddAnnotationIntention.java
index 899da3035ce5..027928a4f695 100644
--- a/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddAnnotationIntention.java
+++ b/java/java-impl/src/com/intellij/codeInsight/intention/impl/AddAnnotationIntention.java
@@ -56,9 +56,11 @@ public abstract class AddAnnotationIntention extends BaseIntentionAction {
Pair<String, String[]> annotations = getAnnotations(project);
String toAdd = annotations.first;
String[] toRemove = annotations.second;
- if (toRemove.length > 0 && AnnotationUtil.isAnnotated(owner, toRemove[0], false, false)) return false;
+ if (toRemove.length > 0 && isAnnotatedSkipInferred(owner, toRemove)) {
+ return false;
+ }
setText(AddAnnotationPsiFix.calcText(owner, toAdd));
- if (AnnotationUtil.isAnnotated(owner, toAdd, false, false)) return false;
+ if (isAnnotatedSkipInferred(owner, toAdd)) return false;
if (owner instanceof PsiMethod) {
PsiType returnType = ((PsiMethod)owner).getReturnType();
@@ -73,6 +75,11 @@ public abstract class AddAnnotationIntention extends BaseIntentionAction {
return true;
}
+ private static boolean isAnnotatedSkipInferred(PsiModifierListOwner owner, String... annoFqns) {
+ PsiAnnotation annotation = AnnotationUtil.findAnnotation(owner, false, annoFqns);
+ return annotation != null && !AnnotationUtil.isInferredAnnotation(annotation);
+ }
+
@Override
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
PsiModifierListOwner owner = AddAnnotationPsiFix.getContainer(file, editor.getCaretModel().getOffset());
diff --git a/java/java-impl/src/com/intellij/codeInspection/equalsAndHashcode/EqualsAndHashcode.java b/java/java-impl/src/com/intellij/codeInspection/equalsAndHashcode/EqualsAndHashcode.java
new file mode 100644
index 000000000000..3887640051c4
--- /dev/null
+++ b/java/java-impl/src/com/intellij/codeInspection/equalsAndHashcode/EqualsAndHashcode.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInspection.equalsAndHashcode;
+
+import com.intellij.codeInsight.generation.GenerateEqualsHandler;
+import com.intellij.codeInspection.InspectionsBundle;
+import com.intellij.codeInspection.LocalQuickFix;
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.fileEditor.FileEditorManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiElement;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author Bas Leijdekkers
+ */
+public class EqualsAndHashcode extends EqualsAndHashcodeBase {
+
+ protected LocalQuickFix[] buildFixes(boolean isOnTheFly, boolean hasEquals) {
+ if (!isOnTheFly) {
+ return LocalQuickFix.EMPTY_ARRAY;
+ }
+ return new LocalQuickFix[]{new GenerateEqualsHashcodeFix(hasEquals)};
+ }
+
+ private static class GenerateEqualsHashcodeFix implements LocalQuickFix {
+
+ private final boolean myHasEquals;
+
+ public GenerateEqualsHashcodeFix(boolean hasEquals) {
+ myHasEquals = hasEquals;
+ }
+
+ @NotNull
+ @Override
+ public String getName() {
+ return myHasEquals
+ ? InspectionsBundle.message("inspection.equals.hashcode.generate.hashcode.quickfix")
+ : InspectionsBundle.message("inspection.equals.hashcode.generate.equals.quickfix");
+ }
+
+ @NotNull
+ @Override
+ public String getFamilyName() {
+ return getName();
+ }
+
+ @Override
+ public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
+ final Editor editor = FileEditorManager.getInstance(project).getSelectedTextEditor();
+ if (editor == null) {
+ return;
+ }
+ final PsiElement element = descriptor.getPsiElement();
+ new GenerateEqualsHandler().invoke(project, editor, element.getContainingFile());
+ }
+ }
+}
diff --git a/java/java-impl/src/com/intellij/codeInspection/inferNullity/InferNullityAnnotationsAction.java b/java/java-impl/src/com/intellij/codeInspection/inferNullity/InferNullityAnnotationsAction.java
index f9127f0b48a5..df49b83ff48d 100644
--- a/java/java-impl/src/com/intellij/codeInspection/inferNullity/InferNullityAnnotationsAction.java
+++ b/java/java-impl/src/com/intellij/codeInspection/inferNullity/InferNullityAnnotationsAction.java
@@ -159,7 +159,7 @@ public class InferNullityAnnotationsAction extends BaseAnalysisAction {
}
else if (Messages.showOkCancelDialog(project, "Infer Nullity Annotations requires that the nullity annotations" +
" be available in all your project sources.\n\nYou will need to add annotations.jar as a library. " +
- "It is possible to configure custom jar in e.g. Constant Conditions & Exceptions inspection or use JetBrains annotations available in installation. " +
+ "It is possible to configure custom JAR in e.g. Constant Conditions & Exceptions inspection or use JetBrains annotations available in installation. " +
" IntelliJ IDEA nullity annotations are freely usable and redistributable under the Apache 2.0 license. Would you like to do it now?",
INFER_NULLITY_ANNOTATIONS, Messages.getErrorIcon()) == Messages.OK) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
diff --git a/java/java-impl/src/com/intellij/find/findUsages/JavaFindUsagesHandler.java b/java/java-impl/src/com/intellij/find/findUsages/JavaFindUsagesHandler.java
index 5c226b84500b..4aff727524bf 100644
--- a/java/java-impl/src/com/intellij/find/findUsages/JavaFindUsagesHandler.java
+++ b/java/java-impl/src/com/intellij/find/findUsages/JavaFindUsagesHandler.java
@@ -100,7 +100,7 @@ public class JavaFindUsagesHandler extends FindUsagesHandler{
return super.getFindUsagesDialog(isSingleFile, toShowInNewTab, mustOpenInNewTab);
}
- private static boolean askWhetherShouldSearchForParameterInOverridingMethods(final PsiElement psiElement, final PsiParameter parameter) {
+ private static boolean askWhetherShouldSearchForParameterInOverridingMethods(@NotNull PsiElement psiElement, @NotNull PsiParameter parameter) {
return Messages.showOkCancelDialog(psiElement.getProject(),
FindBundle.message("find.parameter.usages.in.overriding.methods.prompt", parameter.getName()),
FindBundle.message("find.parameter.usages.in.overriding.methods.title"),
@@ -283,10 +283,10 @@ public class JavaFindUsagesHandler extends FindUsagesHandler{
final JavaVariableFindUsagesOptions varOptions = (JavaVariableFindUsagesOptions) options;
if (varOptions.isReadAccess || varOptions.isWriteAccess){
if (varOptions.isReadAccess && varOptions.isWriteAccess){
- if (!addElementUsages(element, processor, options)) return false;
+ if (!addElementUsages(element, options, processor)) return false;
}
else{
- if (!addElementUsages(element, new Processor<UsageInfo>() {
+ if (!addElementUsages(element, varOptions, new Processor<UsageInfo>() {
@Override
public boolean process(UsageInfo info) {
final PsiElement element = info.getElement();
@@ -296,12 +296,12 @@ public class JavaFindUsagesHandler extends FindUsagesHandler{
}
return true;
}
- }, varOptions)) return false;
+ })) return false;
}
}
}
else if (options.isUsages) {
- if (!addElementUsages(element, processor, options)) return false;
+ if (!addElementUsages(element, options, processor)) return false;
}
boolean success = ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
@@ -325,29 +325,35 @@ public class JavaFindUsagesHandler extends FindUsagesHandler{
if (!success) return false;
if (options instanceof JavaPackageFindUsagesOptions && ((JavaPackageFindUsagesOptions)options).isClassesUsages){
- if (!addClassesUsages((PsiPackage)element, processor, (JavaPackageFindUsagesOptions)options)) return false;
+ if (!addClassesUsages((PsiPackage)element, (JavaPackageFindUsagesOptions)options, processor)) return false;
}
if (options instanceof JavaClassFindUsagesOptions) {
final JavaClassFindUsagesOptions classOptions = (JavaClassFindUsagesOptions)options;
final PsiClass psiClass = (PsiClass)element;
+ PsiManager manager = ApplicationManager.getApplication().runReadAction(new Computable<PsiManager>() {
+ @Override
+ public PsiManager compute() {
+ return psiClass.getManager();
+ }
+ });
if (classOptions.isMethodsUsages){
- if (!addMethodsUsages(psiClass, processor, classOptions)) return false;
+ if (!addMethodsUsages(psiClass, manager, classOptions, processor)) return false;
}
if (classOptions.isFieldsUsages){
- if (!addFieldsUsages(psiClass, processor, classOptions)) return false;
+ if (!addFieldsUsages(psiClass, manager, classOptions, processor)) return false;
}
if (psiClass.isInterface()) {
if (classOptions.isDerivedInterfaces){
if (classOptions.isImplementingClasses){
- if (!addInheritors(psiClass, processor, classOptions)) return false;
+ if (!addInheritors(psiClass, classOptions, processor)) return false;
}
else{
- if (!addDerivedInterfaces(psiClass, processor, classOptions)) return false;
+ if (!addDerivedInterfaces(psiClass, classOptions, processor)) return false;
}
}
else if (classOptions.isImplementingClasses){
- if (!addImplementingClasses(psiClass, processor, classOptions)) return false;
+ if (!addImplementingClasses(psiClass, classOptions, processor)) return false;
}
if (classOptions.isImplementingClasses) {
@@ -355,13 +361,13 @@ public class JavaFindUsagesHandler extends FindUsagesHandler{
new PsiElementProcessor<PsiFunctionalExpression>() {
@Override
public boolean execute(@NotNull PsiFunctionalExpression expression) {
- return addResult(processor, expression, options);
+ return addResult(expression, options, processor);
}
}));
}
}
else if (classOptions.isDerivedClasses) {
- if (!addInheritors(psiClass, processor, classOptions)) return false;
+ if (!addInheritors(psiClass, classOptions, processor)) return false;
}
}
@@ -380,14 +386,14 @@ public class JavaFindUsagesHandler extends FindUsagesHandler{
new PsiElementProcessor<PsiFunctionalExpression>() {
@Override
public boolean execute(@NotNull PsiFunctionalExpression expression) {
- return addResult(processor, expression, options);
+ return addResult(expression, options, processor);
}
}));
}
}
if (element instanceof PomTarget) {
- if (!addAliasingUsages((PomTarget)element, processor, options)) return false;
+ if (!addAliasingUsages((PomTarget)element, options, processor)) return false;
}
final Boolean isSearchable = ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
@Override
@@ -403,8 +409,8 @@ public class JavaFindUsagesHandler extends FindUsagesHandler{
}
private static boolean addAliasingUsages(@NotNull PomTarget pomTarget,
- @NotNull final Processor<UsageInfo> processor,
- @NotNull final FindUsagesOptions options) {
+ @NotNull final FindUsagesOptions options,
+ @NotNull final Processor<UsageInfo> processor) {
for (AliasingPsiTargetMapper aliasingPsiTargetMapper : Extensions.getExtensions(AliasingPsiTargetMapper.EP_NAME)) {
for (AliasingPsiTarget psiTarget : aliasingPsiTargetMapper.getTargets(pomTarget)) {
boolean success = ReferencesSearch
@@ -412,7 +418,7 @@ public class JavaFindUsagesHandler extends FindUsagesHandler{
.forEach(new ReadActionProcessor<PsiReference>() {
@Override
public boolean processInReadAction(final PsiReference reference) {
- return addResult(processor, reference, options);
+ return addResult(reference, options, processor);
}
});
if (!success) return false;
@@ -428,15 +434,15 @@ public class JavaFindUsagesHandler extends FindUsagesHandler{
new PsiElementProcessor<PsiMethod>() {
@Override
public boolean execute(@NotNull PsiMethod element) {
- return addResult(processor, element.getNavigationElement(), options);
+ return addResult(element.getNavigationElement(), options, processor);
}
}));
}
private static boolean addClassesUsages(@NotNull PsiPackage aPackage,
- @NotNull final Processor<UsageInfo> processor,
- @NotNull final JavaPackageFindUsagesOptions options) {
+ @NotNull final JavaPackageFindUsagesOptions options,
+ @NotNull final Processor<UsageInfo> processor) {
ProgressIndicator progress = ProgressManager.getInstance().getProgressIndicator();
if (progress != null){
progress.pushState();
@@ -446,18 +452,19 @@ public class JavaFindUsagesHandler extends FindUsagesHandler{
addClassesInPackage(aPackage, options.isIncludeSubpackages, classes);
for (final PsiClass aClass : classes) {
if (progress != null) {
- progress.setText(FindBundle.message("find.searching.for.references.to.class.progress", ApplicationManager.getApplication().runReadAction(new Computable<String>(){
+ String name = ApplicationManager.getApplication().runReadAction(new Computable<String>() {
@Override
public String compute() {
return aClass.getName();
}
- })));
+ });
+ progress.setText(FindBundle.message("find.searching.for.references.to.class.progress", name));
progress.checkCanceled();
}
boolean success = ReferencesSearch.search(new ReferencesSearch.SearchParameters(aClass, options.searchScope, false, options.fastTrack)).forEach(new ReadActionProcessor<PsiReference>() {
@Override
public boolean processInReadAction(final PsiReference psiReference) {
- return addResult(processor, psiReference, options);
+ return addResult(psiReference, options, processor);
}
});
if (!success) return false;
@@ -469,8 +476,13 @@ public class JavaFindUsagesHandler extends FindUsagesHandler{
return true;
}
- private static void addClassesInPackage(@NotNull PsiPackage aPackage, boolean includeSubpackages, @NotNull List<PsiClass> array) {
- PsiDirectory[] dirs = aPackage.getDirectories();
+ private static void addClassesInPackage(@NotNull final PsiPackage aPackage, boolean includeSubpackages, @NotNull List<PsiClass> array) {
+ PsiDirectory[] dirs = ApplicationManager.getApplication().runReadAction(new Computable<PsiDirectory[]>() {
+ @Override
+ public PsiDirectory[] compute() {
+ return aPackage.getDirectories();
+ }
+ });
for (PsiDirectory dir : dirs) {
addClassesInDirectory(dir, includeSubpackages, array);
}
@@ -495,22 +507,40 @@ public class JavaFindUsagesHandler extends FindUsagesHandler{
}
private static boolean addMethodsUsages(@NotNull final PsiClass aClass,
- @NotNull final Processor<UsageInfo> processor,
- @NotNull final JavaClassFindUsagesOptions options) {
+ @NotNull final PsiManager manager,
+ @NotNull final JavaClassFindUsagesOptions options,
+ @NotNull final Processor<UsageInfo> processor) {
if (options.isIncludeInherited) {
- final PsiManager manager = aClass.getManager();
- PsiMethod[] methods = aClass.getAllMethods();
- MethodsLoop:
+ final PsiMethod[] methods = ApplicationManager.getApplication().runReadAction(new Computable<PsiMethod[]>() {
+ @Override
+ public PsiMethod[] compute() {
+ return aClass.getAllMethods();
+ }
+ });
for(int i = 0; i < methods.length; i++){
final PsiMethod method = methods[i];
- // filter overriden methods
- MethodSignature methodSignature = method.getSignature(PsiSubstitutor.EMPTY);
- for(int j = 0; j < i; j++){
- if (methodSignature.equals(methods[j].getSignature(PsiSubstitutor.EMPTY))) continue MethodsLoop;
- }
- final PsiClass methodClass = method.getContainingClass();
- if (methodClass != null && manager.areElementsEquivalent(methodClass, aClass)){
- if (!addElementUsages(methods[i], processor, options)) return false;
+ // filter overridden methods
+ final int finalI = i;
+ final PsiClass methodClass =
+ ApplicationManager.getApplication().runReadAction(new Computable<PsiClass>() {
+ @Override
+ public PsiClass compute() {
+ MethodSignature methodSignature = method.getSignature(PsiSubstitutor.EMPTY);
+ for (int j = 0; j < finalI; j++) {
+ if (methodSignature.equals(methods[j].getSignature(PsiSubstitutor.EMPTY))) return null;
+ }
+ return method.getContainingClass();
+ }
+ });
+ if (methodClass == null) continue;
+ boolean equivalent = ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
+ @Override
+ public Boolean compute() {
+ return manager.areElementsEquivalent(methodClass, aClass);
+ }
+ });
+ if (equivalent){
+ if (!addElementUsages(method, options, processor)) return false;
}
else {
MethodReferencesSearch.SearchParameters parameters =
@@ -519,7 +549,7 @@ public class JavaFindUsagesHandler extends FindUsagesHandler{
.forEach(new PsiReferenceProcessorAdapter(new PsiReferenceProcessor() {
@Override
public boolean execute(PsiReference reference) {
- addResultFromReference(reference, methodClass, manager, aClass, processor, options);
+ addResultFromReference(reference, methodClass, manager, aClass, options, processor);
return true;
}
}));
@@ -528,35 +558,59 @@ public class JavaFindUsagesHandler extends FindUsagesHandler{
}
}
else {
- for (PsiMethod method : aClass.getMethods()) {
- if (!addElementUsages(method, processor, options)) return false;
+ PsiMethod[] methods = ApplicationManager.getApplication().runReadAction(new Computable<PsiMethod[]>() {
+ @Override
+ public PsiMethod[] compute() {
+ return aClass.getMethods();
+ }
+ });
+ for (PsiMethod method : methods) {
+ if (!addElementUsages(method, options, processor)) return false;
}
}
return true;
}
private static boolean addFieldsUsages(@NotNull final PsiClass aClass,
- @NotNull final Processor<UsageInfo> processor,
- @NotNull final JavaClassFindUsagesOptions options) {
+ @NotNull final PsiManager manager,
+ @NotNull final JavaClassFindUsagesOptions options,
+ @NotNull final Processor<UsageInfo> processor) {
if (options.isIncludeInherited) {
- final PsiManager manager = aClass.getManager();
- PsiField[] fields = aClass.getAllFields();
- FieldsLoop:
+ final PsiField[] fields = ApplicationManager.getApplication().runReadAction(new Computable<PsiField[]>() {
+ @Override
+ public PsiField[] compute() {
+ return aClass.getAllFields();
+ }
+ });
for (int i = 0; i < fields.length; i++) {
final PsiField field = fields[i];
// filter hidden fields
- for (int j = 0; j < i; j++) {
- if (Comparing.strEqual(field.getName(), fields[j].getName())) continue FieldsLoop;
- }
- final PsiClass fieldClass = field.getContainingClass();
- if (manager.areElementsEquivalent(fieldClass, aClass)) {
- if (!addElementUsages(fields[i], processor, options)) return false;
+ final int finalI = i;
+ final PsiClass fieldClass =
+ ApplicationManager.getApplication().runReadAction(new Computable<PsiClass>() {
+ @Override
+ public PsiClass compute() {
+ for (int j = 0; j < finalI; j++) {
+ if (Comparing.strEqual(field.getName(), fields[j].getName())) return null;
+ }
+ return field.getContainingClass();
+ }
+ });
+ if (fieldClass == null) continue;
+ boolean equivalent = ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
+ @Override
+ public Boolean compute() {
+ return manager.areElementsEquivalent(fieldClass, aClass);
+ }
+ });
+ if (equivalent) {
+ if (!addElementUsages(fields[i], options, processor)) return false;
}
else {
boolean success = ReferencesSearch.search(new ReferencesSearch.SearchParameters(field, options.searchScope, false, options.fastTrack)).forEach(new ReadActionProcessor<PsiReference>() {
@Override
public boolean processInReadAction(final PsiReference reference) {
- return addResultFromReference(reference, fieldClass, manager, aClass, processor, options);
+ return addResultFromReference(reference, fieldClass, manager, aClass, options, processor);
}
});
if (!success) return false;
@@ -571,14 +625,14 @@ public class JavaFindUsagesHandler extends FindUsagesHandler{
}
});
for (PsiField field : fields) {
- if (!addElementUsages(field, processor, options)) return false;
+ if (!addElementUsages(field, options, processor)) return false;
}
}
return true;
}
@Nullable
- private static PsiClass getFieldOrMethodAccessedClass(@NotNull PsiReferenceExpression ref, PsiClass fieldOrMethodClass) {
+ private static PsiClass getFieldOrMethodAccessedClass(@NotNull PsiReferenceExpression ref, @NotNull PsiClass fieldOrMethodClass) {
PsiElement[] children = ref.getChildren();
if (children.length > 1 && children[0] instanceof PsiExpression) {
PsiExpression expr = (PsiExpression)children[0];
@@ -606,39 +660,39 @@ public class JavaFindUsagesHandler extends FindUsagesHandler{
}
private static boolean addInheritors(@NotNull PsiClass aClass,
- @NotNull final Processor<UsageInfo> processor,
- @NotNull final JavaClassFindUsagesOptions options) {
+ @NotNull final JavaClassFindUsagesOptions options,
+ @NotNull final Processor<UsageInfo> processor) {
return ClassInheritorsSearch.search(aClass, options.searchScope, options.isCheckDeepInheritance).forEach(new PsiElementProcessorAdapter<PsiClass>(
new PsiElementProcessor<PsiClass>() {
@Override
public boolean execute(@NotNull PsiClass element) {
- return addResult(processor, element, options);
+ return addResult(element, options, processor);
}
}));
}
private static boolean addDerivedInterfaces(@NotNull PsiClass anInterface,
- @NotNull final Processor<UsageInfo> processor,
- @NotNull final JavaClassFindUsagesOptions options) {
+ @NotNull final JavaClassFindUsagesOptions options,
+ @NotNull final Processor<UsageInfo> processor) {
return ClassInheritorsSearch.search(anInterface, options.searchScope, options.isCheckDeepInheritance).forEach(new PsiElementProcessorAdapter<PsiClass>(
new PsiElementProcessor<PsiClass>() {
@Override
public boolean execute(@NotNull PsiClass inheritor) {
- return !inheritor.isInterface() || addResult(processor, inheritor, options);
+ return !inheritor.isInterface() || addResult(inheritor, options, processor);
}
}));
}
private static boolean addImplementingClasses(@NotNull PsiClass anInterface,
- @NotNull final Processor<UsageInfo> processor,
- @NotNull final JavaClassFindUsagesOptions options) {
+ @NotNull final JavaClassFindUsagesOptions options,
+ @NotNull final Processor<UsageInfo> processor) {
return ClassInheritorsSearch.search(anInterface, options.searchScope, options.isCheckDeepInheritance).forEach(new PsiElementProcessorAdapter<PsiClass>(
new PsiElementProcessor<PsiClass>() {
@Override
public boolean execute(@NotNull PsiClass inheritor) {
- return inheritor.isInterface() || addResult(processor, inheritor, options);
+ return inheritor.isInterface() || addResult(inheritor, options, processor);
}
}));
}
@@ -647,14 +701,14 @@ public class JavaFindUsagesHandler extends FindUsagesHandler{
@NotNull PsiClass methodClass,
@NotNull PsiManager manager,
@NotNull PsiClass aClass,
- @NotNull Processor<UsageInfo> processor,
- @NotNull FindUsagesOptions options) {
+ @NotNull FindUsagesOptions options,
+ @NotNull Processor<UsageInfo> processor) {
PsiElement refElement = reference.getElement();
if (refElement instanceof PsiReferenceExpression) {
PsiClass usedClass = getFieldOrMethodAccessedClass((PsiReferenceExpression)refElement, methodClass);
if (usedClass != null) {
if (manager.areElementsEquivalent(usedClass, aClass) || usedClass.isInheritor(aClass, true)) {
- if (!addResult(processor, refElement, options)) return false;
+ if (!addResult(refElement, options, processor)) return false;
}
}
}
@@ -662,8 +716,8 @@ public class JavaFindUsagesHandler extends FindUsagesHandler{
}
private static boolean addElementUsages(@NotNull final PsiElement element,
- @NotNull final Processor<UsageInfo> processor,
- @NotNull final FindUsagesOptions options) {
+ @NotNull final FindUsagesOptions options,
+ @NotNull final Processor<UsageInfo> processor) {
final SearchScope searchScope = options.searchScope;
final PsiClass[] parentClass = new PsiClass[1];
if (element instanceof PsiMethod && ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
@@ -684,7 +738,7 @@ public class JavaFindUsagesHandler extends FindUsagesHandler{
.forEach(new ReadActionProcessor<PsiReference>() {
@Override
public boolean processInReadAction(final PsiReference ref) {
- return addResult(processor, ref, options);
+ return addResult(ref, options, processor);
}
});
}
@@ -694,7 +748,7 @@ public class JavaFindUsagesHandler extends FindUsagesHandler{
final ReadActionProcessor<PsiReference> consumer = new ReadActionProcessor<PsiReference>() {
@Override
public boolean processInReadAction(final PsiReference ref) {
- return addResult(processor, ref, options);
+ return addResult(ref, options, processor);
}
};
@@ -708,11 +762,13 @@ public class JavaFindUsagesHandler extends FindUsagesHandler{
return ReferencesSearch.search(new ReferencesSearch.SearchParameters(element, searchScope, false, options.fastTrack)).forEach(consumer);
}
- private static boolean addResult(@NotNull Processor<UsageInfo> processor, @NotNull PsiElement element, @NotNull FindUsagesOptions options) {
+ private static boolean addResult(@NotNull PsiElement element,
+ @NotNull FindUsagesOptions options,
+ @NotNull Processor<UsageInfo> processor) {
return !filterUsage(element, options) || processor.process(new UsageInfo(element));
}
- private static boolean addResult(Processor<UsageInfo> processor, PsiReference ref, FindUsagesOptions options) {
+ private static boolean addResult(@NotNull PsiReference ref, @NotNull FindUsagesOptions options, @NotNull Processor<UsageInfo> processor) {
if (filterUsage(ref.getElement(), options)){
TextRange rangeInElement = ref.getRangeInElement();
return processor.process(new UsageInfo(ref.getElement(), rangeInElement.getStartOffset(), rangeInElement.getEndOffset(), false));
@@ -720,7 +776,7 @@ public class JavaFindUsagesHandler extends FindUsagesHandler{
return true;
}
- private static boolean filterUsage(PsiElement usage, FindUsagesOptions options) {
+ private static boolean filterUsage(PsiElement usage, @NotNull FindUsagesOptions options) {
if (!(usage instanceof PsiJavaCodeReferenceElement)) {
return true;
}
@@ -780,5 +836,4 @@ public class JavaFindUsagesHandler extends FindUsagesHandler{
}
return super.findReferencesToHighlight(target, searchScope);
}
-
}
diff --git a/java/java-impl/src/com/intellij/ide/JavaLanguageCodeStyleSettingsProvider.java b/java/java-impl/src/com/intellij/ide/JavaLanguageCodeStyleSettingsProvider.java
index 2f684304ae58..c6c4f6c144d2 100644
--- a/java/java-impl/src/com/intellij/ide/JavaLanguageCodeStyleSettingsProvider.java
+++ b/java/java-impl/src/com/intellij/ide/JavaLanguageCodeStyleSettingsProvider.java
@@ -19,6 +19,7 @@ import com.intellij.application.options.IndentOptionsEditor;
import com.intellij.application.options.JavaIndentOptionsEditor;
import com.intellij.lang.Language;
import com.intellij.lang.java.JavaLanguage;
+import com.intellij.openapi.application.ApplicationBundle;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.project.Project;
import com.intellij.pom.java.LanguageLevel;
@@ -57,8 +58,8 @@ public class JavaLanguageCodeStyleSettingsProvider extends LanguageCodeStyleSett
@Override
public void customizeSettings(@NotNull CodeStyleSettingsCustomizable consumer, @NotNull SettingsType settingsType) {
- consumer.showAllStandardOptions();
if (settingsType == SettingsType.SPACING_SETTINGS) {
+ consumer.showAllStandardOptions();
consumer.showCustomOption(JavaCodeStyleSettings.class, "SPACES_WITHIN_ANGLE_BRACKETS", "Angle brackets",CodeStyleSettingsCustomizable.SPACES_WITHIN);
String groupName = CodeStyleSettingsCustomizable.SPACES_IN_TYPE_ARGUMENTS;
@@ -69,6 +70,95 @@ public class JavaLanguageCodeStyleSettingsProvider extends LanguageCodeStyleSett
consumer.showCustomOption(JavaCodeStyleSettings.class, "SPACE_BEFORE_OPENING_ANGLE_BRACKET_IN_TYPE_PARAMETER", "Before opening angle bracket", groupName);
consumer.showCustomOption(JavaCodeStyleSettings.class, "SPACE_AROUND_TYPE_BOUNDS_IN_TYPE_PARAMETERS", "Around type bounds", groupName);
}
+ else if (settingsType == SettingsType.WRAPPING_AND_BRACES_SETTINGS) {
+ consumer.showStandardOptions("RIGHT_MARGIN",
+ "KEEP_CONTROL_STATEMENT_IN_ONE_LINE",
+ "LINE_COMMENT_AT_FIRST_COLUMN",
+ "BLOCK_COMMENT_AT_FIRST_COLUMN",
+ "KEEP_LINE_BREAKS",
+ "KEEP_FIRST_COLUMN_COMMENT",
+ "CALL_PARAMETERS_WRAP",
+ "PREFER_PARAMETERS_WRAP",
+ "CALL_PARAMETERS_LPAREN_ON_NEXT_LINE",
+ "CALL_PARAMETERS_RPAREN_ON_NEXT_LINE",
+ "METHOD_PARAMETERS_WRAP",
+ "METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE",
+ "METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE",
+ "RESOURCE_LIST_WRAP",
+ "RESOURCE_LIST_LPAREN_ON_NEXT_LINE",
+ "RESOURCE_LIST_RPAREN_ON_NEXT_LINE",
+ "EXTENDS_LIST_WRAP",
+ "THROWS_LIST_WRAP",
+ "EXTENDS_KEYWORD_WRAP",
+ "THROWS_KEYWORD_WRAP",
+ "METHOD_CALL_CHAIN_WRAP",
+ "PARENTHESES_EXPRESSION_LPAREN_WRAP",
+ "PARENTHESES_EXPRESSION_RPAREN_WRAP",
+ "BINARY_OPERATION_WRAP",
+ "BINARY_OPERATION_SIGN_ON_NEXT_LINE",
+ "TERNARY_OPERATION_WRAP",
+ "TERNARY_OPERATION_SIGNS_ON_NEXT_LINE",
+ "MODIFIER_LIST_WRAP",
+ "KEEP_SIMPLE_BLOCKS_IN_ONE_LINE",
+ "KEEP_SIMPLE_METHODS_IN_ONE_LINE",
+ "KEEP_SIMPLE_CLASSES_IN_ONE_LINE",
+ "KEEP_MULTIPLE_EXPRESSIONS_IN_ONE_LINE",
+ "FOR_STATEMENT_WRAP",
+ "FOR_STATEMENT_LPAREN_ON_NEXT_LINE",
+ "FOR_STATEMENT_RPAREN_ON_NEXT_LINE",
+ "ARRAY_INITIALIZER_WRAP",
+ "ARRAY_INITIALIZER_LBRACE_ON_NEXT_LINE",
+ "ARRAY_INITIALIZER_RBRACE_ON_NEXT_LINE",
+ "ASSIGNMENT_WRAP",
+ "PLACE_ASSIGNMENT_SIGN_ON_NEXT_LINE",
+ "LABELED_STATEMENT_WRAP",
+ "ASSERT_STATEMENT_WRAP",
+ "ASSERT_STATEMENT_COLON_ON_NEXT_LINE",
+ "IF_BRACE_FORCE",
+ "DOWHILE_BRACE_FORCE",
+ "WHILE_BRACE_FORCE",
+ "FOR_BRACE_FORCE",
+ "WRAP_LONG_LINES",
+ "METHOD_ANNOTATION_WRAP",
+ "CLASS_ANNOTATION_WRAP",
+ "FIELD_ANNOTATION_WRAP",
+ "PARAMETER_ANNOTATION_WRAP",
+ "VARIABLE_ANNOTATION_WRAP",
+ "ALIGN_MULTILINE_CHAINED_METHODS",
+ "ALIGN_MULTILINE_PARAMETERS",
+ "ALIGN_MULTILINE_PARAMETERS_IN_CALLS",
+ "ALIGN_MULTILINE_RESOURCES",
+ "ALIGN_MULTILINE_FOR",
+ "INDENT_WHEN_CASES",
+ "ALIGN_MULTILINE_BINARY_OPERATION",
+ "ALIGN_MULTILINE_ASSIGNMENT",
+ "ALIGN_MULTILINE_TERNARY_OPERATION",
+ "ALIGN_MULTILINE_THROWS_LIST",
+ "ALIGN_THROWS_KEYWORD",
+ "ALIGN_MULTILINE_EXTENDS_LIST",
+ "ALIGN_MULTILINE_METHOD_BRACKETS",
+ "ALIGN_MULTILINE_PARENTHESIZED_EXPRESSION",
+ "ALIGN_MULTILINE_ARRAY_INITIALIZER_EXPRESSION",
+ "ALIGN_GROUP_FIELD_DECLARATIONS",
+ "BRACE_STYLE",
+ "CLASS_BRACE_STYLE",
+ "METHOD_BRACE_STYLE",
+ "USE_FLYING_GEESE_BRACES",
+ "FLYING_GEESE_BRACES_GAP",
+ "DO_NOT_INDENT_TOP_LEVEL_CLASS_MEMBERS",
+ "ELSE_ON_NEW_LINE",
+ "WHILE_ON_NEW_LINE",
+ "CATCH_ON_NEW_LINE",
+ "FINALLY_ON_NEW_LINE",
+ "INDENT_CASE_FROM_SWITCH",
+ "SPECIAL_ELSE_IF_TREATMENT",
+ "ENUM_CONSTANTS_WRAP");
+ String groupName = ApplicationBundle.message("wrapping.fields.annotation");
+ consumer.showCustomOption(JavaCodeStyleSettings.class, "DO_NOT_WRAP_AFTER_SINGLE_ANNOTATION", "Do not wrap after single annotation", groupName);
+ }
+ else {
+ consumer.showAllStandardOptions();
+ }
}
@Override
diff --git a/java/java-impl/src/com/intellij/ide/actions/CreatePackageInfoAction.java b/java/java-impl/src/com/intellij/ide/actions/CreatePackageInfoAction.java
index 64a8c1bcfcb5..8fd9f0d422db 100644
--- a/java/java-impl/src/com/intellij/ide/actions/CreatePackageInfoAction.java
+++ b/java/java-impl/src/com/intellij/ide/actions/CreatePackageInfoAction.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -41,7 +41,7 @@ import org.jetbrains.jps.model.java.JavaModuleSourceRootTypes;
*/
public class CreatePackageInfoAction extends CreateFromTemplateActionBase implements DumbAware {
- protected CreatePackageInfoAction() {
+ public CreatePackageInfoAction() {
super(IdeBundle.message("action.create.new.package-info.title"),
IdeBundle.message("action.create.new.package-info.description"), AllIcons.FileTypes.Java);
}
diff --git a/java/java-impl/src/com/intellij/ide/projectView/impl/ClassesTreeStructureProvider.java b/java/java-impl/src/com/intellij/ide/projectView/impl/ClassesTreeStructureProvider.java
index 7e0515726610..ef745b3aaa8b 100644
--- a/java/java-impl/src/com/intellij/ide/projectView/impl/ClassesTreeStructureProvider.java
+++ b/java/java-impl/src/com/intellij/ide/projectView/impl/ClassesTreeStructureProvider.java
@@ -62,8 +62,9 @@ public class ClassesTreeStructureProvider implements SelectableTreeStructureProv
if (originalElement instanceof PsiFile) {
PsiFile classFile = (PsiFile)originalElement;
final VirtualFile virtualClassFile = classFile.getVirtualFile();
- if (virtualClassFile != null && fileIndex.isInLibraryClasses(virtualClassFile) &&
- classOwner.getManager().areElementsEquivalent(classOwner.getContainingDirectory(), classFile.getContainingDirectory())) {
+ if (virtualClassFile != null && fileIndex.isInLibraryClasses(virtualClassFile)
+ && !classOwner.getManager().areElementsEquivalent(classOwner, classFile)
+ && classOwner.getManager().areElementsEquivalent(classOwner.getContainingDirectory(), classFile.getContainingDirectory())) {
continue;
}
}
diff --git a/java/java-impl/src/com/intellij/ide/util/scopeChooser/ClassHierarchyScopeDescriptor.java b/java/java-impl/src/com/intellij/ide/util/scopeChooser/ClassHierarchyScopeDescriptor.java
index 356933823226..05b2578e5df1 100644
--- a/java/java-impl/src/com/intellij/ide/util/scopeChooser/ClassHierarchyScopeDescriptor.java
+++ b/java/java-impl/src/com/intellij/ide/util/scopeChooser/ClassHierarchyScopeDescriptor.java
@@ -69,23 +69,25 @@ public class ClassHierarchyScopeDescriptor extends ScopeDescriptor {
chooser.showDialog();
PsiClass aClass = chooser.getSelected();
- if (aClass == null) return null;
+ if (aClass == null) {
+ myCachedScope = GlobalSearchScope.EMPTY_SCOPE;
+ } else {
+ final List<PsiElement> classesToSearch = new LinkedList<PsiElement>();
+ classesToSearch.add(aClass);
- final List<PsiElement> classesToSearch = new LinkedList<PsiElement>();
- classesToSearch.add(aClass);
+ classesToSearch.addAll(ClassInheritorsSearch.search(aClass, true).findAll());
- classesToSearch.addAll(ClassInheritorsSearch.search(aClass, true).findAll());
+ FunctionalExpressionSearch.search(aClass).forEach(new Processor<PsiFunctionalExpression>() {
+ @Override
+ public boolean process(PsiFunctionalExpression expression) {
+ classesToSearch.add(expression);
+ return true;
+ }
+ });
- FunctionalExpressionSearch.search(aClass).forEach(new Processor<PsiFunctionalExpression>() {
- @Override
- public boolean process(PsiFunctionalExpression expression) {
- classesToSearch.add(expression);
- return true;
- }
- });
-
- myCachedScope = new LocalSearchScope(PsiUtilCore.toPsiElementArray(classesToSearch),
- IdeBundle.message("scope.hierarchy", ClassPresentationUtil.getNameForClass(aClass, true)));
+ myCachedScope = new LocalSearchScope(PsiUtilCore.toPsiElementArray(classesToSearch),
+ IdeBundle.message("scope.hierarchy", ClassPresentationUtil.getNameForClass(aClass, true)));
+ }
}
return myCachedScope;
diff --git a/java/java-impl/src/com/intellij/jarFinder/FindJarFix.java b/java/java-impl/src/com/intellij/jarFinder/FindJarFix.java
index ee203e34deac..e82f79652074 100644
--- a/java/java-impl/src/com/intellij/jarFinder/FindJarFix.java
+++ b/java/java-impl/src/com/intellij/jarFinder/FindJarFix.java
@@ -69,7 +69,7 @@ public abstract class FindJarFix<T extends PsiElement> implements IntentionActio
@NotNull
@Override
public String getText() {
- return "Find jar on web";
+ return "Find JAR on web";
}
@NotNull
@@ -190,7 +190,7 @@ public abstract class FindJarFix<T extends PsiElement> implements IntentionActio
} else {
JBPopupFactory.getInstance()
.createListPopupBuilder(libNames)
- .setTitle("Select a jar file")
+ .setTitle("Select a JAR file")
.setItemChoosenCallback(new Runnable() {
@Override
public void run() {
diff --git a/java/java-impl/src/com/intellij/openapi/projectRoots/impl/JavaAwareProjectJdkTableImpl.java b/java/java-impl/src/com/intellij/openapi/projectRoots/impl/JavaAwareProjectJdkTableImpl.java
index 44f0132acbb5..fd9fa64eae66 100644
--- a/java/java-impl/src/com/intellij/openapi/projectRoots/impl/JavaAwareProjectJdkTableImpl.java
+++ b/java/java-impl/src/com/intellij/openapi/projectRoots/impl/JavaAwareProjectJdkTableImpl.java
@@ -22,17 +22,16 @@ package com.intellij.openapi.projectRoots.impl;
import com.intellij.openapi.components.*;
import com.intellij.openapi.project.ProjectBundle;
-import com.intellij.openapi.projectRoots.*;
+import com.intellij.openapi.projectRoots.JavaSdk;
+import com.intellij.openapi.projectRoots.ProjectJdkTable;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.projectRoots.SdkTypeId;
import com.intellij.util.SystemProperties;
import org.jdom.Element;
@State(
- name="ProjectJdkTable",
- roamingType = RoamingType.DISABLED,
- storages= {
- @Storage(
- file = StoragePathMacros.APP_CONFIG + "/jdk.table.xml"
- )}
+ name = "ProjectJdkTable",
+ storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/jdk.table.xml", roamingType = RoamingType.DISABLED)}
)
public class JavaAwareProjectJdkTableImpl extends ProjectJdkTableImpl {
public static JavaAwareProjectJdkTableImpl getInstanceEx() {
diff --git a/java/java-impl/src/com/intellij/openapi/roots/impl/LanguageLevelProjectExtensionImpl.java b/java/java-impl/src/com/intellij/openapi/roots/impl/LanguageLevelProjectExtensionImpl.java
index 496795b85444..836d6e005113 100644
--- a/java/java-impl/src/com/intellij/openapi/roots/impl/LanguageLevelProjectExtensionImpl.java
+++ b/java/java-impl/src/com/intellij/openapi/roots/impl/LanguageLevelProjectExtensionImpl.java
@@ -97,7 +97,9 @@ public class LanguageLevelProjectExtensionImpl extends LanguageLevelProjectExten
@Override
public void languageLevelsChanged() {
- JavaLanguageLevelPusher.pushLanguageLevel(myProject);
+ if (!myProject.isDefault()) {
+ JavaLanguageLevelPusher.pushLanguageLevel(myProject);
+ }
}
@Override
diff --git a/java/java-impl/src/com/intellij/psi/codeStyle/JavaCodeStyleSettings.java b/java/java-impl/src/com/intellij/psi/codeStyle/JavaCodeStyleSettings.java
index 7e117e3ed0c7..b7d0f71fe00d 100644
--- a/java/java-impl/src/com/intellij/psi/codeStyle/JavaCodeStyleSettings.java
+++ b/java/java-impl/src/com/intellij/psi/codeStyle/JavaCodeStyleSettings.java
@@ -30,4 +30,5 @@ public class JavaCodeStyleSettings extends CustomCodeStyleSettings {
public boolean SPACE_BEFORE_OPENING_ANGLE_BRACKET_IN_TYPE_PARAMETER = false;
public boolean SPACE_AROUND_TYPE_BOUNDS_IN_TYPE_PARAMETERS = true;
+ public boolean DO_NOT_WRAP_AFTER_SINGLE_ANNOTATION = false;
}
diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java b/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java
index 4d225e65d88b..5230805aa03c 100644
--- a/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java
+++ b/java/java-impl/src/com/intellij/psi/formatter/java/JavaSpacePropertyProcessor.java
@@ -1129,7 +1129,7 @@ public class JavaSpacePropertyProcessor extends JavaElementVisitor {
@Override
public void visitModifierList(PsiModifierList list) {
- createSpaceInCode(true);
+ myResult = Spacing.createSpacing(1, 1, 0, mySettings.KEEP_LINE_BREAKS, mySettings.KEEP_BLANK_LINES_IN_CODE);
}
@Override
diff --git a/java/java-impl/src/com/intellij/psi/formatter/java/wrap/impl/JavaChildWrapArranger.java b/java/java-impl/src/com/intellij/psi/formatter/java/wrap/impl/JavaChildWrapArranger.java
index 954f03248b9c..5b05ced2d5a1 100644
--- a/java/java-impl/src/com/intellij/psi/formatter/java/wrap/impl/JavaChildWrapArranger.java
+++ b/java/java-impl/src/com/intellij/psi/formatter/java/wrap/impl/JavaChildWrapArranger.java
@@ -20,6 +20,7 @@ import com.intellij.formatting.WrapType;
import com.intellij.lang.ASTNode;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
+import com.intellij.psi.codeStyle.JavaCodeStyleSettings;
import com.intellij.psi.formatter.FormatterUtil;
import com.intellij.psi.formatter.java.JavaFormatterUtil;
import com.intellij.psi.formatter.java.wrap.JavaWrapManager;
@@ -29,6 +30,7 @@ import com.intellij.psi.impl.source.tree.CompositeElement;
import com.intellij.psi.impl.source.tree.JavaElementType;
import com.intellij.psi.tree.IElementType;
import com.intellij.util.ArrayUtil;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import static com.intellij.psi.formatter.java.JavaFormatterUtil.getWrapType;
@@ -69,6 +71,7 @@ public class JavaChildWrapArranger {
CommonCodeStyleSettings settings,
Wrap suggestedWrap,
ReservedWrapsProvider reservedWrapsProvider) {
+ final JavaCodeStyleSettings javaSettings = settings.getRootSettings().getCustomSettings(JavaCodeStyleSettings.class);
ASTNode directParent = child.getTreeParent();
int role = ((CompositeElement)directParent).getChildRole(child);
@@ -153,7 +156,7 @@ public class JavaChildWrapArranger {
if (prev != null && prev.getElementType() == JavaElementType.MODIFIER_LIST) {
ASTNode last = prev.getLastChildNode();
if (last != null && last.getElementType() == JavaElementType.ANNOTATION) {
- if (isTypeAnnotation(last.getPsi())) {
+ if (isTypeAnnotation(last.getPsi()) || javaSettings.DO_NOT_WRAP_AFTER_SINGLE_ANNOTATION && isFieldModifierListWithSingleAnnotation(prev)) {
return Wrap.createWrap(WrapType.NONE, false);
}
else {
@@ -182,6 +185,10 @@ public class JavaChildWrapArranger {
ASTNode prev = FormatterUtil.getPreviousNonWhitespaceSibling(child);
if (prev != null && prev.getElementType() == JavaElementType.ANNOTATION) {
+ if (javaSettings.DO_NOT_WRAP_AFTER_SINGLE_ANNOTATION && isFieldModifierListWithSingleAnnotation(parent)) {
+ return Wrap.createWrap(WrapType.NONE, false);
+ }
+
return Wrap.createWrap(getWrapType(getAnnotationWrapType(parent.getTreeParent(), child, settings)), true);
}
@@ -256,6 +263,23 @@ public class JavaChildWrapArranger {
return suggestedWrap;
}
+ private static boolean isFieldModifierListWithSingleAnnotation(@NotNull ASTNode elem) {
+ ASTNode parent = elem.getTreeParent();
+ if (parent != null && parent.getElementType() == JavaElementType.FIELD) {
+ return isModifierListWithSingleAnnotation(elem);
+ }
+ return false;
+ }
+
+ private static boolean isModifierListWithSingleAnnotation(@NotNull ASTNode elem) {
+ if (elem.getPsi() instanceof PsiModifierList) {
+ if (((PsiModifierList)elem.getPsi()).getAnnotations().length == 1) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private static int getAnnotationWrapType(ASTNode parent, ASTNode child, CommonCodeStyleSettings settings) {
IElementType nodeType = parent.getElementType();
diff --git a/java/java-impl/src/com/intellij/psi/impl/file/PsiPackageImplementationHelperImpl.java b/java/java-impl/src/com/intellij/psi/impl/file/PsiPackageImplementationHelperImpl.java
index 658ee6561e68..0c49938053f0 100644
--- a/java/java-impl/src/com/intellij/psi/impl/file/PsiPackageImplementationHelperImpl.java
+++ b/java/java-impl/src/com/intellij/psi/impl/file/PsiPackageImplementationHelperImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,11 +24,11 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
-import com.intellij.openapi.module.ModuleUtil;
-import com.intellij.openapi.roots.impl.ModifiableModelCommitter;
+import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.*;
-import com.intellij.openapi.vfs.VfsUtil;
+import com.intellij.openapi.roots.impl.ModifiableModelCommitter;
+import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowId;
@@ -37,6 +37,9 @@ import com.intellij.psi.*;
import com.intellij.psi.impl.PackagePrefixElementFinder;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiModificationTracker;
+import com.intellij.psi.util.PsiUtil;
+import com.intellij.psi.util.PsiUtilCore;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.model.java.JavaModuleSourceRootTypes;
import java.util.ArrayList;
@@ -46,22 +49,25 @@ import java.util.List;
* @author yole
*/
public class PsiPackageImplementationHelperImpl extends PsiPackageImplementationHelper {
+ @NotNull
@Override
- public GlobalSearchScope adjustAllScope(PsiPackage psiPackage, GlobalSearchScope globalSearchScope) {
+ public GlobalSearchScope adjustAllScope(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope globalSearchScope) {
return NonClasspathClassFinder.addNonClasspathScope(psiPackage.getProject(), globalSearchScope);
}
+ @NotNull
@Override
- public VirtualFile[] occursInPackagePrefixes(PsiPackage psiPackage) {
+ public VirtualFile[] occursInPackagePrefixes(@NotNull PsiPackage psiPackage) {
List<VirtualFile> result = new ArrayList<VirtualFile>();
final Module[] modules = ModuleManager.getInstance(psiPackage.getProject()).getModules();
+ String qualifiedName = psiPackage.getQualifiedName();
for (final Module module : modules) {
for (final ContentEntry contentEntry : ModuleRootManager.getInstance(module).getContentEntries()) {
final List<SourceFolder> sourceFolders = contentEntry.getSourceFolders(JavaModuleSourceRootTypes.SOURCES);
for (final SourceFolder sourceFolder : sourceFolders) {
final String packagePrefix = sourceFolder.getPackagePrefix();
- if (packagePrefix.startsWith(psiPackage.getQualifiedName())) {
+ if (packagePrefix.startsWith(qualifiedName)) {
final VirtualFile file = sourceFolder.getFile();
if (file != null) {
result.add(file);
@@ -71,11 +77,11 @@ public class PsiPackageImplementationHelperImpl extends PsiPackageImplementation
}
}
- return VfsUtil.toVirtualFileArray(result);
+ return VfsUtilCore.toVirtualFileArray(result);
}
@Override
- public void handleQualifiedNameChange(final PsiPackage psiPackage, final String newQualifiedName) {
+ public void handleQualifiedNameChange(@NotNull final PsiPackage psiPackage, @NotNull final String newQualifiedName) {
ApplicationManager.getApplication().assertWriteAccessAllowed();
final String oldQualifedName = psiPackage.getQualifiedName();
final boolean anyChanged = changePackagePrefixes(psiPackage, oldQualifedName, newQualifiedName);
@@ -94,7 +100,7 @@ public class PsiPackageImplementationHelperImpl extends PsiPackageImplementation
}
}
- private static boolean changePackagePrefixes(PsiPackage psiPackage, final String oldQualifiedName, final String newQualifiedName) {
+ private static boolean changePackagePrefixes(@NotNull PsiPackage psiPackage, @NotNull String oldQualifiedName, @NotNull String newQualifiedName) {
final Module[] modules = ModuleManager.getInstance(psiPackage.getProject()).getModules();
List<ModifiableRootModel> modelsToCommit = new ArrayList<ModifiableRootModel>();
for (final Module module : modules) {
@@ -128,7 +134,7 @@ public class PsiPackageImplementationHelperImpl extends PsiPackageImplementation
}
@Override
- public void navigate(final PsiPackage psiPackage, final boolean requestFocus) {
+ public void navigate(@NotNull final PsiPackage psiPackage, final boolean requestFocus) {
final Project project = psiPackage.getProject();
ToolWindow window = ToolWindowManager.getInstance(project).getToolWindow(ToolWindowId.PROJECT_VIEW);
window.activate(null);
@@ -143,7 +149,8 @@ public class PsiPackageImplementationHelperImpl extends PsiPackageImplementation
});
}
- private static PsiDirectory[] suggestMostAppropriateDirectories(PsiPackage psiPackage) {
+ @NotNull
+ private static PsiDirectory[] suggestMostAppropriateDirectories(@NotNull PsiPackage psiPackage) {
final Project project = psiPackage.getProject();
PsiDirectory[] directories = null;
final Editor editor = FileEditorManager.getInstance(project).getSelectedTextEditor();
@@ -151,10 +158,20 @@ public class PsiPackageImplementationHelperImpl extends PsiPackageImplementation
final Document document = editor.getDocument();
final PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(document);
if (psiFile != null) {
- final Module module = ModuleUtil.findModuleForPsiElement(psiFile);
+ final Module module = ModuleUtilCore.findModuleForPsiElement(psiFile);
if (module != null) {
- directories = psiPackage.getDirectories(GlobalSearchScope.moduleWithDependenciesScope(module));
- } else {
+ final VirtualFile virtualFile = PsiUtilCore.getVirtualFile(psiFile);
+ final boolean isInTests =
+ virtualFile != null && ModuleRootManager.getInstance(module).getFileIndex().isInTestSourceContent(virtualFile);
+ if (isInTests) {
+ directories = psiPackage.getDirectories(GlobalSearchScope.moduleTestsWithDependentsScope(module));
+ }
+
+ if (directories == null || directories.length == 0) {
+ directories = psiPackage.getDirectories(GlobalSearchScope.moduleWithDependenciesScope(module));
+ }
+ }
+ else {
directories = psiPackage.getDirectories(GlobalSearchScope.notScope(GlobalSearchScope.projectScope(project)));
}
}
@@ -167,12 +184,13 @@ public class PsiPackageImplementationHelperImpl extends PsiPackageImplementation
}
@Override
- public boolean packagePrefixExists(PsiPackage psiPackage) {
+ public boolean packagePrefixExists(@NotNull PsiPackage psiPackage) {
return PackagePrefixElementFinder.getInstance(psiPackage.getProject()).packagePrefixExists(psiPackage.getQualifiedName());
}
+ @NotNull
@Override
- public Object[] getDirectoryCachedValueDependencies(PsiPackage psiPackage) {
+ public Object[] getDirectoryCachedValueDependencies(@NotNull PsiPackage psiPackage) {
return new Object[] { PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT, ProjectRootManager.getInstance(psiPackage.getProject()) };
}
}
diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethod/AbstractExtractDialog.java b/java/java-impl/src/com/intellij/refactoring/extractMethod/AbstractExtractDialog.java
index 7e49181472b0..9f83b6ed080b 100644
--- a/java/java-impl/src/com/intellij/refactoring/extractMethod/AbstractExtractDialog.java
+++ b/java/java-impl/src/com/intellij/refactoring/extractMethod/AbstractExtractDialog.java
@@ -20,25 +20,18 @@
*/
package com.intellij.refactoring.extractMethod;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.psi.PsiModifier;
import com.intellij.refactoring.util.VariableData;
-public abstract class AbstractExtractDialog extends DialogWrapper {
- protected AbstractExtractDialog(Project project) {
- super(project, true);
- }
-
-
- public abstract String getChosenMethodName();
-
- public abstract VariableData[] getChosenParameters();
+public interface AbstractExtractDialog {
+ String getChosenMethodName();
+ VariableData[] getChosenParameters();
@PsiModifier.ModifierConstant
- public abstract String getVisibility();
-
- public abstract boolean isMakeStatic();
+ String getVisibility();
+ boolean isMakeStatic();
+ boolean isChainedConstructor();
- public abstract boolean isChainedConstructor();
+ void show();
+ boolean isOK();
} \ No newline at end of file
diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodDialog.java b/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodDialog.java
index f4cfccb496ad..fc933de2b80e 100644
--- a/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodDialog.java
+++ b/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodDialog.java
@@ -21,6 +21,7 @@ import com.intellij.openapi.editor.event.DocumentAdapter;
import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Splitter;
import com.intellij.openapi.ui.VerticalFlowLayout;
import com.intellij.openapi.util.text.StringUtil;
@@ -59,7 +60,7 @@ import java.awt.event.*;
* @author Konstantin Bulenkov
*/
@SuppressWarnings("MethodMayBeStatic")
-public class ExtractMethodDialog extends AbstractExtractDialog {
+public class ExtractMethodDialog extends DialogWrapper implements AbstractExtractDialog {
public static final String EXTRACT_METHOD_DEFAULT_VISIBILITY = "extract.method.default.visibility";
private final Project myProject;
private final PsiType myReturnType;
@@ -96,7 +97,7 @@ public class ExtractMethodDialog extends AbstractExtractDialog {
String title,
String helpId,
final PsiElement[] elementsToExtract) {
- super(project);
+ super(project, true);
myProject = project;
myTargetClass = targetClass;
myReturnType = returnType;
diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java b/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java
index c61c29c58ff9..0b760502384a 100644
--- a/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java
+++ b/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java
@@ -463,14 +463,14 @@ public class ExtractMethodProcessor implements MatchProvider {
protected void apply(final AbstractExtractDialog dialog) {
myMethodName = dialog.getChosenMethodName();
myVariableDatum = dialog.getChosenParameters();
- myStatic |= dialog.isMakeStatic();
+ myStatic = isStatic() | dialog.isMakeStatic();
myIsChainedConstructor = dialog.isChainedConstructor();
myMethodVisibility = dialog.getVisibility();
}
protected AbstractExtractDialog createExtractMethodDialog(final boolean direct) {
- return new ExtractMethodDialog(myProject, myTargetClass, myInputVariables, myReturnType, myTypeParameterList,
- myThrownExceptions, myStatic, myCanBeStatic, myCanBeChainedConstructor,
+ return new ExtractMethodDialog(myProject, myTargetClass, myInputVariables, myReturnType, getTypeParameterList(),
+ getThrownExceptions(), isStatic(), isCanBeStatic(), myCanBeChainedConstructor,
suggestInitialMethodName(),
myRefactoringName, myHelpId, myElements) {
protected boolean areTypesDirected() {
@@ -575,10 +575,16 @@ public class ExtractMethodProcessor implements MatchProvider {
chooseAnchor();
- int col = myEditor.getCaretModel().getLogicalPosition().column;
- int line = myEditor.getCaretModel().getLogicalPosition().line;
- LogicalPosition pos = new LogicalPosition(0, 0);
- myEditor.getCaretModel().moveToLogicalPosition(pos);
+ LogicalPosition pos1;
+ if (myEditor != null) {
+ int col = myEditor.getCaretModel().getLogicalPosition().column;
+ int line = myEditor.getCaretModel().getLogicalPosition().line;
+ pos1 = new LogicalPosition(line, col);
+ LogicalPosition pos = new LogicalPosition(0, 0);
+ myEditor.getCaretModel().moveToLogicalPosition(pos);
+ } else {
+ pos1 = null;
+ }
final SearchScope processConflictsScope = myMethodVisibility.equals(PsiModifier.PRIVATE) ?
new LocalSearchScope(myTargetClass) :
@@ -610,17 +616,18 @@ public class ExtractMethodProcessor implements MatchProvider {
ApplicationManager.getApplication().runWriteAction(extract);
}
- LogicalPosition pos1 = new LogicalPosition(line, col);
- myEditor.getCaretModel().moveToLogicalPosition(pos1);
- int offset = myMethodCall.getMethodExpression().getTextRange().getStartOffset();
- myEditor.getCaretModel().moveToOffset(offset);
- myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
- myEditor.getSelectionModel().removeSelection();
+ if (myEditor != null) {
+ myEditor.getCaretModel().moveToLogicalPosition(pos1);
+ int offset = myMethodCall.getMethodExpression().getTextRange().getStartOffset();
+ myEditor.getCaretModel().moveToOffset(offset);
+ myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
+ myEditor.getSelectionModel().removeSelection();
+ }
}
- private void doExtract() throws IncorrectOperationException {
+ public void doExtract() throws IncorrectOperationException {
- PsiMethod newMethod = generateEmptyMethod(myThrownExceptions, myStatic);
+ PsiMethod newMethod = generateEmptyMethod(getThrownExceptions(), isStatic());
myExpression = myInputVariables.replaceWrappedReferences(myElements, myExpression);
renameInputVariables();
@@ -991,6 +998,10 @@ public class ExtractMethodProcessor implements MatchProvider {
return myTargetClass;
}
+ public PsiType getReturnType() {
+ return myReturnType;
+ }
+
private PsiMethod generateEmptyMethod(PsiClassType[] exceptions, boolean isStatic) throws IncorrectOperationException {
PsiMethod newMethod;
if (myIsChainedConstructor) {
@@ -1001,8 +1012,8 @@ public class ExtractMethodProcessor implements MatchProvider {
PsiUtil.setModifierProperty(newMethod, PsiModifier.STATIC, isStatic);
}
PsiUtil.setModifierProperty(newMethod, myMethodVisibility, true);
- if (myTypeParameterList != null) {
- newMethod.getTypeParameterList().replace(myTypeParameterList);
+ if (getTypeParameterList() != null) {
+ newMethod.getTypeParameterList().replace(getTypeParameterList());
}
PsiCodeBlock body = newMethod.getBody();
LOG.assertTrue(body != null);
@@ -1400,4 +1411,28 @@ public class ExtractMethodProcessor implements MatchProvider {
public InputVariables getInputVariables() {
return myInputVariables;
}
+
+ public PsiTypeParameterList getTypeParameterList() {
+ return myTypeParameterList;
+ }
+
+ public PsiClassType[] getThrownExceptions() {
+ return myThrownExceptions;
+ }
+
+ public boolean isStatic() {
+ return myStatic;
+ }
+
+ public boolean isCanBeStatic() {
+ return myCanBeStatic;
+ }
+
+ public PsiElement[] getElements() {
+ return myElements;
+ }
+
+ public PsiVariable[] getOutputVariables() {
+ return myOutputVariables;
+ }
}
diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractLightMethodObjectHandler.java b/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractLightMethodObjectHandler.java
new file mode 100644
index 000000000000..bb465b9848bb
--- /dev/null
+++ b/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractLightMethodObjectHandler.java
@@ -0,0 +1,254 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.refactoring.extractMethodObject;
+
+import com.intellij.codeInsight.CodeInsightUtil;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Condition;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.*;
+import com.intellij.psi.codeStyle.CodeStyleManager;
+import com.intellij.psi.codeStyle.JavaCodeStyleManager;
+import com.intellij.psi.controlFlow.*;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.refactoring.extractMethod.AbstractExtractDialog;
+import com.intellij.refactoring.extractMethod.InputVariables;
+import com.intellij.refactoring.extractMethod.PrepareFailedException;
+import com.intellij.refactoring.util.RefactoringUtil;
+import com.intellij.refactoring.util.VariableData;
+import com.intellij.usageView.UsageInfo;
+import com.intellij.util.Function;
+import com.intellij.util.IncorrectOperationException;
+import com.intellij.util.VisibilityUtil;
+import com.intellij.util.containers.ContainerUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+
+public class ExtractLightMethodObjectHandler {
+ private static final Logger LOG = Logger.getInstance("#" + ExtractLightMethodObjectHandler.class.getName());
+
+ public static class ExtractedData {
+ private String myGeneratedCallText;
+ private PsiClass myGeneratedInnerClass;
+ private final PsiElement myAnchor;
+
+ public ExtractedData(String generatedCallText, PsiClass generatedInnerClass, PsiElement anchor) {
+ myGeneratedCallText = generatedCallText;
+ myGeneratedInnerClass = generatedInnerClass;
+ myAnchor = anchor;
+ }
+
+ public PsiElement getAnchor() {
+ return myAnchor;
+ }
+
+ public String getGeneratedCallText() {
+ return myGeneratedCallText;
+ }
+
+ public PsiClass getGeneratedInnerClass() {
+ return myGeneratedInnerClass;
+ }
+ }
+
+ @Nullable
+ public static ExtractedData extractLightMethodObject(final Project project,
+ final PsiFile file,
+ @NotNull final PsiCodeFragment fragment,
+ final String methodName) throws PrepareFailedException {
+ PsiExpression expression = CodeInsightUtil.findExpressionInRange(fragment, 0, fragment.getTextLength());
+ final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project);
+ final PsiElement[] elements;
+ if (expression != null) {
+ elements = new PsiElement[] {elementFactory.createStatementFromText(expression.getText() + ";", expression)};
+ } else {
+ elements = CodeInsightUtil.findStatementsInRange(fragment, 0, fragment.getTextLength());
+ }
+ if (elements.length == 0) {
+ return null;
+ }
+
+ final PsiFile copy = PsiFileFactory.getInstance(project)
+ .createFileFromText(file.getName(), file.getFileType(), file.getText(), file.getModificationStamp(), false);
+
+ final PsiElement originalContext = fragment.getContext();
+ if (originalContext == null) {
+ return null;
+ }
+ final TextRange range = originalContext.getTextRange();
+ final PsiElement originalAnchor =
+ CodeInsightUtil.findElementInRange(copy, range.getStartOffset(), range.getEndOffset(), originalContext.getClass());
+ //todo before this or super, not found etc
+ final PsiElement anchor = RefactoringUtil.getParentStatement(originalAnchor, false);
+ final PsiElement container = anchor.getParent();
+ final PsiElement firstElementCopy = container.addRangeBefore(elements[0], elements[elements.length - 1], anchor);
+ final PsiElement[] elementsCopy = CodeInsightUtil.findStatementsInRange(copy,
+ firstElementCopy.getTextRange().getStartOffset(),
+ anchor.getTextRange().getStartOffset());
+ if (elementsCopy[elementsCopy.length - 1] instanceof PsiExpressionStatement) {
+ final PsiExpression expr = ((PsiExpressionStatement)elementsCopy[elementsCopy.length - 1]).getExpression();
+ if (!(expr instanceof PsiAssignmentExpression)) {
+ final PsiType expressionType = expr.getType();
+ if (expressionType != null && expressionType != PsiType.VOID) {
+ final String uniqueResultName = JavaCodeStyleManager.getInstance(project).suggestUniqueVariableName("result", elementsCopy[0], true);
+ final String statementText = expressionType.getCanonicalText() + " " + uniqueResultName + " = " + expr.getText() + ";";
+ elementsCopy[elementsCopy.length - 1] = elementsCopy[elementsCopy.length - 1]
+ .replace(elementFactory.createStatementFromText(statementText, elementsCopy[elementsCopy.length - 1]));
+ }
+ }
+ }
+
+ LOG.assertTrue(elementsCopy[0].getParent() == container, "element: " + elementsCopy[0].getText() + "; container: " + container.getText());
+ final int startOffsetInContainer = elementsCopy[0].getStartOffsetInParent();
+
+ final ControlFlow controlFlow;
+ try {
+ controlFlow = ControlFlowFactory.getInstance(project).getControlFlow(container, LocalsOrMyInstanceFieldsControlFlowPolicy.getInstance());
+ }
+ catch (AnalysisCanceledException e) {
+ return null;
+ }
+
+ List<PsiVariable> variables = ControlFlowUtil.getUsedVariables(controlFlow,
+ controlFlow.getStartOffset(elementsCopy[0]),
+ controlFlow.getEndOffset(elementsCopy[elementsCopy.length - 1]));
+
+ variables = ContainerUtil.filter(variables, new Condition<PsiVariable>() {
+ @Override
+ public boolean value(PsiVariable variable) {
+ final PsiElement variableScope = variable instanceof PsiParameter ? ((PsiParameter)variable).getDeclarationScope()
+ : PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class, PsiForStatement.class);
+ return variableScope != null && PsiTreeUtil.isAncestor(variableScope, elementsCopy[elementsCopy.length - 1], false);
+ }
+ });
+
+
+ final String outputVariables = StringUtil.join(variables, new Function<PsiVariable, String>() {
+ @Override
+ public String fun(PsiVariable variable) {
+ return "\"variable: \" + " + variable.getName();
+ }
+ }, " +");
+ PsiStatement outStatement = elementFactory.createStatementFromText("System.out.println(" + outputVariables + ");", anchor);
+ outStatement = (PsiStatement)container.addAfter(outStatement, elementsCopy[elementsCopy.length - 1]);
+
+ copy.accept(new JavaRecursiveElementWalkingVisitor() {
+ private void makePublic(PsiMember method) {
+ if (method.hasModifierProperty(PsiModifier.PRIVATE)) {
+ VisibilityUtil.setVisibility(method.getModifierList(), PsiModifier.PUBLIC);
+ }
+ }
+
+ @Override
+ public void visitMethod(PsiMethod method) {
+ super.visitMethod(method);
+ makePublic(method);
+ }
+
+ @Override
+ public void visitField(PsiField field) {
+ super.visitField(field);
+ makePublic(field);
+ }
+ });
+
+ final ExtractMethodObjectProcessor extractMethodObjectProcessor = new ExtractMethodObjectProcessor(project, null, elementsCopy, "") {
+ @Override
+ protected AbstractExtractDialog createExtractMethodObjectDialog(MyExtractMethodProcessor processor) {
+ return new LightExtractMethodObjectDialog(this, methodName);
+ }
+ };
+ extractMethodObjectProcessor.getExtractProcessor().setShowErrorDialogs(false);
+
+ final ExtractMethodObjectProcessor.MyExtractMethodProcessor extractProcessor = extractMethodObjectProcessor.getExtractProcessor();
+ if (extractProcessor.prepare()) {
+ if (extractProcessor.showDialog()) {
+ try {
+ extractProcessor.doExtract();
+ final UsageInfo[] usages = extractMethodObjectProcessor.findUsages();
+ extractMethodObjectProcessor.performRefactoring(usages);
+ extractMethodObjectProcessor.runChangeSignature();
+ }
+ catch (IncorrectOperationException e) {
+ LOG.error(e);
+ }
+ if (extractMethodObjectProcessor.isCreateInnerClass()) {
+ extractMethodObjectProcessor.changeInstanceAccess(project);
+ }
+ final PsiElement method = extractMethodObjectProcessor.getMethod();
+ LOG.assertTrue(method != null);
+ method.delete();
+ }
+ } else {
+ return null;
+ }
+
+ final int startOffset = startOffsetInContainer + container.getTextRange().getStartOffset();
+ final String generatedCall = copy.getText().substring(startOffset, outStatement.getTextOffset());
+ return new ExtractedData(generatedCall,
+ (PsiClass)CodeStyleManager.getInstance(project).reformat(extractMethodObjectProcessor.getInnerClass()),
+ originalAnchor);
+ }
+
+
+ private static class LightExtractMethodObjectDialog implements AbstractExtractDialog {
+ private final ExtractMethodObjectProcessor myProcessor;
+ private final String myMethodName;
+
+ public LightExtractMethodObjectDialog(ExtractMethodObjectProcessor processor, String methodName) {
+ myProcessor = processor;
+ myMethodName = methodName;
+ }
+
+ @Override
+ public String getChosenMethodName() {
+ return myMethodName;
+ }
+
+ @Override
+ public VariableData[] getChosenParameters() {
+ final InputVariables inputVariables = myProcessor.getExtractProcessor().getInputVariables();
+ return inputVariables.getInputVariables().toArray(new VariableData[inputVariables.getInputVariables().size()]);
+ }
+
+ @Override
+ public String getVisibility() {
+ return PsiModifier.PUBLIC;
+ }
+
+ @Override
+ public boolean isMakeStatic() {
+ return false;
+ }
+
+ @Override
+ public boolean isChainedConstructor() {
+ return false;
+ }
+
+ @Override
+ public void show() {}
+
+ @Override
+ public boolean isOK() {
+ return true;
+ }
+ }
+}
diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectDialog.java b/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectDialog.java
index fddd19bb4630..f79280fd1365 100644
--- a/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectDialog.java
+++ b/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectDialog.java
@@ -19,6 +19,7 @@ import com.intellij.openapi.editor.event.DocumentAdapter;
import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.help.HelpManager;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.psi.*;
@@ -44,7 +45,7 @@ import java.awt.event.ActionListener;
import java.util.Enumeration;
-public class ExtractMethodObjectDialog extends AbstractExtractDialog {
+public class ExtractMethodObjectDialog extends DialogWrapper implements AbstractExtractDialog {
private final Project myProject;
private final PsiType myReturnType;
private final PsiTypeParameterList myTypeParameterList;
@@ -86,7 +87,7 @@ public class ExtractMethodObjectDialog extends AbstractExtractDialog {
public ExtractMethodObjectDialog(Project project, PsiClass targetClass, final InputVariables inputVariables, PsiType returnType,
PsiTypeParameterList typeParameterList, PsiType[] exceptions, boolean isStatic, boolean canBeStatic,
final PsiElement[] elementsToExtract, final boolean multipleExitPoints) {
- super(project);
+ super(project, true);
myProject = project;
myTargetClass = targetClass;
myReturnType = returnType;
diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectHandler.java b/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectHandler.java
index d8fb3fd6ef87..459a7030457f 100644
--- a/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectHandler.java
+++ b/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectHandler.java
@@ -30,9 +30,7 @@ import com.intellij.openapi.editor.ScrollType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pass;
import com.intellij.openapi.util.TextRange;
-import com.intellij.psi.PsiDocumentManager;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiFile;
+import com.intellij.psi.*;
import com.intellij.psi.impl.source.PostprocessReformattingAspect;
import com.intellij.refactoring.HelpID;
import com.intellij.refactoring.RefactoringActionHandler;
@@ -55,7 +53,10 @@ public class ExtractMethodObjectHandler implements RefactoringActionHandler {
});
}
- private void invokeOnElements(@NotNull final Project project, @NotNull final Editor editor, @NotNull PsiFile file, @NotNull PsiElement[] elements) {
+ private static void invokeOnElements(@NotNull final Project project,
+ @NotNull final Editor editor,
+ @NotNull PsiFile file,
+ @NotNull PsiElement[] elements) {
if (elements.length == 0) {
String message = RefactoringBundle
.getCannotRefactorMessage(RefactoringBundle.message("selected.block.should.represent.a.set.of.statements.or.an.expression"));
@@ -63,17 +64,18 @@ public class ExtractMethodObjectHandler implements RefactoringActionHandler {
return;
}
- final ExtractMethodObjectProcessor processor = new ExtractMethodObjectProcessor(project, editor, elements, "");
- final ExtractMethodObjectProcessor.MyExtractMethodProcessor extractProcessor = processor.getExtractProcessor();
try {
- if (!extractProcessor.prepare()) return;
+ extractMethodObject(project, editor, new ExtractMethodObjectProcessor(project, editor, elements, ""));
}
catch (PrepareFailedException e) {
CommonRefactoringUtil.showErrorHint(project, editor, e.getMessage(), ExtractMethodObjectProcessor.REFACTORING_NAME, HelpID.EXTRACT_METHOD_OBJECT);
ExtractMethodHandler.highlightPrepareError(e, file, editor, project);
- return;
}
+ }
+ static void extractMethodObject(Project project, Editor editor, ExtractMethodObjectProcessor processor) throws PrepareFailedException {
+ final ExtractMethodObjectProcessor.MyExtractMethodProcessor extractProcessor = processor.getExtractProcessor();
+ if (!extractProcessor.prepare()) return;
if (!CommonRefactoringUtil.checkReadOnlyStatus(project, extractProcessor.getTargetClass().getContainingFile())) return;
if (extractProcessor.showDialog()) {
run(project, editor, processor, extractProcessor);
@@ -81,11 +83,16 @@ public class ExtractMethodObjectHandler implements RefactoringActionHandler {
}
public static void run(@NotNull final Project project,
- @NotNull final Editor editor,
+ final Editor editor,
@NotNull final ExtractMethodObjectProcessor processor,
@NotNull final ExtractMethodObjectProcessor.MyExtractMethodProcessor extractProcessor) {
- final int offset = editor.getCaretModel().getOffset();
- final RangeMarker marker = editor.getDocument().createRangeMarker(new TextRange(offset, offset));
+ final RangeMarker marker;
+ if (editor != null) {
+ final int offset = editor.getCaretModel().getOffset();
+ marker = editor.getDocument().createRangeMarker(new TextRange(offset, offset));
+ } else {
+ marker = null;
+ }
CommandProcessor.getInstance().executeCommand(project, new Runnable() {
public void run() {
PostprocessReformattingAspect.getInstance(project).postponeFormattingInside(new Runnable() {
@@ -98,7 +105,11 @@ public class ExtractMethodObjectHandler implements RefactoringActionHandler {
}
});
processor.run();
- processor.runChangeSignature();
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ public void run() {
+ processor.runChangeSignature();
+ }
+ });
}
catch (IncorrectOperationException e) {
LOG.error(e);
@@ -110,7 +121,9 @@ public class ExtractMethodObjectHandler implements RefactoringActionHandler {
if (processor.isCreateInnerClass()) {
processor.moveUsedMethodsToInner();
PsiDocumentManager.getInstance(project).commitAllDocuments();
- DuplicatesImpl.processDuplicates(extractProcessor, project, editor);
+ if (editor != null) {
+ DuplicatesImpl.processDuplicates(extractProcessor, project, editor);
+ }
}
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
@@ -125,9 +138,11 @@ public class ExtractMethodObjectHandler implements RefactoringActionHandler {
});
}
}, ExtractMethodObjectProcessor.REFACTORING_NAME, ExtractMethodObjectProcessor.REFACTORING_NAME);
- editor.getCaretModel().moveToOffset(marker.getStartOffset());
- marker.dispose();
- editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
+ if (editor != null) {
+ editor.getCaretModel().moveToOffset(marker.getStartOffset());
+ marker.dispose();
+ editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
+ }
}
public void invoke(@NotNull final Project project, @NotNull final PsiElement[] elements, final DataContext dataContext) {
diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectProcessor.java b/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectProcessor.java
index 7f95c49c65b3..49f4b2727cee 100644
--- a/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectProcessor.java
+++ b/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectProcessor.java
@@ -37,10 +37,13 @@ import com.intellij.psi.codeStyle.VariableKind;
import com.intellij.psi.controlFlow.ControlFlowUtil;
import com.intellij.psi.impl.source.PsiImmediateClassType;
import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.search.LocalSearchScope;
+import com.intellij.psi.search.SearchScope;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.PropertyUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
+import com.intellij.psi.util.PsiUtilCore;
import com.intellij.refactoring.BaseRefactoringProcessor;
import com.intellij.refactoring.HelpID;
import com.intellij.refactoring.changeSignature.ChangeSignatureProcessor;
@@ -52,6 +55,7 @@ import com.intellij.refactoring.ui.MemberSelectionPanel;
import com.intellij.refactoring.util.RefactoringUtil;
import com.intellij.refactoring.util.classMembers.MemberInfo;
import com.intellij.refactoring.util.duplicates.Match;
+import com.intellij.testFramework.LightVirtualFile;
import com.intellij.usageView.UsageInfo;
import com.intellij.usageView.UsageViewDescriptor;
import com.intellij.usageView.UsageViewUtil;
@@ -82,7 +86,7 @@ public class ExtractMethodObjectProcessor extends BaseRefactoringProcessor {
private boolean myMadeStatic = false;
private final Set<MethodToMoveUsageInfo> myUsages = new LinkedHashSet<MethodToMoveUsageInfo>();
private PsiClass myInnerClass;
- private ChangeSignatureProcessor myChangeSignatureProcessor;
+ private boolean myChangeReturnType;
private Runnable myCopyMethodToInner;
public ExtractMethodObjectProcessor(Project project, Editor editor, PsiElement[] elements, final String innerClassName) {
@@ -100,8 +104,12 @@ public class ExtractMethodObjectProcessor extends BaseRefactoringProcessor {
@NotNull
protected UsageInfo[] findUsages() {
final ArrayList<UsageInfo> result = new ArrayList<UsageInfo>();
+ final PsiClass containingClass = getMethod().getContainingClass();
+ final SearchScope scope = PsiUtilCore.getVirtualFile(containingClass) == null
+ ? new LocalSearchScope(containingClass)
+ : GlobalSearchScope.projectScope(myProject);
PsiReference[] refs =
- ReferencesSearch.search(getMethod(), GlobalSearchScope.projectScope(myProject), false).toArray(PsiReference.EMPTY_ARRAY);
+ ReferencesSearch.search(getMethod(), scope, false).toArray(PsiReference.EMPTY_ARRAY);
for (PsiReference ref : refs) {
final PsiElement element = ref.getElement();
if (element != null && element.isValid()) {
@@ -141,7 +149,7 @@ public class ExtractMethodObjectProcessor extends BaseRefactoringProcessor {
return UsageViewUtil.removeDuplicatedUsages(usageInfos);
}
- protected void performRefactoring(final UsageInfo[] usages) {
+ public void performRefactoring(final UsageInfo[] usages) {
try {
if (isCreateInnerClass()) {
myInnerClass = (PsiClass)getMethod().getContainingClass().add(myElementFactory.createClass(getInnerClassName()));
@@ -258,12 +266,6 @@ public class ExtractMethodObjectProcessor extends BaseRefactoringProcessor {
myInnerClass.add(GenerateMembersUtil.generateGetterPrototype(field));
}
- PsiParameter[] params = getMethod().getParameterList().getParameters();
- ParameterInfoImpl[] infos = new ParameterInfoImpl[params.length];
- for (int i = 0; i < params.length; i++) {
- PsiParameter param = params[i];
- infos[i] = new ParameterInfoImpl(i, param.getName(), param.getType());
- }
final PsiCodeBlock body = getMethod().getBody();
LOG.assertTrue(body != null);
final LinkedHashSet<PsiLocalVariable> vars = new LinkedHashSet<PsiLocalVariable>();
@@ -320,7 +322,7 @@ public class ExtractMethodObjectProcessor extends BaseRefactoringProcessor {
for (PsiElement declaredElement : declaredElements) {
if (declaredElement instanceof PsiVariable) {
for (PsiVariable variable : outputVariables) {
- PsiLocalVariable var = (PsiLocalVariable)declaredElement;
+ PsiVariable var = (PsiVariable)declaredElement;
if (Comparing.strEqual(var.getName(), variable.getName())) {
final PsiExpression initializer = var.getInitializer();
if (initializer == null) {
@@ -385,23 +387,25 @@ public class ExtractMethodObjectProcessor extends BaseRefactoringProcessor {
}
}
- myChangeSignatureProcessor = new ChangeSignatureProcessor(myProject, getMethod(), false, null, getMethod().getName(),
- new PsiImmediateClassType(myInnerClass, PsiSubstitutor.EMPTY), infos);
+ myChangeReturnType = true;
}
void runChangeSignature() {
- if (myChangeSignatureProcessor != null) {
- myChangeSignatureProcessor.run();
- }
if (myCopyMethodToInner != null) {
- ApplicationManager.getApplication().runWriteAction(myCopyMethodToInner);
+ myCopyMethodToInner.run();
+ }
+ if (myChangeReturnType) {
+ final PsiTypeElement typeElement = ((PsiLocalVariable)((PsiDeclarationStatement)JavaPsiFacade.getElementFactory(myProject)
+ .createStatementFromText(myInnerClassName + " l =null;", myInnerClass)).getDeclaredElements()[0]).getTypeElement();
+ final PsiTypeElement innerMethodReturnTypeElement = myInnerMethod.getReturnTypeElement();
+ LOG.assertTrue(innerMethodReturnTypeElement != null);
+ innerMethodReturnTypeElement.replace(typeElement);
}
}
private String getPureName(PsiVariable var) {
final JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(myProject);
- final VariableKind kind = var instanceof PsiLocalVariable ? VariableKind.LOCAL_VARIABLE : VariableKind.PARAMETER;
- return styleManager.variableNameToPropertyName(var.getName(), kind);
+ return styleManager.variableNameToPropertyName(var.getName(), styleManager.getVariableKind(var));
}
public PsiExpression processMethodDeclaration( PsiExpressionList expressionList) throws IncorrectOperationException {
@@ -624,6 +628,22 @@ public class ExtractMethodObjectProcessor extends BaseRefactoringProcessor {
return myExtractProcessor;
}
+ protected AbstractExtractDialog createExtractMethodObjectDialog(final MyExtractMethodProcessor processor) {
+ return new ExtractMethodObjectDialog(myProject, processor.getTargetClass(), processor.getInputVariables(), processor.getReturnType(),
+ processor.getTypeParameterList(),
+ processor.getThrownExceptions(), processor.isStatic(), processor.isCanBeStatic(),
+ processor.getElements(), myMultipleExitPoints){
+ @Override
+ protected boolean isUsedAfter(PsiVariable variable) {
+ return ArrayUtil.find(processor.getOutputVariables(), variable) != -1;
+ }
+ };
+ }
+
+ public PsiClass getInnerClass() {
+ return myInnerClass;
+ }
+
public class MyExtractMethodProcessor extends ExtractMethodProcessor {
public MyExtractMethodProcessor(Project project,
@@ -640,19 +660,13 @@ public class ExtractMethodObjectProcessor extends BaseRefactoringProcessor {
@Override
protected void apply(final AbstractExtractDialog dialog) {
super.apply(dialog);
- myCreateInnerClass = ((ExtractMethodObjectDialog)dialog).createInnerClass();
+ myCreateInnerClass = !(dialog instanceof ExtractMethodObjectDialog) || ((ExtractMethodObjectDialog)dialog).createInnerClass();
myInnerClassName = myCreateInnerClass ? StringUtil.capitalize(dialog.getChosenMethodName()) : dialog.getChosenMethodName();
}
@Override
protected AbstractExtractDialog createExtractMethodDialog(final boolean direct) {
- return new ExtractMethodObjectDialog(myProject, myTargetClass, myInputVariables, myReturnType, myTypeParameterList,
- myThrownExceptions, myStatic, myCanBeStatic, myElements, myMultipleExitPoints){
- @Override
- protected boolean isUsedAfter(PsiVariable variable) {
- return ArrayUtil.find(myOutputVariables, variable) != -1;
- }
- };
+ return createExtractMethodObjectDialog(this);
}
@Override
diff --git a/java/java-impl/src/com/intellij/refactoring/inheritanceToDelegation/InheritanceToDelegationDialog.java b/java/java-impl/src/com/intellij/refactoring/inheritanceToDelegation/InheritanceToDelegationDialog.java
index 32e4992fe744..efff2b7790cd 100644
--- a/java/java-impl/src/com/intellij/refactoring/inheritanceToDelegation/InheritanceToDelegationDialog.java
+++ b/java/java-impl/src/com/intellij/refactoring/inheritanceToDelegation/InheritanceToDelegationDialog.java
@@ -33,7 +33,6 @@ import com.intellij.refactoring.ui.NameSuggestionsField;
import com.intellij.refactoring.ui.RefactoringDialog;
import com.intellij.refactoring.util.classMembers.InterfaceMemberDependencyGraph;
import com.intellij.refactoring.util.classMembers.MemberInfo;
-import com.intellij.util.containers.HashMap;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -45,6 +44,7 @@ import java.awt.event.ItemListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.HashMap;
public class InheritanceToDelegationDialog extends RefactoringDialog {
private final PsiClass[] mySuperClasses;
diff --git a/java/java-impl/src/com/intellij/refactoring/inheritanceToDelegation/InheritanceToDelegationHandler.java b/java/java-impl/src/com/intellij/refactoring/inheritanceToDelegation/InheritanceToDelegationHandler.java
index c9daa8c1bbdb..7cc464bcb710 100644
--- a/java/java-impl/src/com/intellij/refactoring/inheritanceToDelegation/InheritanceToDelegationHandler.java
+++ b/java/java-impl/src/com/intellij/refactoring/inheritanceToDelegation/InheritanceToDelegationHandler.java
@@ -41,13 +41,10 @@ import com.intellij.refactoring.util.RefactoringHierarchyUtil;
import com.intellij.refactoring.util.RefactoringMessageUtil;
import com.intellij.refactoring.util.classMembers.MemberInfo;
import com.intellij.refactoring.util.classMembers.MemberInfoStorage;
-import com.intellij.util.containers.HashMap;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
+import java.util.*;
public class InheritanceToDelegationHandler implements RefactoringActionHandler {
private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.inheritanceToDelegation.InheritanceToDelegationHandler");
@@ -106,23 +103,26 @@ public class InheritanceToDelegationHandler implements RefactoringActionHandler
if (!CommonRefactoringUtil.checkReadOnlyStatus(project, aClass)) return;
- final PsiClass[] bases = aClass.getSupers();
+ PsiClass[] bases = aClass.getSupers();
@NonNls final String javaLangObject = CommonClassNames.JAVA_LANG_OBJECT;
+
if (bases.length == 0 || bases.length == 1 && javaLangObject.equals(bases[0].getQualifiedName())) {
String message = RefactoringBundle.getCannotRefactorMessage(RefactoringBundle.message("class.does.not.have.base.classes.or.interfaces", aClass.getQualifiedName()));
CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, HelpID.INHERITANCE_TO_DELEGATION);
return;
}
- final HashMap<PsiClass, Collection<MemberInfo>> basesToMemberInfos = new HashMap<PsiClass, Collection<MemberInfo>>();
+ final HashMap<PsiClass, Collection<MemberInfo>> basesToMemberInfos = new LinkedHashMap<PsiClass, Collection<MemberInfo>>();
for (PsiClass base : bases) {
+ if (javaLangObject.equals(base.getQualifiedName())) continue;
basesToMemberInfos.put(base, createBaseClassMemberInfos(base));
}
+ final Set<PsiClass> baseClasses = basesToMemberInfos.keySet();
new InheritanceToDelegationDialog(project, aClass,
- bases, basesToMemberInfos).show();
+ baseClasses.toArray(new PsiClass[baseClasses.size()]), basesToMemberInfos).show();
}
private static List<MemberInfo> createBaseClassMemberInfos(PsiClass baseClass) {
diff --git a/java/java-impl/src/com/intellij/refactoring/util/RefactoringUtil.java b/java/java-impl/src/com/intellij/refactoring/util/RefactoringUtil.java
index ed08349519a7..0cc9819c4574 100644
--- a/java/java-impl/src/com/intellij/refactoring/util/RefactoringUtil.java
+++ b/java/java-impl/src/com/intellij/refactoring/util/RefactoringUtil.java
@@ -30,10 +30,7 @@ import com.intellij.openapi.editor.markup.RangeHighlighter;
import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectRootManager;
-import com.intellij.openapi.util.Comparing;
-import com.intellij.openapi.util.Condition;
-import com.intellij.openapi.util.Pair;
-import com.intellij.openapi.util.TextRange;
+import com.intellij.openapi.util.*;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
@@ -1045,13 +1042,13 @@ public class RefactoringUtil {
}
public static void fixJavadocsForParams(PsiMethod method, Set<PsiParameter> newParameters) throws IncorrectOperationException {
- fixJavadocsForParams(method, newParameters, Condition.FALSE);
+ fixJavadocsForParams(method, newParameters, Conditions.<Pair<PsiParameter,String>>alwaysFalse());
}
public static void fixJavadocsForParams(PsiMethod method,
Set<PsiParameter> newParameters,
Condition<Pair<PsiParameter, String>> eqCondition) throws IncorrectOperationException {
- fixJavadocsForParams(method, newParameters, eqCondition, Condition.TRUE);
+ fixJavadocsForParams(method, newParameters, eqCondition, Conditions.<String>alwaysTrue());
}
public static void fixJavadocsForParams(PsiMethod method,
@@ -1245,7 +1242,7 @@ public class RefactoringUtil {
@Nullable
public static PsiTypeParameterList createTypeParameterListWithUsedTypeParameters(@Nullable final PsiTypeParameterList fromList,
@NotNull final PsiElement... elements) {
- return createTypeParameterListWithUsedTypeParameters(fromList, Condition.TRUE, elements);
+ return createTypeParameterListWithUsedTypeParameters(fromList, Conditions.<PsiTypeParameter>alwaysTrue(), elements);
}
@Nullable
@@ -1290,7 +1287,7 @@ public class RefactoringUtil {
}
public static void collectTypeParameters(final Set<PsiTypeParameter> used, final PsiElement element) {
- collectTypeParameters(used, element, Condition.TRUE);
+ collectTypeParameters(used, element, Conditions.<PsiTypeParameter>alwaysTrue());
}
public static void collectTypeParameters(final Set<PsiTypeParameter> used, final PsiElement element,
final Condition<PsiTypeParameter> filter) {
diff --git a/java/java-indexing-api/src/com/intellij/psi/search/searches/ClassInheritorsSearch.java b/java/java-indexing-api/src/com/intellij/psi/search/searches/ClassInheritorsSearch.java
index cc6bf9d3044d..ec3599fec62e 100644
--- a/java/java-indexing-api/src/com/intellij/psi/search/searches/ClassInheritorsSearch.java
+++ b/java/java-indexing-api/src/com/intellij/psi/search/searches/ClassInheritorsSearch.java
@@ -21,10 +21,7 @@ import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressIndicatorProvider;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.Computable;
-import com.intellij.openapi.util.Condition;
-import com.intellij.openapi.util.Pair;
-import com.intellij.openapi.util.Ref;
+import com.intellij.openapi.util.*;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PsiSearchScopeUtil;
@@ -106,7 +103,7 @@ public class ClassInheritorsSearch extends ExtensibleQueryFactory<PsiClass, Clas
private final InheritanceChecker myInheritanceChecker;
public SearchParameters(@NotNull final PsiClass aClass, @NotNull SearchScope scope, final boolean checkDeep, final boolean checkInheritance, boolean includeAnonymous) {
- this(aClass, scope, checkDeep, checkInheritance, includeAnonymous, Condition.TRUE);
+ this(aClass, scope, checkDeep, checkInheritance, includeAnonymous, Conditions.<String>alwaysTrue());
}
public SearchParameters(@NotNull final PsiClass aClass, @NotNull SearchScope scope, final boolean checkDeep, final boolean checkInheritance,
@@ -170,7 +167,12 @@ public class ClassInheritorsSearch extends ExtensibleQueryFactory<PsiClass, Clas
}
public static Query<PsiClass> search(@NotNull final PsiClass aClass, final boolean checkDeep) {
- return search(aClass, aClass.getUseScope(), checkDeep);
+ return search(aClass, ApplicationManager.getApplication().runReadAction(new Computable<SearchScope>() {
+ @Override
+ public SearchScope compute() {
+ return aClass.getUseScope();
+ }
+ }), checkDeep);
}
public static Query<PsiClass> search(@NotNull PsiClass aClass) {
diff --git a/java/java-psi-api/src/com/intellij/psi/GenericsUtil.java b/java/java-psi-api/src/com/intellij/psi/GenericsUtil.java
index c835a4171f74..4646aea635b3 100644
--- a/java/java-psi-api/src/com/intellij/psi/GenericsUtil.java
+++ b/java/java-psi-api/src/com/intellij/psi/GenericsUtil.java
@@ -262,7 +262,9 @@ public class GenericsUtil {
for (PsiTypeParameter typeParameter : typeParams) {
PsiType substituted = substitutor.substitute(typeParameter);
if (substituted == null) return null;
- substituted = PsiUtil.captureToplevelWildcards(substituted, context);
+ if (context != null) {
+ substituted = PsiUtil.captureToplevelWildcards(substituted, context);
+ }
PsiClassType[] extendsTypes = typeParameter.getExtendsListTypes();
for (PsiClassType type : extendsTypes) {
diff --git a/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java b/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java
index fcf5e8945e7a..8ff42ca085a0 100644
--- a/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java
+++ b/java/java-psi-api/src/com/intellij/psi/LambdaUtil.java
@@ -477,6 +477,17 @@ public class LambdaUtil {
return true;
}
+ //JLS 14.8 Expression Statements
+ public static boolean isExpressionStatementExpression(PsiElement body) {
+ return body instanceof PsiAssignmentExpression ||
+ body instanceof PsiPrefixExpression &&
+ (((PsiPrefixExpression)body).getOperationTokenType() == JavaTokenType.PLUSPLUS ||
+ ((PsiPrefixExpression)body).getOperationTokenType() == JavaTokenType.MINUSMINUS) ||
+ body instanceof PsiPostfixExpression ||
+ body instanceof PsiCallExpression ||
+ body instanceof PsiReferenceExpression && !body.isPhysical();
+ }
+
public static class TypeParamsChecker extends PsiTypeVisitor<Boolean> {
private PsiMethod myMethod;
private final PsiClass myClass;
diff --git a/java/java-psi-api/src/com/intellij/psi/PsiPackage.java b/java/java-psi-api/src/com/intellij/psi/PsiPackage.java
index ed68dc2ac204..65e0af8265ad 100644
--- a/java/java-psi-api/src/com/intellij/psi/PsiPackage.java
+++ b/java/java-psi-api/src/com/intellij/psi/PsiPackage.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -111,7 +111,7 @@ public interface PsiPackage extends PsiCheckedRenameElement, NavigationItem, Psi
@NonNls
String getName();
- boolean containsClassNamed(String name);
+ boolean containsClassNamed(@NotNull String name);
@NotNull
PsiClass[] findClassByShortName(@NotNull String name, @NotNull GlobalSearchScope scope);
diff --git a/java/java-psi-api/src/com/intellij/psi/util/ClassUtil.java b/java/java-psi-api/src/com/intellij/psi/util/ClassUtil.java
index 9f7f6e2cc164..b5b72565da19 100644
--- a/java/java-psi-api/src/com/intellij/psi/util/ClassUtil.java
+++ b/java/java-psi-api/src/com/intellij/psi/util/ClassUtil.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -33,6 +33,7 @@ public class ClassUtil {
return null;
}
+ @NotNull
public static String extractClassName(@NotNull String fqName) {
int i = fqName.lastIndexOf('.');
return i == -1 ? fqName : fqName.substring(i + 1);
@@ -58,7 +59,7 @@ public class ClassUtil {
return null;
}
- public static void formatClassName(@NotNull final PsiClass aClass, final StringBuilder buf) {
+ public static void formatClassName(@NotNull final PsiClass aClass, @NotNull StringBuilder buf) {
final String qName = aClass.getQualifiedName();
if (qName != null) {
buf.append(qName);
@@ -78,7 +79,7 @@ public class ClassUtil {
}
@Nullable
- private static PsiClass getContainerClass(final PsiClass aClass) {
+ private static PsiClass getContainerClass(@NotNull PsiClass aClass) {
PsiElement parent = aClass.getContext();
while (parent != null && !(parent instanceof PsiClass)) {
parent = parent.getContext();
@@ -113,11 +114,11 @@ public class ClassUtil {
return result[0];
}
- public static PsiClass findNonQualifiedClassByIndex(final String indexName, @NotNull final PsiClass containingClass) {
+ public static PsiClass findNonQualifiedClassByIndex(@NotNull String indexName, @NotNull final PsiClass containingClass) {
return findNonQualifiedClassByIndex(indexName, containingClass, false);
}
- public static PsiClass findNonQualifiedClassByIndex(final String indexName, @NotNull final PsiClass containingClass,
+ public static PsiClass findNonQualifiedClassByIndex(@NotNull String indexName, @NotNull final PsiClass containingClass,
final boolean jvmCompatible) {
String prefix = getDigitPrefix(indexName);
final int idx = !prefix.isEmpty() ? Integer.parseInt(prefix) : -1;
@@ -167,6 +168,7 @@ public class ClassUtil {
return result[0];
}
+ @NotNull
private static String getDigitPrefix(@NotNull String indexName) {
int i;
for (i = 0; i < indexName.length(); i++) {
@@ -186,24 +188,24 @@ public class ClassUtil {
* @return found psiClass
*/
@Nullable
- public static PsiClass findPsiClass(final PsiManager psiManager, String externalName){
+ public static PsiClass findPsiClass(@NotNull PsiManager psiManager, @NotNull String externalName){
return findPsiClass(psiManager, externalName, null, false);
}
@Nullable
- public static PsiClass findPsiClass(final PsiManager psiManager,
- String externalName,
+ public static PsiClass findPsiClass(@NotNull PsiManager psiManager,
+ @NotNull String externalName,
PsiClass psiClass,
boolean jvmCompatible) {
return findPsiClass(psiManager, externalName, psiClass, jvmCompatible, GlobalSearchScope.allScope(psiManager.getProject()));
}
@Nullable
- public static PsiClass findPsiClass(final PsiManager psiManager,
- String externalName,
+ public static PsiClass findPsiClass(@NotNull PsiManager psiManager,
+ @NotNull String externalName,
@Nullable PsiClass psiClass,
boolean jvmCompatible,
- final GlobalSearchScope scope) {
+ @NotNull GlobalSearchScope scope) {
for (int pos = 0; pos < externalName.length(); pos++) {
if (externalName.charAt(pos) == '$') {
PsiClass parentClass = psiClass;
@@ -220,8 +222,8 @@ public class ClassUtil {
}
@Nullable
- private static PsiClass findSubclass(final PsiManager psiManager,
- final String externalName,
+ private static PsiClass findSubclass(@NotNull PsiManager psiManager,
+ @NotNull String externalName,
final PsiClass psiClass,
final boolean jvmCompatible) {
for (int pos = 0; pos < externalName.length(); pos++) {
@@ -251,7 +253,7 @@ public class ClassUtil {
@Nullable
- public static PsiClass findPsiClassByJVMName(final PsiManager manager, final String jvmClassName) {
+ public static PsiClass findPsiClassByJVMName(@NotNull PsiManager manager, @NotNull String jvmClassName) {
return findPsiClass(manager, jvmClassName.replace('/', '.'), null, true);
}
} \ No newline at end of file
diff --git a/java/java-psi-api/src/com/intellij/psi/util/MethodSignatureBase.java b/java/java-psi-api/src/com/intellij/psi/util/MethodSignatureBase.java
index 150a39c4d647..de1c4bf3336a 100644
--- a/java/java-psi-api/src/com/intellij/psi/util/MethodSignatureBase.java
+++ b/java/java-psi-api/src/com/intellij/psi/util/MethodSignatureBase.java
@@ -75,6 +75,7 @@ public abstract class MethodSignatureBase implements MethodSignature {
return myTypeParameters;
}
+ @NotNull
public PsiType[] getErasedParameterTypes() {
PsiType[] result = myErasedParameterTypes;
if (result == null) {
diff --git a/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java b/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java
index b38bb494c1e7..a7f92056a195 100644
--- a/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java
+++ b/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java
@@ -1108,8 +1108,11 @@ public final class PsiUtil extends PsiUtilCore {
}
public static PsiReturnStatement[] findReturnStatements(PsiMethod method) {
+ return findReturnStatements(method.getBody());
+ }
+
+ public static PsiReturnStatement[] findReturnStatements(PsiCodeBlock body) {
ArrayList<PsiReturnStatement> vector = new ArrayList<PsiReturnStatement>();
- PsiCodeBlock body = method.getBody();
if (body != null) {
addReturnStatements(vector, body);
}
diff --git a/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilderBase.java b/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilderBase.java
index f4154bc4fe1a..9b6c23e79b00 100644
--- a/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilderBase.java
+++ b/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilderBase.java
@@ -625,6 +625,11 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem
}
int leftStart = method.getParameterList().getTextRange().getEndOffset();
+ int bodyStart = body.getTextRange().getStartOffset();
+ if (bodyStart > leftStart && !StringUtil.isEmptyOrSpaces(document.getCharsSequence().subSequence(leftStart + 1, bodyStart))) {
+ return false;
+ }
+
int leftEnd = statement.getTextRange().getStartOffset();
int rightStart = statement.getTextRange().getEndOffset();
int rightEnd = body.getTextRange().getEndOffset();
diff --git a/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java b/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java
index 1f642b18d1b1..67b1ef813de8 100644
--- a/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java
+++ b/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java
@@ -501,6 +501,7 @@ public class JavaDocInfoGenerator {
buffer.append("<b>");
buffer.append(field.getName());
appendInitializer(buffer, field);
+ enumConstantOrdinal(buffer, field, field.getContainingClass(), "\n");
buffer.append("</b>");
}
@@ -638,7 +639,7 @@ public class JavaDocInfoGenerator {
String text = o.toString();
PsiType type = variable.getType();
if (type.equalsToText(CommonClassNames.JAVA_LANG_STRING)) {
- text = "\"" + StringUtil.shortenPathWithEllipsis(text, 120) + "\"";
+ text = "\"" + StringUtil.escapeLineBreak(StringUtil.shortenPathWithEllipsis(text, 120)) + "\"";
}
else if (type.equalsToText("char")) text = "'" + text + "'";
try {
@@ -754,7 +755,20 @@ public class JavaDocInfoGenerator {
}
final PsiAnnotationMemberValue value = pair.getValue();
if (value != null) {
- buffer.append(XmlStringUtil.escapeString(value.getText()));
+ if (value instanceof PsiArrayInitializerMemberValue) {
+ buffer.append("{");
+ boolean firstMember = true;
+
+ for(PsiAnnotationMemberValue memberValue:((PsiArrayInitializerMemberValue)value).getInitializers()) {
+ if (!firstMember) buffer.append(",");
+ firstMember = false;
+
+ appendLinkOrText(buffer, memberValue, generateLink);
+ }
+ buffer.append("}");
+ } else {
+ appendLinkOrText(buffer, value, generateLink);
+ }
}
}
buffer.append(")");
@@ -778,6 +792,32 @@ public class JavaDocInfoGenerator {
}
}
+ private static void appendLinkOrText(StringBuilder buffer,
+ PsiAnnotationMemberValue memberValue,
+ boolean generateLink) {
+ if (generateLink && memberValue instanceof PsiQualifiedReferenceElement) {
+ String text = ((PsiQualifiedReferenceElement)memberValue).getCanonicalText();
+ PsiElement resolve = ((PsiQualifiedReferenceElement)memberValue).resolve();
+
+ if (resolve instanceof PsiField) {
+ PsiField field = (PsiField)resolve;
+ PsiClass aClass = field.getContainingClass();
+ int startOfPropertyNamePosition = text.lastIndexOf('.');
+
+ if (startOfPropertyNamePosition != -1) {
+ text = text.substring(0, startOfPropertyNamePosition) + '#' + text.substring(startOfPropertyNamePosition + 1);
+ }
+ else {
+ if (aClass != null) text = aClass.getQualifiedName() + '#' + field.getName();
+ }
+ generateLink(buffer, text, aClass != null? aClass.getName() + '.' + field.getName():null, memberValue, false);
+ return;
+ }
+ }
+
+ buffer.append(XmlStringUtil.escapeString(memberValue.getText()));
+ }
+
public static boolean isDocumentedAnnotationType(@Nullable PsiElement annotationType) {
return annotationType instanceof PsiClass && AnnotationUtil.isAnnotated((PsiClass)annotationType, "java.lang.annotation.Documented", false);
}
diff --git a/java/java-psi-impl/src/com/intellij/core/CorePsiPackageImplementationHelper.java b/java/java-psi-impl/src/com/intellij/core/CorePsiPackageImplementationHelper.java
index 5a97f596d983..51e010e05d29 100644
--- a/java/java-psi-impl/src/com/intellij/core/CorePsiPackageImplementationHelper.java
+++ b/java/java-psi-impl/src/com/intellij/core/CorePsiPackageImplementationHelper.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiPackage;
import com.intellij.psi.impl.file.PsiPackageImplementationHelper;
import com.intellij.psi.search.GlobalSearchScope;
+import org.jetbrains.annotations.NotNull;
/**
* @author yole
@@ -27,31 +28,34 @@ import com.intellij.psi.search.GlobalSearchScope;
public class CorePsiPackageImplementationHelper extends PsiPackageImplementationHelper {
private static final ModificationTracker[] EMPTY_DEPENDENCY = {ModificationTracker.NEVER_CHANGED};
+ @NotNull
@Override
- public GlobalSearchScope adjustAllScope(PsiPackage psiPackage, GlobalSearchScope globalSearchScope) {
+ public GlobalSearchScope adjustAllScope(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope globalSearchScope) {
return globalSearchScope;
}
+ @NotNull
@Override
- public VirtualFile[] occursInPackagePrefixes(PsiPackage psiPackage) {
+ public VirtualFile[] occursInPackagePrefixes(@NotNull PsiPackage psiPackage) {
return VirtualFile.EMPTY_ARRAY;
}
@Override
- public void handleQualifiedNameChange(PsiPackage psiPackage, String newQualifiedName) {
+ public void handleQualifiedNameChange(@NotNull PsiPackage psiPackage, @NotNull String newQualifiedName) {
}
@Override
- public void navigate(PsiPackage psiPackage, boolean requestFocus) {
+ public void navigate(@NotNull PsiPackage psiPackage, boolean requestFocus) {
}
@Override
- public boolean packagePrefixExists(PsiPackage psiPackage) {
+ public boolean packagePrefixExists(@NotNull PsiPackage psiPackage) {
return false;
}
+ @NotNull
@Override
- public Object[] getDirectoryCachedValueDependencies(PsiPackage cachedValueProvider) {
+ public Object[] getDirectoryCachedValueDependencies(@NotNull PsiPackage cachedValueProvider) {
return EMPTY_DEPENDENCY;
}
}
diff --git a/java/java-psi-impl/src/com/intellij/psi/NonClasspathClassFinder.java b/java/java-psi-impl/src/com/intellij/psi/NonClasspathClassFinder.java
index 59a4e10d40fe..7fc4a2245941 100644
--- a/java/java-psi-impl/src/com/intellij/psi/NonClasspathClassFinder.java
+++ b/java/java-psi-impl/src/com/intellij/psi/NonClasspathClassFinder.java
@@ -248,7 +248,7 @@ public abstract class NonClasspathClassFinder extends PsiElementFinder {
}
@NotNull
- public static GlobalSearchScope addNonClasspathScope(Project project, GlobalSearchScope base) {
+ public static GlobalSearchScope addNonClasspathScope(@NotNull Project project, @NotNull GlobalSearchScope base) {
GlobalSearchScope scope = base;
for (PsiElementFinder finder : Extensions.getExtensions(EP_NAME, project)) {
if (finder instanceof NonClasspathClassFinder) {
diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java
index 9c9525aef859..d53bb2e26820 100644
--- a/java/java-psi-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java
+++ b/java/java-psi-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java
@@ -389,7 +389,7 @@ public class PsiSubstitutorImpl implements PsiSubstitutor {
}
else {
//unbounded
- substituted = PsiWildcardType.createExtends(manager, substitutedBoundType);
+ substituted = substitutedBoundType instanceof PsiCapturedWildcardType ? ((PsiCapturedWildcardType)substitutedBoundType).getWildcard() : PsiWildcardType.createExtends(manager, substitutedBoundType);
}
}
}
diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsFileImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsFileImpl.java
index 6ab8174ce28a..20c11a7ccb39 100644
--- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsFileImpl.java
+++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsFileImpl.java
@@ -27,8 +27,7 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.extensions.PluginId;
import com.intellij.openapi.fileTypes.FileType;
-import com.intellij.openapi.progress.NonCancelableSection;
-import com.intellij.openapi.progress.ProgressIndicatorProvider;
+import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.DefaultProjectFactory;
import com.intellij.openapi.roots.FileIndexFacade;
import com.intellij.openapi.ui.Queryable;
@@ -323,7 +322,7 @@ public class ClsFileImpl extends ClsRepositoryPsiElement<PsiClassHolderFileStub>
synchronized (myMirrorLock) {
mirrorTreeElement = myMirrorFileElement;
if (mirrorTreeElement == null) {
- VirtualFile file = getVirtualFile();
+ final VirtualFile file = getVirtualFile();
CharSequence mirrorText = ClassFileDecompiler.decompileText(file);
String ext = JavaFileType.INSTANCE.getDefaultExtension();
@@ -335,16 +334,18 @@ public class ClsFileImpl extends ClsRepositoryPsiElement<PsiClassHolderFileStub>
mirrorTreeElement = SourceTreeToPsiMap.psiToTreeNotNull(mirror);
// IMPORTANT: do not take lock too early - FileDocumentManager.saveToString() can run write action
- NonCancelableSection section = ProgressIndicatorProvider.startNonCancelableSectionIfSupported();
- try {
- setMirror(mirrorTreeElement);
- }
- catch (InvalidMirrorException e) {
- LOG.error(file.getPath(), wrapException(e, file));
- }
- finally {
- section.done();
- }
+ final TreeElement finalMirrorTreeElement = mirrorTreeElement;
+ ProgressManager.getInstance().executeNonCancelableSection(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ setMirror(finalMirrorTreeElement);
+ }
+ catch (InvalidMirrorException e) {
+ LOG.error(file.getPath(), wrapException(e, file));
+ }
+ }
+ });
myMirrorFileElement = mirrorTreeElement;
}
diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/file/PsiPackageImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/file/PsiPackageImpl.java
index 9129052bf74f..93fd1ebbd935 100644
--- a/java/java-psi-impl/src/com/intellij/psi/impl/file/PsiPackageImpl.java
+++ b/java/java-psi-impl/src/com/intellij/psi/impl/file/PsiPackageImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@ import com.intellij.navigation.ItemPresentationProviders;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.ui.Queryable;
import com.intellij.openapi.util.Condition;
+import com.intellij.openapi.util.Conditions;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.impl.JavaPsiFacadeImpl;
@@ -46,7 +47,6 @@ import org.jetbrains.annotations.Nullable;
import java.util.*;
public class PsiPackageImpl extends PsiPackageBase implements PsiPackage, Queryable {
- public static boolean DEBUG = false;
private volatile CachedValue<PsiModifierList> myAnnotationList;
private volatile CachedValue<Collection<PsiDirectory>> myDirectories;
private volatile CachedValue<Collection<PsiDirectory>> myDirectoriesWithLibSources;
@@ -72,6 +72,7 @@ public class PsiPackageImpl extends PsiPackageBase implements PsiPackage, Querya
}
}
+ @NotNull
private CachedValue<Collection<PsiDirectory>> createCachedDirectories(final boolean includeLibrarySources) {
return CachedValuesManager.getManager(myManager.getProject()).createCachedValue(new CachedValueProvider<Collection<PsiDirectory>>() {
@Override
@@ -131,6 +132,7 @@ public class PsiPackageImpl extends PsiPackageBase implements PsiPackage, Querya
}
}
+ @Override
public String toString() {
return "PsiPackage:" + getQualifiedName();
}
@@ -141,6 +143,7 @@ public class PsiPackageImpl extends PsiPackageBase implements PsiPackage, Querya
return getClasses(allScope());
}
+ @NotNull
protected GlobalSearchScope allScope() {
return PsiPackageImplementationHelper.getInstance().adjustAllScope(this, GlobalSearchScope.allScope(getProject()));
}
@@ -177,7 +180,7 @@ public class PsiPackageImpl extends PsiPackageBase implements PsiPackage, Querya
}
@NotNull
- private PsiClass[] getCachedClassesByName(String name) {
+ private PsiClass[] getCachedClassesByName(@NotNull String name) {
if (DumbService.getInstance(getProject()).isDumb()) {
return getCachedClassInDumbMode(name);
}
@@ -215,7 +218,7 @@ public class PsiPackageImpl extends PsiPackageBase implements PsiPackage, Querya
}
@Override
- public boolean containsClassNamed(String name) {
+ public boolean containsClassNamed(@NotNull String name) {
return getCachedClassesByName(name).length > 0;
}
@@ -247,7 +250,7 @@ public class PsiPackageImpl extends PsiPackageBase implements PsiPackage, Querya
}
@Nullable
- private PsiPackage findSubPackageByName(String name) {
+ private PsiPackage findSubPackageByName(@NotNull String name) {
final String qName = getQualifiedName();
final String subpackageQName = qName.isEmpty() ? name : qName + "." + name;
return getFacade().findPackage(subpackageQName);
@@ -270,11 +273,11 @@ public class PsiPackageImpl extends PsiPackageBase implements PsiPackage, Querya
if (nameHint != null) {
final String shortName = nameHint.getName(state);
final PsiClass[] classes = findClassByShortName(shortName, scope);
- if (!processClasses(processor, state, classes, Condition.TRUE)) return false;
+ if (!processClasses(processor, state, classes, Conditions.<String>alwaysTrue())) return false;
}
else {
PsiClass[] classes = getClasses(scope);
- if (!processClasses(processor, state, classes, nameCondition != null ? nameCondition : Condition.TRUE)) return false;
+ if (!processClasses(processor, state, classes, nameCondition != null ? nameCondition : Conditions.<String>alwaysTrue())) return false;
}
}
if (classHint == null || classHint.shouldProcess(ElementClassHint.DeclarationKind.PACKAGE)) {
@@ -302,7 +305,9 @@ public class PsiPackageImpl extends PsiPackageBase implements PsiPackage, Querya
return true;
}
- private static boolean processClasses(PsiScopeProcessor processor, ResolveState state, PsiClass[] classes,
+ private static boolean processClasses(@NotNull PsiScopeProcessor processor,
+ @NotNull ResolveState state,
+ @NotNull PsiClass[] classes,
@NotNull Condition<String> nameCondition) {
for (PsiClass aClass : classes) {
String name = aClass.getName();
diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/file/PsiPackageImplementationHelper.java b/java/java-psi-impl/src/com/intellij/psi/impl/file/PsiPackageImplementationHelper.java
index 050786c617f0..4ca3f1fead43 100644
--- a/java/java-psi-impl/src/com/intellij/psi/impl/file/PsiPackageImplementationHelper.java
+++ b/java/java-psi-impl/src/com/intellij/psi/impl/file/PsiPackageImplementationHelper.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2011 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,22 +19,26 @@ import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiPackage;
import com.intellij.psi.search.GlobalSearchScope;
+import org.jetbrains.annotations.NotNull;
/**
* @author yole
*/
public abstract class PsiPackageImplementationHelper {
- public abstract GlobalSearchScope adjustAllScope(PsiPackage psiPackage, GlobalSearchScope globalSearchScope);
+ @NotNull
+ public abstract GlobalSearchScope adjustAllScope(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope globalSearchScope);
- public abstract VirtualFile[] occursInPackagePrefixes(PsiPackage psiPackage);
+ @NotNull
+ public abstract VirtualFile[] occursInPackagePrefixes(@NotNull PsiPackage psiPackage);
- public abstract void handleQualifiedNameChange(PsiPackage psiPackage, String newQualifiedName);
+ public abstract void handleQualifiedNameChange(@NotNull PsiPackage psiPackage, @NotNull String newQualifiedName);
- public abstract void navigate(PsiPackage psiPackage, boolean requestFocus);
+ public abstract void navigate(@NotNull PsiPackage psiPackage, boolean requestFocus);
- public abstract boolean packagePrefixExists(PsiPackage psiPackage);
+ public abstract boolean packagePrefixExists(@NotNull PsiPackage psiPackage);
- public abstract Object[] getDirectoryCachedValueDependencies(PsiPackage cachedValueProvider);
+ @NotNull
+ public abstract Object[] getDirectoryCachedValueDependencies(@NotNull PsiPackage cachedValueProvider);
public static PsiPackageImplementationHelper getInstance() {
return ServiceManager.getService(PsiPackageImplementationHelper.class);
diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiFieldImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiFieldImpl.java
index 78c5c2d8fdc8..fd38e3ddaf56 100644
--- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiFieldImpl.java
+++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiFieldImpl.java
@@ -399,9 +399,14 @@ public class PsiFieldImpl extends JavaStubPsiElement<PsiFieldStub> implements Ps
@Override
public PsiElement getOriginalElement() {
- PsiClass originalClass = (PsiClass)getContainingClass().getOriginalElement();
- PsiField originalField = originalClass.findFieldByName(getName(), false);
- return originalField != null ? originalField : this;
+ PsiClass containingClass = getContainingClass();
+ if (containingClass != null) {
+ PsiField originalField = ((PsiClass)containingClass.getOriginalElement()).findFieldByName(getName(), false);
+ if (originalField != null) {
+ return originalField;
+ }
+ }
+ return this;
}
@Override
diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiParameterImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiParameterImpl.java
index e77e7ad01f5e..799f9b459e69 100644
--- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiParameterImpl.java
+++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiParameterImpl.java
@@ -324,4 +324,24 @@ public class PsiParameterImpl extends JavaStubPsiElement<PsiParameterStub> imple
final PsiElement declarationScope = getDeclarationScope();
return new LocalSearchScope(declarationScope);
}
+
+ @Override
+ public PsiElement getOriginalElement() {
+ PsiElement parent = getParent();
+ if (parent instanceof PsiParameterList) {
+ PsiElement gParent = parent.getParent();
+ if (gParent instanceof PsiMethod) {
+ PsiElement originalMethod = gParent.getOriginalElement();
+ if (originalMethod instanceof PsiMethod) {
+ int index = ((PsiParameterList)parent).getParameterIndex(this);
+ PsiParameter[] originalParameters = ((PsiMethod)originalMethod).getParameterList().getParameters();
+ if (index < originalParameters.length) {
+ return originalParameters[index];
+ }
+ }
+ }
+ }
+ return this;
+ }
+
}
diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/PsiResolveHelperImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/PsiResolveHelperImpl.java
index 556bf7152b68..a27dfe5adb83 100644
--- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/PsiResolveHelperImpl.java
+++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/PsiResolveHelperImpl.java
@@ -15,7 +15,6 @@
*/
package com.intellij.psi.impl.source.resolve;
-import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
@@ -211,16 +210,8 @@ public class PsiResolveHelperImpl implements PsiResolveHelper {
.getSubstitutionForTypeParameter(typeParam, param, arg, isContraVariantPosition, languageLevel);
}
- private PsiInferenceHelper myTestHelper;
-
- public void setTestHelper(PsiInferenceHelper testHelper) {
- myTestHelper = testHelper;
- }
-
- public PsiInferenceHelper getInferenceHelper(LanguageLevel languageLevel) {
- if (ApplicationManager.getApplication().isUnitTestMode() && myTestHelper != null) {
- return myTestHelper;
- }
+ @NotNull
+ public PsiInferenceHelper getInferenceHelper(@NotNull LanguageLevel languageLevel) {
if (languageLevel.isAtLeast(LanguageLevel.JDK_1_8)) {
return new PsiGraphInferenceHelper(myManager);
}
diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java
index 35db6c29bc0c..a1b4570e5361 100644
--- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java
+++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java
@@ -174,7 +174,6 @@ public class InferenceSession {
}
}
}
- return true;
}
if (expr instanceof PsiLambdaExpression) {
if (!((PsiLambdaExpression)expr).hasFormalParameterTypes()) {
@@ -234,7 +233,7 @@ public class InferenceSession {
!MethodCandidateInfo.ourOverloadGuard.currentStack().contains(PsiUtil.skipParenthesizedExprUp(parent.getParent()))) {
final Set<ConstraintFormula> additionalConstraints = new LinkedHashSet<ConstraintFormula>();
if (parameters.length > 0) {
- collectAdditionalConstraints(parameters, args, properties.getMethod(), PsiSubstitutor.EMPTY, additionalConstraints, properties.isVarargs(), true);
+ collectAdditionalConstraints(parameters, args, properties.getMethod(), PsiSubstitutor.EMPTY, additionalConstraints, properties.isVarargs());
}
if (!additionalConstraints.isEmpty() && !proceedWithAdditionalConstraints(additionalConstraints)) {
@@ -264,67 +263,113 @@ public class InferenceSession {
PsiMethod parentMethod,
PsiSubstitutor siteSubstitutor,
Set<ConstraintFormula> additionalConstraints,
- boolean varargs, boolean toplevel) {
+ boolean varargs) {
for (int i = 0; i < args.length; i++) {
- if (args[i] != null) {
- InferenceSession session = myNestedSessions.get(PsiTreeUtil.getParentOfType(args[i], PsiCallExpression.class));
- if (session == null) {
- session = this;
- }
- PsiType parameterType = session.substituteWithInferenceVariables(getParameterType(parameters, i, siteSubstitutor, varargs));
- if (!isPertinentToApplicability(args[i], parentMethod)) {
- additionalConstraints.add(new ExpressionCompatibilityConstraint(args[i], parameterType));
+ final PsiExpression arg = PsiUtil.skipParenthesizedExprDown(args[i]);
+ if (arg != null) {
+ final InferenceSession nestedCallSession = findNestedCallSession(arg);
+ final PsiType parameterType =
+ nestedCallSession.substituteWithInferenceVariables(getParameterType(parameters, i, siteSubstitutor, varargs));
+ if (!isPertinentToApplicability(arg, parentMethod)) {
+ additionalConstraints.add(new ExpressionCompatibilityConstraint(arg, parameterType));
}
- additionalConstraints.add(new CheckedExceptionCompatibilityConstraint(args[i], parameterType));
- if (args[i] instanceof PsiCallExpression && PsiPolyExpressionUtil.isPolyExpression(args[i])) {
+ additionalConstraints.add(new CheckedExceptionCompatibilityConstraint(arg, parameterType));
+ if (arg instanceof PsiCallExpression) {
//If the expression is a poly class instance creation expression (15.9) or a poly method invocation expression (15.12),
//the set contains all constraint formulas that would appear in the set C when determining the poly expression's invocation type.
- final PsiCallExpression callExpression = (PsiCallExpression)args[i];
- collectAdditionalConstraints(additionalConstraints, callExpression);
- } else if (args[i] instanceof PsiLambdaExpression && toplevel) {
- final PsiType interfaceReturnType = LambdaUtil.getFunctionalInterfaceReturnType(parameterType);
- if (interfaceReturnType != null) {
- final List<PsiExpression> returnExpressions = LambdaUtil.getReturnExpressions((PsiLambdaExpression)args[i]);
- for (PsiExpression returnExpression : returnExpressions) {
- if (returnExpression instanceof PsiCallExpression) {
- final PsiCallExpression callExpression = (PsiCallExpression)returnExpression;
- collectAdditionalConstraints(additionalConstraints, callExpression);
- }
- }
+ final PsiMethod calledMethod = getCalledMethod((PsiCallExpression)arg);
+ if (PsiPolyExpressionUtil.isMethodCallPolyExpression(arg, calledMethod)) {
+ collectAdditionalConstraints(additionalConstraints, (PsiCallExpression)arg);
}
+ } else if (arg instanceof PsiLambdaExpression) {
+ collectLambdaReturnExpression(additionalConstraints, (PsiLambdaExpression)arg, parameterType);
}
}
}
}
+ private static PsiMethod getCalledMethod(PsiCallExpression arg) {
+ final PsiExpressionList argumentList = arg.getArgumentList();
+ if (argumentList == null || argumentList.getExpressions().length == 0) {
+ return null;
+ }
+
+ MethodCandidateInfo.CurrentCandidateProperties properties = MethodCandidateInfo.getCurrentMethod(argumentList);
+ if (properties != null) {
+ return properties.getMethod();
+ }
+ final JavaResolveResult resolveResult = getMethodResult(arg);
+ return resolveResult instanceof MethodCandidateInfo ? (PsiMethod)resolveResult.getElement() : null;
+ }
+
+ private void collectLambdaReturnExpression(Set<ConstraintFormula> additionalConstraints,
+ PsiLambdaExpression lambdaExpression,
+ PsiType parameterType) {
+ final PsiType interfaceReturnType = LambdaUtil.getFunctionalInterfaceReturnType(parameterType);
+ if (interfaceReturnType != null) {
+ final List<PsiExpression> returnExpressions = LambdaUtil.getReturnExpressions(lambdaExpression);
+ for (PsiExpression returnExpression : returnExpressions) {
+ processReturnExpression(additionalConstraints, returnExpression, interfaceReturnType);
+ }
+ }
+ }
+
+ private void processReturnExpression(Set<ConstraintFormula> additionalConstraints,
+ PsiExpression returnExpression,
+ PsiType functionalType) {
+ if (returnExpression instanceof PsiCallExpression) {
+ final PsiMethod calledMethod = getCalledMethod((PsiCallExpression)returnExpression);
+ if (PsiPolyExpressionUtil.isMethodCallPolyExpression(returnExpression, calledMethod)) {
+ collectAdditionalConstraints(additionalConstraints, (PsiCallExpression)returnExpression);
+ }
+ }
+ else if (returnExpression instanceof PsiParenthesizedExpression) {
+ processReturnExpression(additionalConstraints, ((PsiParenthesizedExpression)returnExpression).getExpression(), functionalType);
+ }
+ else if (returnExpression instanceof PsiConditionalExpression) {
+ processReturnExpression(additionalConstraints, ((PsiConditionalExpression)returnExpression).getThenExpression(), functionalType);
+ processReturnExpression(additionalConstraints, ((PsiConditionalExpression)returnExpression).getElseExpression(), functionalType);
+ }
+ else if (returnExpression instanceof PsiLambdaExpression) {
+ collectLambdaReturnExpression(additionalConstraints, (PsiLambdaExpression)returnExpression, functionalType);
+ }
+ }
+
private void collectAdditionalConstraints(final Set<ConstraintFormula> additionalConstraints,
final PsiCallExpression callExpression) {
PsiExpressionList argumentList = callExpression.getArgumentList();
if (argumentList != null) {
- final PsiLambdaExpression expression = PsiTreeUtil.getParentOfType(argumentList, PsiLambdaExpression.class);
- final Computable<JavaResolveResult> computableResolve = new Computable<JavaResolveResult>() {
- @Override
- public JavaResolveResult compute() {
- return callExpression.resolveMethodGenerics();
- }
- };
+ final JavaResolveResult result = getMethodResult(callExpression);
MethodCandidateInfo.CurrentCandidateProperties properties = MethodCandidateInfo.getCurrentMethod(argumentList);
- final JavaResolveResult result = properties != null ? null :
- expression == null
- ? computableResolve.compute()
- : PsiResolveHelper.ourGraphGuard.doPreventingRecursion(expression, false, computableResolve);
final PsiMethod method = result instanceof MethodCandidateInfo ? ((MethodCandidateInfo)result).getElement() : properties != null ? properties.getMethod() : null;
if (method != null) {
final PsiExpression[] newArgs = argumentList.getExpressions();
final PsiParameter[] newParams = method.getParameterList().getParameters();
if (newParams.length > 0) {
collectAdditionalConstraints(newParams, newArgs, method, result != null ? ((MethodCandidateInfo)result).getSiteSubstitutor() : properties.getSubstitutor(),
- additionalConstraints, result != null ? ((MethodCandidateInfo)result).isVarargs() : properties.isVarargs(), false);
+ additionalConstraints, result != null ? ((MethodCandidateInfo)result).isVarargs() : properties.isVarargs());
}
}
}
}
+ private static JavaResolveResult getMethodResult(final PsiCallExpression callExpression) {
+ final PsiExpressionList argumentList = callExpression.getArgumentList();
+
+ final PsiLambdaExpression expression = PsiTreeUtil.getParentOfType(argumentList, PsiLambdaExpression.class);
+ final Computable<JavaResolveResult> computableResolve = new Computable<JavaResolveResult>() {
+ @Override
+ public JavaResolveResult compute() {
+ return callExpression.resolveMethodGenerics();
+ }
+ };
+ MethodCandidateInfo.CurrentCandidateProperties properties = MethodCandidateInfo.getCurrentMethod(argumentList);
+ return properties != null ? null :
+ expression == null
+ ? computableResolve.compute()
+ : PsiResolveHelper.ourGraphGuard.doPreventingRecursion(expression, false, computableResolve);
+ }
+
public PsiSubstitutor retrieveNonPrimitiveEqualsBounds(Collection<InferenceVariable> variables) {
PsiSubstitutor substitutor = mySiteSubstitutor;
for (InferenceVariable variable : variables) {
@@ -702,7 +747,7 @@ public class InferenceSession {
}
final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(getManager().getProject());
- final PsiTypeParameter[] freshParameters = createFreshVariables(vars);
+ final PsiTypeParameter[] freshParameters = createFreshVariables(vars, substitutor);
for (int i = 0; i < freshParameters.length; i++) {
PsiTypeParameter parameter = freshParameters[i];
final InferenceVariable var = vars.get(i);
@@ -725,7 +770,7 @@ public class InferenceSession {
return substitutor;
}
- private PsiTypeParameter[] createFreshVariables(final List<InferenceVariable> vars) {
+ private PsiTypeParameter[] createFreshVariables(final List<InferenceVariable> vars, final PsiSubstitutor siteSubstitutor) {
final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(getManager().getProject());
PsiSubstitutor substitutor = PsiSubstitutor.EMPTY;
@@ -742,7 +787,7 @@ public class InferenceSession {
final String classText = "class I<" + StringUtil.join(vars, new Function<InferenceVariable, String>() {
@Override
public String fun(InferenceVariable variable) {
- final PsiType glb = composeBound(variable, InferenceBound.UPPER, UPPER_BOUND_FUNCTION, ySubstitutor, true);
+ final PsiType glb = composeBound(variable, InferenceBound.UPPER, UPPER_BOUND_FUNCTION, ySubstitutor.putAll(siteSubstitutor), true);
return getFreshVariableName(variable) + " extends " + glb.getInternalCanonicalText();
}
}, ", ") + ">{}";
@@ -860,46 +905,67 @@ public class InferenceSession {
//extract subset of constraints
final Set<ConstraintFormula> subset = buildSubset(additionalConstraints);
- //collect all input variables of selection
+ //collect all input variables of selection
final Set<InferenceVariable> varsToResolve = new LinkedHashSet<InferenceVariable>();
for (ConstraintFormula formula : subset) {
if (formula instanceof InputOutputConstraintFormula) {
- final Set<InferenceVariable> inputVariables = ((InputOutputConstraintFormula)formula).getInputVariables(this);
- if (inputVariables != null) {
- for (InferenceVariable inputVariable : inputVariables) {
- varsToResolve.addAll(inputVariable.getDependencies(this));
- }
- varsToResolve.addAll(inputVariables);
- }
+ collectVarsToResolve(varsToResolve, (InputOutputConstraintFormula)formula);
}
}
- //resolve input variables
- PsiSubstitutor substitutor = resolveSubset(varsToResolve, siteSubstitutor);
- if (substitutor == null) {
- return false;
+ for (ConstraintFormula formula : subset) {
+ if (!processOneConstraint(formula, siteSubstitutor, varsToResolve)) return false;
}
+ }
+ return true;
+ }
- if (myContext instanceof PsiCallExpression) {
- PsiExpressionList argumentList = ((PsiCallExpression)myContext).getArgumentList();
- LOG.assertTrue(argumentList != null);
- MethodCandidateInfo.updateSubstitutor(argumentList, substitutor);
+ private void collectVarsToResolve(Set<InferenceVariable> varsToResolve, InputOutputConstraintFormula formula) {
+ final Set<InferenceVariable> inputVariables = formula.getInputVariables(this);
+ if (inputVariables != null) {
+ for (InferenceVariable inputVariable : inputVariables) {
+ varsToResolve.addAll(inputVariable.getDependencies(this));
}
+ varsToResolve.addAll(inputVariables);
+ }
+ }
- try {
- for (ConstraintFormula additionalConstraint : subset) {
- additionalConstraint.apply(substitutor, true);
- }
-
- myConstraints.addAll(subset);
- if (!repeatInferencePhases(true)) {
- return false;
+ private boolean processOneConstraint(ConstraintFormula formula, PsiSubstitutor siteSubstitutor, Set<InferenceVariable> varsToResolve) {
+ if (formula instanceof ExpressionCompatibilityConstraint) {
+ final PsiExpression expression = ((ExpressionCompatibilityConstraint)formula).getExpression();
+ final PsiCallExpression callExpression = PsiTreeUtil.getParentOfType(expression, PsiCallExpression.class, false);
+ if (callExpression != null) {
+ final InferenceSession session = myNestedSessions.get(callExpression);
+ if (session != null) {
+ formula.apply(session.myInferenceSubstitution, true);
+ collectVarsToResolve(varsToResolve, (InputOutputConstraintFormula)formula);
}
}
- finally {
- LambdaUtil.ourFunctionTypes.set(null);
+ }
+
+ //resolve input variables
+ PsiSubstitutor substitutor = resolveSubset(varsToResolve, siteSubstitutor);
+ if (substitutor == null) {
+ return false;
+ }
+
+ if (myContext instanceof PsiCallExpression) {
+ PsiExpressionList argumentList = ((PsiCallExpression)myContext).getArgumentList();
+ LOG.assertTrue(argumentList != null);
+ MethodCandidateInfo.updateSubstitutor(argumentList, substitutor);
+ }
+
+ try {
+ formula.apply(substitutor, true);
+
+ myConstraints.add(formula);
+ if (!repeatInferencePhases(true)) {
+ return false;
}
}
+ finally {
+ LambdaUtil.ourFunctionTypes.set(null);
+ }
return true;
}
@@ -1139,9 +1205,6 @@ public class InferenceSession {
}
final List<PsiExpression> returnExpressions = LambdaUtil.getReturnExpressions((PsiLambdaExpression)arg);
- if (sReturnType == PsiType.VOID) {
- return returnExpressions.isEmpty() && session == null;
- }
if (LambdaUtil.isFunctionalType(sReturnType) && LambdaUtil.isFunctionalType(tReturnType) &&
!TypeConversionUtil.isAssignable(TypeConversionUtil.erasure(sReturnType), TypeConversionUtil.erasure(tReturnType)) &&
@@ -1197,10 +1260,6 @@ public class InferenceSession {
return true;
}
- if (sReturnType == PsiType.VOID && session != null) {
- return false;
- }
-
final boolean sPrimitive = sReturnType instanceof PsiPrimitiveType && sReturnType != PsiType.VOID;
final boolean tPrimitive = tReturnType instanceof PsiPrimitiveType && tReturnType != PsiType.VOID;
@@ -1295,6 +1354,14 @@ public class InferenceSession {
return myInferenceSubstitution.substitute(type);
}
+ public InferenceSession findNestedCallSession(PsiExpression arg) {
+ InferenceSession session = myNestedSessions.get(PsiTreeUtil.getParentOfType(arg, PsiCallExpression.class));
+ if (session == null) {
+ session = this;
+ }
+ return session;
+ }
+
public PsiType startWithFreshVars(PsiType type) {
PsiSubstitutor s = PsiSubstitutor.EMPTY;
for (InferenceVariable variable : myInferenceVariables) {
diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceVariable.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceVariable.java
index 8d91b620f798..da7b4b78930a 100644
--- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceVariable.java
+++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceVariable.java
@@ -17,6 +17,7 @@ package com.intellij.psi.impl.source.resolve.graphInference;
import com.intellij.psi.*;
import com.intellij.psi.impl.light.LightTypeParameter;
+import com.intellij.psi.util.PsiUtil;
import java.util.*;
@@ -49,6 +50,10 @@ public class InferenceVariable extends LightTypeParameter {
}
public boolean addBound(PsiType classType, InferenceBound inferenceBound) {
+ if (inferenceBound == InferenceBound.EQ &&
+ PsiUtil.resolveClassInClassTypeOnly(classType) == this) {
+ return false;
+ }
List<PsiType> list = myBounds.get(inferenceBound);
if (list == null) {
list = new ArrayList<PsiType>();
@@ -77,20 +82,18 @@ public class InferenceVariable extends LightTypeParameter {
}
}
+ if (!session.hasCapture(this) && dependencies.isEmpty()) {
+ return dependencies;
+ }
+
next:
for (InferenceVariable variable : session.getInferenceVariables()) {
if (!dependencies.contains(variable) && variable != this) {
- nextBound:
- for (List<PsiType> bounds : myBounds.values()) { //todo
+ for (List<PsiType> bounds : variable.myBounds.values()) { //todo
if (bounds != null) {
for (PsiType bound : bounds) {
- final Set<InferenceVariable> deps = new HashSet<InferenceVariable>();
- session.collectDependencies(bound, deps);
- if (deps.isEmpty()) {
- continue nextBound;
- }
-
- if (deps.contains(this)) {
+ final InferenceVariable inferenceVariable = session.getInferenceVariable(bound);
+ if (inferenceVariable == this) {
dependencies.add(variable);
continue next;
}
diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/LambdaExpressionCompatibilityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/LambdaExpressionCompatibilityConstraint.java
index c282481e79c0..f7e9badfa33c 100644
--- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/LambdaExpressionCompatibilityConstraint.java
+++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/LambdaExpressionCompatibilityConstraint.java
@@ -3,6 +3,7 @@ package com.intellij.psi.impl.source.resolve.graphInference.constraints;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.resolve.graphInference.FunctionalInterfaceParameterizationUtil;
import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession;
+import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import java.util.List;
@@ -62,8 +63,9 @@ public class LambdaExpressionCompatibilityConstraint implements ConstraintFormul
if (returnExpressions.isEmpty() && !myExpression.isValueCompatible()) { //not value-compatible
return false;
}
- returnType = session.substituteWithInferenceVariables(substitutor.substitute(returnType));
- if (!session.isProperType(returnType)) {
+ InferenceSession callsession = session.findNestedCallSession(myExpression);
+ returnType = callsession.substituteWithInferenceVariables(substitutor.substitute(returnType));
+ if (!callsession.isProperType(returnType)) {
for (PsiExpression returnExpression : returnExpressions) {
constraints.add(new ExpressionCompatibilityConstraint(returnExpression, returnType));
}
diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java
index fbfd8195fc11..b5e4188e1644 100644
--- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java
+++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java
@@ -169,11 +169,11 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm
}
LOG.assertTrue(referencedMethodReturnType != null, method);
- session.initBounds(method.getTypeParameters());
+ session.initBounds(myExpression, method.getTypeParameters());
if (!PsiTreeUtil.isContextAncestor(containingClass, myExpression, false) ||
PsiUtil.getEnclosingStaticElement(myExpression, containingClass) != null) {
- session.initBounds(containingClass.getTypeParameters());
+ session.initBounds(myExpression, containingClass.getTypeParameters());
}
//if i) the method reference elides NonWildTypeArguments,
@@ -243,7 +243,7 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm
final PsiClass qualifierClass = PsiUtil.resolveClassInType(qualifierType);
if (qualifierClass != null) {
- session.initBounds(qualifierClass.getTypeParameters());
+ session.initBounds(myExpression, qualifierClass.getTypeParameters());
constraints.add(new StrictSubtypingConstraint(session.substituteWithInferenceVariables(qualifierType),
session.substituteWithInferenceVariables(substitutor.substitute(targetParameters[0].getType()))));
}
diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/StrictSubtypingConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/StrictSubtypingConstraint.java
index 412b09eadec3..6b3c104aab35 100644
--- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/StrictSubtypingConstraint.java
+++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/StrictSubtypingConstraint.java
@@ -92,8 +92,22 @@ public class StrictSubtypingConstraint implements ConstraintFormula {
return false;
}
- if (!(myS instanceof PsiClassType)) return false;
- PsiClassType.ClassResolveResult SResult = ((PsiClassType)myS).resolveGenerics();
+ PsiClassType.ClassResolveResult SResult = null;
+ if (myS instanceof PsiIntersectionType) {
+ for (PsiType conjunct : ((PsiIntersectionType)myS).getConjuncts()) {
+ if (conjunct instanceof PsiClassType) {
+ final PsiClassType.ClassResolveResult conjunctResult = ((PsiClassType)conjunct).resolveGenerics();
+ if (InheritanceUtil.isInheritorOrSelf(conjunctResult.getElement(), CClass, true)) {
+ SResult = conjunctResult;
+ break;
+ }
+ }
+ }
+ } else if (myS instanceof PsiClassType) {
+ SResult = ((PsiClassType)myS).resolveGenerics();
+ }
+
+ if (SResult == null) return false;
PsiClass SClass = SResult.getElement();
if (((PsiClassType)myT).isRaw()) {
return SClass != null && InheritanceUtil.isInheritorOrSelf(SClass, CClass, true);
diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLambdaExpressionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLambdaExpressionImpl.java
index 069f667d92cf..9d35ace98cf4 100644
--- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLambdaExpressionImpl.java
+++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLambdaExpressionImpl.java
@@ -30,7 +30,6 @@ import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
-import com.intellij.util.containers.IntArrayList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -78,16 +77,11 @@ public class PsiLambdaExpressionImpl extends ExpressionPsiElement implements Psi
@Override
public boolean isVoidCompatible() {
final PsiElement body = getBody();
- if (body != null) {
- try {
- ControlFlow controlFlow = ControlFlowFactory.getInstance(getProject()).getControlFlow(body, LocalsOrMyInstanceFieldsControlFlowPolicy
- .getInstance());
- int startOffset = controlFlow.getStartOffset(body);
- int endOffset = controlFlow.getEndOffset(body);
- return startOffset != -1 && endOffset != -1 && !ControlFlowUtil.canCompleteNormally(controlFlow, startOffset, endOffset);
- }
- catch (AnalysisCanceledException e) {
- return true;
+ if (body instanceof PsiCodeBlock) {
+ for (PsiReturnStatement statement : PsiUtil.findReturnStatements((PsiCodeBlock)body)) {
+ if (statement.getReturnValue() != null) {
+ return false;
+ }
}
}
return true;
@@ -96,18 +90,25 @@ public class PsiLambdaExpressionImpl extends ExpressionPsiElement implements Psi
@Override
public boolean isValueCompatible() {
final PsiElement body = getBody();
- if (body != null) {
+ if (body instanceof PsiCodeBlock) {
try {
- final ControlFlow controlFlow =
- ControlFlowFactory.getInstance(getProject()).getControlFlow(body, LocalsOrMyInstanceFieldsControlFlowPolicy.getInstance(), false);
- if (ControlFlowUtil.findExitPointsAndStatements(controlFlow, 0, controlFlow.getSize(), new IntArrayList(),
- PsiReturnStatement.class,
- PsiThrowStatement.class).isEmpty()) {
+ ControlFlow controlFlow =
+ ControlFlowFactory.getInstance(getProject()).getControlFlow(body, LocalsOrMyInstanceFieldsControlFlowPolicy
+ .getInstance());
+ int startOffset = controlFlow.getStartOffset(body);
+ int endOffset = controlFlow.getEndOffset(body);
+ if (startOffset != -1 && endOffset != -1 && ControlFlowUtil.canCompleteNormally(controlFlow, startOffset, endOffset)) {
return false;
}
}
catch (AnalysisCanceledException e) {
- return true;
+ return false;
+ }
+
+ for (PsiReturnStatement statement : PsiUtil.findReturnStatements((PsiCodeBlock)body)) {
+ if (statement.getReturnValue() == null) {
+ return false;
+ }
}
}
return true;
@@ -200,17 +201,36 @@ public class PsiLambdaExpressionImpl extends ExpressionPsiElement implements Psi
}
}
+
+ //A lambda expression (§15.27) is potentially compatible with a functional interface type (§9.8) if all of the following are true:
+ // The arity of the target type's function type is the same as the arity of the lambda expression.
+ // If the target type's function type has a void return, then the lambda body is either a statement expression (§14.8) or a void-compatible block (§15.27.2).
+ // If the target type's function type has a (non-void) return type, then the lambda body is either an expression or a value-compatible block (§15.27.2).
+ PsiType methodReturnType = interfaceMethod.getReturnType();
if (checkReturnType) {
final String uniqueVarName = JavaCodeStyleManager.getInstance(getProject()).suggestUniqueVariableName("l", this, true);
final String canonicalText = toArray(leftType).getCanonicalText();
final PsiStatement assignmentFromText = JavaPsiFacade.getElementFactory(getProject())
.createStatementFromText(canonicalText + " " + uniqueVarName + " = " + getText(), this);
final PsiLocalVariable localVariable = (PsiLocalVariable)((PsiDeclarationStatement)assignmentFromText).getDeclaredElements()[0];
- PsiType methodReturnType = interfaceMethod.getReturnType();
if (methodReturnType != null) {
return LambdaHighlightingUtil.checkReturnTypeCompatible((PsiLambdaExpression)localVariable.getInitializer(),
substitutor.substitute(methodReturnType)) == null;
}
+ } else {
+ final PsiElement body = getBody();
+ if (methodReturnType == PsiType.VOID) {
+ if (body instanceof PsiCodeBlock) {
+ return isVoidCompatible();
+ } else {
+ return LambdaUtil.isExpressionStatementExpression(body);
+ }
+ } else {
+ if (body instanceof PsiCodeBlock) {
+ return isValueCompatible();
+ }
+ return body instanceof PsiExpression;
+ }
}
return true;
}
diff --git a/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java b/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java
index 3d9ea08125a8..6bb33be05ea5 100644
--- a/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java
+++ b/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java
@@ -158,7 +158,8 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
// A lambda expression or a method reference expression is potentially compatible with a type variable if the type variable is a type parameter of the candidate method.
final PsiClass paramClass = PsiUtil.resolveClassInType(paramType);
if (paramClass instanceof PsiTypeParameter && ((PsiTypeParameter)paramClass).getOwner() == method) continue;
- if (!lambdaExpression.isAcceptable(((MethodCandidateInfo)conflict).getSubstitutor(false).substitute(paramType), lambdaExpression.hasFormalParameterTypes())) {
+ if (!lambdaExpression.isAcceptable(((MethodCandidateInfo)conflict).getSubstitutor(false).substitute(paramType),
+ InferenceSession.isPertinentToApplicability(lambdaExpression, method))) {
iterator.remove();
}
}
@@ -397,7 +398,7 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
}
@MethodCandidateInfo.ApplicabilityLevelConstant
- protected int checkApplicability(@NotNull List<CandidateInfo> conflicts) {
+ public int checkApplicability(@NotNull List<CandidateInfo> conflicts) {
@MethodCandidateInfo.ApplicabilityLevelConstant int maxApplicabilityLevel = 0;
boolean toFilter = false;
for (CandidateInfo conflict : conflicts) {
diff --git a/java/java-tests/testData/codeInsight/completion/smartType/NoSemicolonInsideParentheses-out.java b/java/java-tests/testData/codeInsight/completion/smartType/NoSemicolonInsideParentheses-out.java
new file mode 100644
index 000000000000..3199c94ee908
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/completion/smartType/NoSemicolonInsideParentheses-out.java
@@ -0,0 +1,7 @@
+public class MyAspect {
+
+ public void foo() {
+ String nameToUse = /*adjustName*/(toString())<caret>; //todo
+ }
+
+}
diff --git a/java/java-tests/testData/codeInsight/completion/smartType/NoSemicolonInsideParentheses.java b/java/java-tests/testData/codeInsight/completion/smartType/NoSemicolonInsideParentheses.java
new file mode 100644
index 000000000000..30c2f7d757af
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/completion/smartType/NoSemicolonInsideParentheses.java
@@ -0,0 +1,7 @@
+public class MyAspect {
+
+ public void foo() {
+ String nameToUse = /*adjustName*/(to<caret>); //todo
+ }
+
+}
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/CaptureWildcardFromUnboundCaptureWildcard.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/CaptureWildcardFromUnboundCaptureWildcard.java
new file mode 100644
index 000000000000..0abec87dc335
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/CaptureWildcardFromUnboundCaptureWildcard.java
@@ -0,0 +1,9 @@
+class Test<X extends Getter<?, ?> & Runnable> {}
+
+interface Supplier<K> {
+ K get();
+}
+
+interface Getter<C, S extends C> extends Supplier<C> {
+ public S get();
+}
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA106985.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA106985.java
new file mode 100644
index 000000000000..b11bfa46632c
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA106985.java
@@ -0,0 +1,15 @@
+
+import java.util.Map;
+
+class Test {
+
+ public static void main(String[] args) {
+ Map<Integer, Object> map = <error descr="Inferred type 'java.lang.Object' for type parameter 'V' is not within its bound; should implement 'java.lang.Comparable'">make()</error>;
+ }
+
+
+ public static <K extends Comparable, V extends Comparable> Map<K,V> make() {
+ return null;
+ }
+
+} \ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA114797.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA114797.java
new file mode 100644
index 000000000000..9e4ee06ade1e
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA114797.java
@@ -0,0 +1,15 @@
+import java.util.ArrayList;
+import java.util.List;
+
+interface A{};
+interface B extends A{};
+
+class GenericTest {
+ public static <M extends V, V> List<V> convert(List<M> list){
+ return new ArrayList<V>();
+ }
+
+ public static void test(){
+ List<A> as = convert(new ArrayList<B>());
+ }
+} \ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/constraints/IntersectionTypeStrictSubtypingConstraint.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/constraints/IntersectionTypeStrictSubtypingConstraint.java
new file mode 100644
index 000000000000..df18646a0009
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/constraints/IntersectionTypeStrictSubtypingConstraint.java
@@ -0,0 +1,15 @@
+import java.io.Serializable;
+import java.util.function.Supplier;
+
+class Test {
+ static class Loader<K> {
+
+ static <K> Loader<K> from(Supplier<K> supplier) {
+ return new Loader<>();
+ }
+ }
+
+ Loader loader = Loader.from((I<String> & Serializable) () -> "");
+
+ interface I<H> extends Supplier<H>{}
+} \ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/FreshVariablesCreatedDuringResolveDependingOnAlreadyResolvedVariables.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/FreshVariablesCreatedDuringResolveDependingOnAlreadyResolvedVariables.java
new file mode 100644
index 000000000000..a3701f1b6cf8
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/FreshVariablesCreatedDuringResolveDependingOnAlreadyResolvedVariables.java
@@ -0,0 +1,17 @@
+class Test {
+
+ class X<F extends Foo, B extends Bar<F, B>> {
+ }
+ class Foo {
+ }
+ class Bar<A, B> {
+ }
+
+ private <F extends Foo, B extends Bar<F, B>> X<F, B> foo() {
+ return null;
+ }
+
+ {
+ X x = foo();
+ }
+}
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/IncompatibleBoundsFromAssignment.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/IncompatibleBoundsFromAssignment.java
new file mode 100644
index 000000000000..d5b8b03050d5
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/IncompatibleBoundsFromAssignment.java
@@ -0,0 +1,15 @@
+import java.util.Map;
+
+class Test {
+
+ public static void main(String[] args) {
+ <error descr="Incompatible types. Found: 'T', required: 'java.util.Map<java.lang.Object,java.lang.Object>'">Map<Object, Object> b = newMapTrie();</error>
+ <error descr="Incompatible types. Found: 'T', required: 'java.util.Map<java.lang.Object,java.util.Map<java.lang.Object,java.lang.Object>>'">Map<Object, Map<Object, Object>> c = newMapTrie();</error>
+ <error descr="Incompatible types. Found: 'T', required: 'java.util.Map<java.lang.Object,java.util.Map<java.lang.Object,java.util.Map<java.lang.Object,java.lang.Object>>>'">Map<Object, Map<Object, Map<Object, Object>>> d = newMapTrie();</error>
+ <error descr="Incompatible types. Found: 'T', required: 'java.util.Map<java.lang.Object,java.util.Map<java.lang.Object,java.util.Map<java.lang.Object,java.util.Map<java.lang.Object,java.lang.Object>>>>'">Map<Object, Map<Object, Map<Object, Map<Object, Object>>>> e = newMapTrie();</error>
+ }
+
+ public static <T extends Map<Byte, T>> T newMapTrie() {
+ return null;
+ }
+} \ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/Ambiguity1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/Ambiguity1.java
index e66630146e6f..02bbebd074b0 100644
--- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/Ambiguity1.java
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/Ambiguity1.java
@@ -12,7 +12,7 @@ class Ambiguity1 {
static <T> void m(I2<T> i2) {}
{
- m<error descr="Ambiguous method call: both 'Ambiguity1.m(I1)' and 'Ambiguity1.m(I2<Object>)' match">(()->{throw new AssertionError();})</error>;
+ m(()->{throw new AssertionError();});
m(() -> {});
m(() -> {
if (false) return;
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguityRawGenerics.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguityRawGenerics.java
index 595787704437..6c664dd9e65a 100644
--- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguityRawGenerics.java
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguityRawGenerics.java
@@ -22,6 +22,6 @@ class AmbiguityRawGenerics {
<Z> void foo(I3<Z> s) { }
void bar() {
- foo<error descr="Ambiguous method call: both 'AmbiguityRawGenerics.foo(I)' and 'AmbiguityRawGenerics.foo(I1)' match">(()-> { throw new RuntimeException(); })</error>;
+ foo<error descr="Ambiguous method call: both 'AmbiguityRawGenerics.foo(I1)' and 'AmbiguityRawGenerics.foo(I2)' match">(()-> { throw new RuntimeException(); })</error>;
}
} \ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/EffectiveFinal.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/EffectiveFinal.java
index 92b268394994..001b1f39c494 100644
--- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/EffectiveFinal.java
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/EffectiveFinal.java
@@ -142,3 +142,37 @@ class IDEA128196 {
new Thread(() -> System.out.println(value));
}
}
+
+class FinalAssignmentInInitializer {
+ private final String x;
+ {
+ Runnable r = () -> <error descr="Cannot assign a value to final variable 'x'">x</error> = "";
+ x = "";
+ }
+}
+
+class AssignmentToFinalInsideLambda {
+ boolean isTrue() {
+ return true;
+ }
+
+ Runnable r = () -> {
+ final int i;
+ if (isTrue()) {
+ i = 1;
+ } else {
+ i = 0;
+ }
+ };
+
+ void a() {
+ Runnable r = () -> {
+ final int i;
+ if (isTrue()) {
+ i = 1;
+ } else {
+ i = 0;
+ }
+ };
+ }
+} \ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/mostSpecific/NoReturnTypeResolutionForThrownException.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/mostSpecific/NoReturnTypeResolutionForThrownException.java
index 81429131d099..1fe14f680abe 100644
--- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/mostSpecific/NoReturnTypeResolutionForThrownException.java
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/mostSpecific/NoReturnTypeResolutionForThrownException.java
@@ -7,7 +7,7 @@ class Test {
void call(I2 p) { }
void test() {
- call<error descr="Ambiguous method call: both 'Test.call(I1)' and 'Test.call(I2)' match">(() -> { throw new RuntimeException(); })</error>;
+ call(() -> { throw new RuntimeException(); });
call(() -> { if (true) return ""; throw new RuntimeException(); });
call(() -> { if (true) return; throw new RuntimeException(); });
}
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/DeepNestedLambdaExpressionsNoFormalParams.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/DeepNestedLambdaExpressionsNoFormalParams.java
new file mode 100644
index 000000000000..5a79aef6a18f
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/DeepNestedLambdaExpressionsNoFormalParams.java
@@ -0,0 +1,70 @@
+
+import java.util.List;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+
+abstract class Simplified {
+ public List<Integer> gerFirstTriangles() {
+ return flatMap(() -> flatMap(() -> map(z -> 1))).collect(Collectors.toList());
+ }
+
+ abstract <R> R flatMap(Supplier<R> mapper);
+ abstract <R> Stream<R> map(Function<Integer, R> mapper);
+}
+
+class PythagoreanTriangles {
+
+ static class Triplet<T,U,R>{
+ private T t;
+ private U u;
+ private R r;
+
+ public Triplet(T t, U u, R r){
+ this.t = t;
+ this.u = u;
+ this.r = r;
+ }
+
+ @Override
+ public String toString() {
+ return t.toString() + "," + u.toString() + "," + r.toString();
+ }
+ }
+
+ public void pythagoreanTriangles(Integer num){
+ Stream<Integer> numbers = IntStream.rangeClosed(1,num).boxed();
+
+ Stream<Triplet<Integer, Integer, Integer>> triangles = numbers.flatMap(x -> {
+ return IntStream.rangeClosed(1, x).boxed().flatMap(y -> {
+ return IntStream.rangeClosed(1, y).boxed().filter(z -> {
+ return x * x == y * y + z * z;
+ }).map(z1 -> new Triplet<Integer, Integer, Integer>(x, y, z1));
+ });
+ });
+
+ triangles.forEach(System.out::println);
+
+ }
+
+ public List<Triplet<Integer, Integer, Integer>> gerFirstTriangles(long num){
+ Stream<Integer> infinity = Stream.iterate(1, (n) -> n + 1);
+ return infinity.flatMap(x -> {
+ return IntStream.rangeClosed(1, x).boxed().flatMap(y -> {
+ return IntStream.rangeClosed(1, y).boxed().filter(z -> {
+ return x * x == y * y + z * z;
+ }).map(z1 -> new Triplet<Integer, Integer, Integer>(x, y, z1));
+ });
+ }).limit(num).collect(Collectors.toList());
+ }
+
+
+ public static void main(String[] args) {
+ PythagoreanTriangles triangles = new PythagoreanTriangles();
+ triangles.pythagoreanTriangles(10);
+ triangles.gerFirstTriangles(5l).forEach(System.out::println);
+ }
+}
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IDEA126778.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IDEA126778.java
new file mode 100644
index 000000000000..d8bdcc0d6c82
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/IDEA126778.java
@@ -0,0 +1,27 @@
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static java.util.stream.Collectors.groupingBy;
+import static java.util.stream.Collectors.mapping;
+
+class Test {
+ private static Map<Long, Long> multiDataPointsToPerTxnSummedValue(final Stream<Map.Entry<DateTime, Map<Long, Long>>> stream) {
+ return stream.flatMap(e -> e.getValue().entrySet().stream().map(ex ->
+ new Object() {
+ Long txId = ex.getKey();
+ DataPoint dataPoint = new DataPoint(e.getKey(), ex.getValue());
+ }
+ )).collect(groupingBy(t -> t.txId, mapping(t -> t.dataPoint, Collectors.summingLong(dataPoint -> dataPoint.getValue().longValue()))));
+ }
+
+ static class MultiDataPoint {}
+ static class DateTime {}
+
+ static class DataPoint {
+ DataPoint(DateTime t, Long val) {}
+ public Long getValue() {
+ return null;
+ }
+ }
+} \ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/NestedLambdaExpressions1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/NestedLambdaExpressions1.java
new file mode 100644
index 000000000000..c31497d1f65a
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/NestedLambdaExpressions1.java
@@ -0,0 +1,27 @@
+class ExplicitLambdaNoParams {
+ interface I<T> {
+ T a();
+ }
+
+ <F> I<F> foo(I<F> iff) { return null;}
+
+ {
+ foo(() -> foo(() -> 1)).a();
+ I<Integer> a1 = foo(() -> foo(() -> 1)).a();
+ }
+}
+
+class LambdaWithFormalParameterTypes {
+
+ interface I<T> {
+ T a(int p);
+ }
+
+ <F> I<F> foo(I<F> iff) { return null;}
+
+ {
+ foo((int a) -> foo((int b) -> 1)).a(0);
+ I<Integer> a1 = foo((int a) -> foo((int b) -> 1)).a(0);
+ }
+
+}
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/NestedLambdaExpressionsNoFormalParams.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/NestedLambdaExpressionsNoFormalParams.java
new file mode 100644
index 000000000000..2d6254525d44
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/NestedLambdaExpressionsNoFormalParams.java
@@ -0,0 +1,55 @@
+import java.util.function.Function;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+abstract class NoFormalParams {
+ interface I<T> {
+ T a(int a);
+ }
+
+ <F> I<F> foo(I<F> i) { return null;}
+
+ {
+ I<Integer> i = foo(a -> foo(b -> 1)).a(0);
+ foo(a -> foo(b -> 1)).a(0);
+ }
+}
+
+abstract class NoFormalParamTypeInferenceNeeded {
+ interface I<T> {
+ T a(int a);
+ }
+
+ abstract <RR> RR map(I<RR> mapper);
+ abstract <R, V> R zip(Function<V, R> zipper);
+
+ {
+ map(a -> zip(text -> text));
+ zip(a -> zip(text -> text));
+ Integer zip = zip(<error descr="Cyclic inference">a -> zip(text -> text)</error>);
+ }
+
+}
+
+class IDEA124983 {
+ class Rectangle{
+ public Rectangle(int i, int j, int h, int w) {
+ }
+ }
+
+ void createGrid() {
+ IntStream.range(0, 4)
+ .mapToObj(i -> IntStream.range(0, 4).mapToObj(j -> {
+ Rectangle rect2 = new Rectangle(i * 64, j * 64, 64, 64);
+ return rect2;
+ }))
+ .flatMap(s -> s)
+ .forEach(this::add);
+ }
+
+ void add(final Rectangle r) {}
+
+ void simplified(final IntStream range) {
+ range.mapToObj(i -> range.mapToObj(j -> 1)).flatMap(s -> s);
+ }
+}
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/NestedLambdaExpressionsNoFormalParams1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/NestedLambdaExpressionsNoFormalParams1.java
new file mode 100644
index 000000000000..a3ce57be1db8
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/NestedLambdaExpressionsNoFormalParams1.java
@@ -0,0 +1,26 @@
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+class IDEA129251 {
+ void simplified(final Stream<String> pStream, final Stream<String> pStream1, final Stream<String> pStream2){
+ pStream.flatMap(x -> Stream.concat(pStream1, pStream2.map(String::toUpperCase)));
+ }
+
+
+ private final Set<String> m_allSubtablesColumns;
+ private final List<SubtableDescription> m_subtablesDescription = null;
+
+ {
+ m_allSubtablesColumns = m_subtablesDescription.stream().
+ flatMap(desc -> Stream.concat(desc.getKeyColumns().stream().map(String::toUpperCase),
+ desc.getValueColumns().stream().map(String::toUpperCase))).
+ collect(Collectors.toSet());
+ }
+
+ abstract class SubtableDescription {
+ abstract List<String> getKeyColumns();
+ abstract List<String> getValueColumns();
+ }
+} \ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/NestedLambdaExpressionsNoFormalParamsStopAtStandalone.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/NestedLambdaExpressionsNoFormalParamsStopAtStandalone.java
new file mode 100644
index 000000000000..be7be3539813
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/NestedLambdaExpressionsNoFormalParamsStopAtStandalone.java
@@ -0,0 +1,32 @@
+import java.util.Map;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.util.stream.Collector;
+import java.util.stream.Stream;
+
+class MultiDataPoint {
+ public MultiDataPoint(final Map<String, String> pCollect) {}
+
+ public static void convertValueResults(final Stream<Result> pStream) {
+ map(() -> new MultiDataPoint(collect(toMap(r -> r.event.substring(0)))));
+ }
+
+ static <R> R collect(Collector<? super Result, ?, R> collector) {return null;}
+
+ static <R> R map(Supplier<R> s) {
+ return null;
+ }
+
+ static <T, K> Collector<T, ?, Map<K,K>> toMap(Function< T, K> keyMapper) {
+ return null;
+ }
+
+ static class Result {
+ public String event;
+
+ public String getValue() {
+ return null;
+ }
+ }
+}
+
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/ParenthesizedExpressionsDuringConstrainsCollection.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/ParenthesizedExpressionsDuringConstrainsCollection.java
new file mode 100644
index 000000000000..2dd69c3dcc79
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newLambda/ParenthesizedExpressionsDuringConstrainsCollection.java
@@ -0,0 +1,13 @@
+import java.util.List;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+abstract class Test {
+ public List<Integer> gerFirstTriangles() {
+ return flatMap((y -> (map((z1 -> (1)))))).collect(Collectors.toList());
+ }
+
+ abstract <R> R flatMap(Function<Integer, R> mapper);
+ abstract <R> Stream<R> map (Function<Integer, R> mapper);
+} \ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/IDEA127275_.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/IDEA127275_.java
index c002468c1b91..5743d171ad28 100644
--- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/IDEA127275_.java
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/newMethodRef/IDEA127275_.java
@@ -4,7 +4,7 @@ import java.util.function.Function;
class Main {
{
- List<Optional<Function<String, String>>> list = asList(of(Main::identity));
+ List<Optional<Function<String, String>>> list = asList(of(<error descr="T is not a functional interface">Main::identity</error>));
}
static <T> List<T> asList(T a) { return null;}
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/overloadResolution/IDEA102800.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/overloadResolution/IDEA102800.java
new file mode 100644
index 000000000000..7c2cc7bdae5e
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/overloadResolution/IDEA102800.java
@@ -0,0 +1,31 @@
+import java.util.function.IntFunction;
+import java.util.function.IntUnaryOperator;
+import java.util.function.Supplier;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+class Test {
+
+ interface IntStream1 {
+ Stream<Integer> map(IntFunction<Integer> mapper);
+ IntStream1 map(IntUnaryOperator mapper);
+
+ Stream<Integer> boxed();
+ }
+
+ void fooBar(IntStream1 instr){
+ Supplier<Stream<Integer>> si = () -> instr.map ((i) -> (( <error descr="Operator '%' cannot be applied to '<lambda parameter>', 'int'">i % 2</error>) == 0) ? i : <error descr="Incompatible types. Found: '<lambda parameter>', required: '<lambda parameter>'">-i</error>).boxed();
+ System.out.println(si);
+ Supplier<Stream<Integer>> si1 = () -> instr.map <error descr="Ambiguous method call: both 'IntStream1.map(IntFunction<Integer>)' and 'IntStream1.map(IntUnaryOperator)' match">(null)</error>.boxed();
+ System.out.println(si1);
+ }
+}
+
+class TestInitial {
+ void fooBar(){
+ Supplier<Stream<Integer>> si = () -> IntStream.range(0, 20).map((i) -> ((i % 2) == 0) ? i : -i).boxed();
+ System.out.println(si);
+ }
+}
+
+
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/overloadResolution/PertinentToApplicabilityOfExplicitlyTypedLambda.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/overloadResolution/PertinentToApplicabilityOfExplicitlyTypedLambda.java
new file mode 100644
index 000000000000..348108fc3443
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/overloadResolution/PertinentToApplicabilityOfExplicitlyTypedLambda.java
@@ -0,0 +1,17 @@
+abstract class PertinentToApplicabilityOfExplicitlyTypedLambdaTest {
+
+ interface A {
+ B m(int a);
+ }
+
+ interface B {
+ int m(int b);
+ }
+
+ abstract void foo(A a);
+ abstract void foo(B b);
+
+ {
+ foo<error descr="Ambiguous method call: both 'PertinentToApplicabilityOfExplicitlyTypedLambdaTest.foo(A)' and 'PertinentToApplicabilityOfExplicitlyTypedLambdaTest.foo(B)' match">(x -> y -> 42)</error>;
+ }
+}
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/overloadResolution/VoidValueCompatibilityOfImplicitlyTypedLambda.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/overloadResolution/VoidValueCompatibilityOfImplicitlyTypedLambda.java
new file mode 100644
index 000000000000..1188a9584dca
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/overloadResolution/VoidValueCompatibilityOfImplicitlyTypedLambda.java
@@ -0,0 +1,23 @@
+interface A {
+ int m(int x);
+}
+
+interface B {
+ void m(boolean x);
+}
+
+abstract class Test {
+ abstract void foo(A j);
+ abstract void foo(B i);
+
+ void bar(Object o) {
+ foo(x -> {
+ return x += 1;
+ });
+ foo(x -> <error descr="Incompatible types. Found: 'int', required: '<lambda parameter>'">x += 1</error>);
+ foo(x -> 1);
+ foo(x -> <error descr="Operator '!' cannot be applied to 'int'">!x</error>);
+ foo(x -> <error descr="Operator '++' cannot be applied to '<lambda parameter>'">++x</error>);
+ foo(x -> o instanceof String ? 1 : 0);
+ }
+}
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/changeMethodSignatureFromUsage8/afterDisjunctionType.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/changeMethodSignatureFromUsage8/afterDisjunctionType.java
new file mode 100644
index 000000000000..7835cfb40ae9
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/changeMethodSignatureFromUsage8/afterDisjunctionType.java
@@ -0,0 +1,15 @@
+// "Add 'Exception' as 1st parameter to method 'f'" "true"
+import java.io.FileInputStream;
+import java.io.IOException;
+
+class Test {
+ public void createFileInputStream() {
+ try {
+ new FileInputStream("test");
+ } catch (IOException |NullPointerException e) {
+ f(e);
+ }
+ }
+
+ public void f(Exception e) { }
+}
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/changeMethodSignatureFromUsage8/beforeDisjunctionType.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/changeMethodSignatureFromUsage8/beforeDisjunctionType.java
new file mode 100644
index 000000000000..ab28d7484f4d
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/changeMethodSignatureFromUsage8/beforeDisjunctionType.java
@@ -0,0 +1,15 @@
+// "Add 'Exception' as 1st parameter to method 'f'" "true"
+import java.io.FileInputStream;
+import java.io.IOException;
+
+class Test {
+ public void createFileInputStream() {
+ try {
+ new FileInputStream("test");
+ } catch (IOException |NullPointerException e) {
+ f(<caret>e);
+ }
+ }
+
+ public void f() { }
+}
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambdaCodeBlock2Expr/afterVoidValueChangedNoConflict.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambdaCodeBlock2Expr/afterVoidValueChangedNoConflict.java
new file mode 100644
index 000000000000..295537651974
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambdaCodeBlock2Expr/afterVoidValueChangedNoConflict.java
@@ -0,0 +1,16 @@
+// "Replace with expression lambda" "true"
+class Test {
+ {
+ a(() -> new Object(){});
+ }
+
+ void a(Supplier<Object> s) {}
+ void a(AI<Object> s) {}
+
+ interface AI<K> {
+ void m();
+ }
+ interface Supplier<T> {
+ T get();
+ }
+} \ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambdaCodeBlock2Expr/beforeVoidValueChanged.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambdaCodeBlock2Expr/beforeVoidValueChanged.java
new file mode 100644
index 000000000000..20a6c0beac73
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambdaCodeBlock2Expr/beforeVoidValueChanged.java
@@ -0,0 +1,19 @@
+// "Replace with expression lambda" "false"
+interface A {
+ int m(int x);
+}
+
+interface B {
+ void m(boolean x);
+}
+
+abstract class X {
+ abstract void foo(A j);
+ abstract void foo(B i);
+
+ void bar(Object o) {
+ foo(x -> {
+ retu<caret>rn x += 1;
+ });
+ }
+} \ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambdaCodeBlock2Expr/beforeVoidValueChangedNoConflict.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambdaCodeBlock2Expr/beforeVoidValueChangedNoConflict.java
new file mode 100644
index 000000000000..fbbf7ff5f527
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/lambdaCodeBlock2Expr/beforeVoidValueChangedNoConflict.java
@@ -0,0 +1,18 @@
+// "Replace with expression lambda" "true"
+class Test {
+ {
+ a(() -> {
+ ret<caret>urn new Object(){};
+ });
+ }
+
+ void a(Supplier<Object> s) {}
+ void a(AI<Object> s) {}
+
+ interface AI<K> {
+ void m();
+ }
+ interface Supplier<T> {
+ T get();
+ }
+} \ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/generation/surroundWith/java/SurroundWithTryFinallyUsingIndents.java b/java/java-tests/testData/codeInsight/generation/surroundWith/java/SurroundWithTryFinallyUsingIndents.java
new file mode 100644
index 000000000000..c491a29b3380
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/generation/surroundWith/java/SurroundWithTryFinallyUsingIndents.java
@@ -0,0 +1,5 @@
+class Test {
+ void test() {
+ <selection> int a = 2;</selection>
+ }
+}
diff --git a/java/java-tests/testData/codeInsight/generation/surroundWith/java/SurroundWithTryFinallyUsingIndents_after.java b/java/java-tests/testData/codeInsight/generation/surroundWith/java/SurroundWithTryFinallyUsingIndents_after.java
new file mode 100644
index 000000000000..a3887076e98f
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/generation/surroundWith/java/SurroundWithTryFinallyUsingIndents_after.java
@@ -0,0 +1,9 @@
+class Test {
+ void test() {
+ try {
+ int a = 2;
+ } finally {
+ <caret>
+ }
+ }
+}
diff --git a/java/java-tests/testData/codeInsight/javadocIG/clickableFieldReference.html b/java/java-tests/testData/codeInsight/javadocIG/clickableFieldReference.html
new file mode 100644
index 000000000000..28602edf96e3
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/javadocIG/clickableFieldReference.html
@@ -0,0 +1,3 @@
+<html><head> <style type="text/css"> #error { background-color: #eeeeee; margin-bottom: 10px; } p { margin: 5px 0; } </style></head><body><PRE>@<a href="psi_element://Bar"><code>Bar</code></a>(<a href="psi_element://Baz#CONST"><code>Baz.CONST</code></a>&nbsp;value = {<a href="psi_element://Baz#CONST"><code>Baz.CONST</code></a>})&nbsp;
+class <b>Foo</b>
+extends <a href="psi_element://java.lang.Object"><code>Object</code></a></PRE></body></html> \ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/javadocIG/clickableFieldReference.java b/java/java-tests/testData/codeInsight/javadocIG/clickableFieldReference.java
new file mode 100644
index 000000000000..3f46d7e1d7ec
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/javadocIG/clickableFieldReference.java
@@ -0,0 +1,7 @@
+import java.lang.annotation.Documented;
+class Text { Foo foo; }
+@Bar(Baz.CONST, value = {Baz.CONST}) class Foo {}
+@Documented @interface Bar {}
+class Baz {
+ static int CONST;
+} \ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/javadocIG/enumConstantOrdinal.html b/java/java-tests/testData/codeInsight/javadocIG/enumConstantOrdinal.html
index 11d610085775..613de9167782 100644
--- a/java/java-tests/testData/codeInsight/javadocIG/enumConstantOrdinal.html
+++ b/java/java-tests/testData/codeInsight/javadocIG/enumConstantOrdinal.html
@@ -1,3 +1,2 @@
-E
- E A
-Enum constant ordinal: 0 \ No newline at end of file
+<html><head> <style type="text/css"> #error { background-color: #eeeeee; margin-bottom: 10px; } p { margin: 5px 0; } </style></head><body><small><b><a href="psi_element://E"><code>E</code></a></b></small><PRE><a href="psi_element://E"><code>E</code></a> <b>A
+Enum constant ordinal: 0</b></PRE></body></html> \ No newline at end of file
diff --git a/java/java-tests/testData/codeInsight/javadocIG/enumConstantOrdinal_quick.html b/java/java-tests/testData/codeInsight/javadocIG/enumConstantOrdinal_quick.html
new file mode 100644
index 000000000000..11d610085775
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/javadocIG/enumConstantOrdinal_quick.html
@@ -0,0 +1,3 @@
+E
+ E A
+Enum constant ordinal: 0 \ No newline at end of file
diff --git a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/awt/annotations.xml b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/awt/annotations.xml
index 2e75eb0e3c6c..68bc4c8bba79 100644
--- a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/awt/annotations.xml
+++ b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/awt/annotations.xml
@@ -132,15 +132,32 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;_,null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.awt.Component java.awt.Color getBackground()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.awt.Component java.awt.Color getForeground()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="java.awt.Component java.awt.Component findUnderMouseInWindow(java.awt.PointerInfo)">
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.awt.Component java.awt.Component getComponentAt(int, int)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="java.awt.Component java.awt.Component getComponentAt(java.awt.Point) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.awt.Component java.awt.Component getComponentAt(java.awt.Point)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.awt.Component java.awt.Component locate(int, int)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.awt.Component java.awt.Dimension getMaximumSize()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -161,6 +178,24 @@
<item name="java.awt.Component java.awt.Dimension size()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.awt.Component java.awt.Font getFont()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.awt.Component java.awt.Font getFont_NoClientCode()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.awt.Component java.awt.Graphics getGraphics()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.awt.Component java.awt.GraphicsConfiguration getGraphicsConfiguration()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.awt.Component java.awt.Image createImage(int, int)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.awt.Component java.awt.Image getBackBuffer()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.awt.Component java.awt.Point getLocation(java.awt.Point) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -169,6 +204,9 @@
<val val="&quot;!null-&gt;!null;null-&gt;!null&quot;"/>
</annotation>
</item>
+ <item name="java.awt.Component java.awt.Point getMousePosition()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.awt.Component java.awt.Point location()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -194,9 +232,24 @@
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
</item>
+ <item name="java.awt.Component java.awt.im.InputContext getInputContext()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.awt.Component java.awt.im.InputMethodRequests getInputMethodRequests()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.awt.Component java.awt.image.VolatileImage createVolatileImage(int, int)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.awt.Component java.awt.image.VolatileImage createVolatileImage(int, int, java.awt.ImageCapabilities) 2">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="java.awt.Component java.awt.image.VolatileImage createVolatileImage(int, int, java.awt.ImageCapabilities)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.awt.Component java.lang.String constructComponentName()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.awt.Component java.lang.String paramString()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -369,21 +422,57 @@
<val val="&quot;_,!null-&gt;!null;_,null-&gt;null&quot;"/>
</annotation>
</item>
+ <item name="java.awt.Container java.awt.Component findComponentAt(int, int)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.awt.Container java.awt.Component findComponentAt(int, int, boolean)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.awt.Container java.awt.Component findComponentAt(java.awt.Point) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.awt.Container java.awt.Component findComponentAt(java.awt.Point)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.awt.Container java.awt.Component findComponentAtImpl(int, int, boolean)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.awt.Container java.awt.Component getComponentAt(int, int)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.awt.Container java.awt.Component getComponentAt(java.awt.Point) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.awt.Container java.awt.Component getComponentAt(java.awt.Point)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.awt.Container java.awt.Component getMouseEventTargetImpl(int, int, boolean, java.awt.Container.EventTargetFilter, boolean, boolean)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.awt.Container java.awt.Component locate(int, int)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.awt.Container java.awt.Component[] getComponents()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
<item name="java.awt.Container java.awt.Component[] getComponents_NoClientCode()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.awt.Container java.awt.FocusTraversalPolicy getFocusTraversalPolicy()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.awt.Container java.awt.Point getMousePosition(boolean)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.awt.Container java.lang.String paramString()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.awt.Container javax.accessibility.Accessible getAccessibleAt(java.awt.Point)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.awt.Container javax.accessibility.Accessible getAccessibleChild(int)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.awt.Container void addContainerListener(java.awt.event.ContainerListener) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -504,6 +593,15 @@
<val val="&quot;null-&gt;false&quot;"/>
</annotation>
</item>
+ <item name="java.awt.Window java.awt.Component getFocusOwner()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.awt.Window java.awt.Component getMostRecentFocusOwner()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.awt.Window java.awt.Container getFocusCycleRootAncestor()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.awt.Window java.lang.Object access$000(java.awt.Window) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
diff --git a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/beans/beancontext/annotations.xml b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/beans/beancontext/annotations.xml
index ce4e092e389f..19cfde133b6b 100644
--- a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/beans/beancontext/annotations.xml
+++ b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/beans/beancontext/annotations.xml
@@ -12,6 +12,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="java.beans.beancontext.BeanContextServicesSupport java.beans.beancontext.BeanContextServicesSupport.BCSSServiceProvider createBCSSServiceProvider(java.lang.Class, java.beans.beancontext.BeanContextServiceProvider)">
<annotation name="org.jetbrains.annotations.NotNull"/>
@@ -31,9 +32,15 @@
<item name="java.beans.beancontext.BeanContextServicesSupport java.lang.Object getService(java.beans.beancontext.BeanContextChild, java.lang.Object, java.lang.Class, java.lang.Object, java.beans.beancontext.BeanContextServiceRevokedListener) 4">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.beans.beancontext.BeanContextServicesSupport java.lang.Object getService(java.beans.beancontext.BeanContextChild, java.lang.Object, java.lang.Class, java.lang.Object, java.beans.beancontext.BeanContextServiceRevokedListener)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.beans.beancontext.BeanContextServicesSupport java.util.Iterator getCurrentServiceClasses()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.beans.beancontext.BeanContextServicesSupport java.util.Iterator getCurrentServiceSelectors(java.lang.Class)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.beans.beancontext.BeanContextServicesSupport void addBeanContextServicesListener(java.beans.beancontext.BeanContextServicesListener) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
diff --git a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/io/annotations.xml b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/io/annotations.xml
index 521adcf48636..4bc566ac9261 100644
--- a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/io/annotations.xml
+++ b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/io/annotations.xml
@@ -11,6 +11,12 @@
<item name="java.io.BufferedReader int read(char[], int, int) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.io.BufferedReader java.lang.String readLine()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.io.BufferedReader java.lang.String readLine(boolean)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.io.BufferedWriter BufferedWriter(java.io.Writer) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -50,6 +56,9 @@
<item name="java.io.DataInputStream int read(byte[]) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.io.DataInputStream java.lang.String readLine()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.io.DataInputStream java.lang.String readUTF()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -133,15 +142,30 @@
<item name="java.io.File java.io.File getCanonicalFile()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.io.File java.io.File getParentFile()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.io.File java.io.File[] listFiles()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.io.File java.io.File[] listFiles(java.io.FileFilter) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="java.io.File java.io.File[] listFiles(java.io.FileFilter)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.io.File java.io.File[] listFiles(java.io.FilenameFilter) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="java.io.File java.io.File[] listFiles(java.io.FilenameFilter)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.io.File java.lang.String getName()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.io.File java.lang.String getParent()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.io.File java.lang.String slashify(java.lang.String, boolean) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -270,9 +294,33 @@
<item name="java.io.ObjectInputStream java.lang.Class resolveProxyClass(java.lang.String[]) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.io.ObjectInputStream java.lang.Enum readEnum(boolean)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.io.ObjectInputStream java.lang.Object access$300(java.io.ObjectInputStream, boolean) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.io.ObjectInputStream java.lang.Object access$300(java.io.ObjectInputStream, boolean)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.io.ObjectInputStream java.lang.Object readArray(boolean)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.io.ObjectInputStream java.lang.Object readNull()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.io.ObjectInputStream java.lang.Object readObject()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.io.ObjectInputStream java.lang.Object readObject0(boolean)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.io.ObjectInputStream java.lang.Object readObjectOverride()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.io.ObjectInputStream java.lang.Object readUnshared()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.io.ObjectInputStream java.lang.Object resolveObject(java.lang.Object)">
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null-&gt;!null;null-&gt;null&quot;"/>
@@ -466,6 +514,9 @@
<item name="java.io.RandomAccessFile int read(byte[]) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.io.RandomAccessFile java.lang.String readLine()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.io.RandomAccessFile java.lang.String readUTF()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
diff --git a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/lang/annotations.xml b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/lang/annotations.xml
index 4862b313a917..00ee3b5c3075 100644
--- a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/lang/annotations.xml
+++ b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/lang/annotations.xml
@@ -250,6 +250,15 @@
<val val="&quot;!null-&gt;!null;null-&gt;null&quot;"/>
</annotation>
</item>
+ <item name="java.lang.Class T newInstance()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.lang.Class T newInstance0()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.lang.Class T[] getEnumConstants()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.Class boolean access$100(java.lang.Object[], java.lang.Object[]) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -275,6 +284,9 @@
<item name="java.lang.Class boolean isAnnotationPresent(java.lang.Class&lt;? extends java.lang.annotation.Annotation&gt;) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.Class java.io.InputStream getResourceAsStream(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.Class java.lang.Class toClass(java.lang.reflect.Type)">
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
@@ -286,12 +298,24 @@
<item name="java.lang.Class java.lang.Class&lt;? extends U&gt; asSubclass(java.lang.Class&lt;U&gt;)">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.Class java.lang.Class.EnclosingMethodInfo getEnclosingMethodInfo()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.lang.Class java.lang.ClassLoader getClassLoader()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.Class java.lang.String argumentTypesToString(java.lang.Class[]) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="java.lang.Class java.lang.String argumentTypesToString(java.lang.Class[])">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.Class java.lang.String getCanonicalName()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.lang.Class java.lang.String getSimpleBinaryName()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.Class java.lang.String getSimpleName()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -303,6 +327,9 @@
<item name="java.lang.Class java.lang.String toString()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.Class java.lang.reflect.Constructor&lt;?&gt; getEnclosingConstructor()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.Class java.lang.reflect.Constructor&lt;T&gt; getConstructor(java.lang.Class...) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -324,12 +351,18 @@
<item name="java.lang.Class java.lang.reflect.Field getField0(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.Class java.lang.reflect.Field getField0(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.Class java.lang.reflect.Field searchFields(java.lang.reflect.Field[], java.lang.String) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
<item name="java.lang.Class java.lang.reflect.Field searchFields(java.lang.reflect.Field[], java.lang.String) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.Class java.lang.reflect.Field searchFields(java.lang.reflect.Field[], java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.Class java.lang.reflect.Field[] copyFields(java.lang.reflect.Field[]) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -342,12 +375,18 @@
<item name="java.lang.Class java.lang.reflect.Method getDeclaredMethod(java.lang.String, java.lang.Class...) 1">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="java.lang.Class java.lang.reflect.Method getEnclosingMethod()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.Class java.lang.reflect.Method getMethod(java.lang.String, java.lang.Class...) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
<item name="java.lang.Class java.lang.reflect.Method getMethod0(java.lang.String, java.lang.Class[]) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.Class java.lang.reflect.Method getMethod0(java.lang.String, java.lang.Class[])">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.Class java.lang.reflect.Method searchMethods(java.lang.reflect.Method[], java.lang.String, java.lang.Class[]) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -360,6 +399,12 @@
<item name="java.lang.Class java.lang.reflect.Method[] copyMethods(java.lang.reflect.Method[]) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.Class java.lang.reflect.Type getGenericSuperclass()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.lang.Class java.net.URL getResource(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.Class void addAll(java.util.Collection, java.lang.reflect.Field[]) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -380,6 +425,21 @@
<val val="&quot;_,null-&gt;false&quot;"/>
</annotation>
</item>
+ <item name="java.lang.ClassLoader java.io.InputStream getResourceAsStream(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.lang.ClassLoader java.io.InputStream getSystemResourceAsStream(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.lang.ClassLoader java.lang.ClassLoader getCallerClassLoader()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.lang.ClassLoader java.lang.ClassLoader getParent()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.lang.ClassLoader java.lang.ClassLoader getSystemClassLoader()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.ClassLoader java.lang.Package definePackage(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.net.URL)">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -390,6 +450,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null-&gt;null;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="java.lang.ClassLoader java.lang.String[] initializePath(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
@@ -401,6 +462,16 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null-&gt;null;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.lang.ClassLoader java.net.URL getBootstrapResource(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.lang.ClassLoader java.net.URL getResource(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.lang.ClassLoader java.net.URL getSystemResource(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="java.lang.ClassLoader java.util.Enumeration findResources(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -1465,6 +1536,12 @@
<item name="java.lang.StringBuilder void writeObject(java.io.ObjectOutputStream) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.System java.io.InputStream nullInputStream()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.lang.System java.io.PrintStream nullPrintStream()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.System java.lang.String clearProperty(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -1486,6 +1563,9 @@
<item name="java.lang.System void setSecurityManager0(java.lang.SecurityManager) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="java.lang.System.1 java.lang.Object run()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.System.2 sun.reflect.ConstantPool getConstantPool(java.lang.Class) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -1525,6 +1605,9 @@
<item name="java.lang.Thread Thread(java.lang.ThreadGroup, java.lang.String) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.Thread java.lang.ClassLoader getContextClassLoader()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.Thread java.lang.String getName()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -1543,6 +1626,15 @@
<item name="java.lang.ThreadLocal T childValue(T) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="java.lang.ThreadLocal T get()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.lang.ThreadLocal T initialValue()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.lang.ThreadLocal T setInitialValue()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.ThreadLocal int access$400(java.lang.ThreadLocal) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -1576,9 +1668,15 @@
<item name="java.lang.ThreadLocal.ThreadLocalMap java.lang.ThreadLocal.ThreadLocalMap.Entry access$000(java.lang.ThreadLocal.ThreadLocalMap, java.lang.ThreadLocal) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.ThreadLocal.ThreadLocalMap java.lang.ThreadLocal.ThreadLocalMap.Entry access$000(java.lang.ThreadLocal.ThreadLocalMap, java.lang.ThreadLocal)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.ThreadLocal.ThreadLocalMap java.lang.ThreadLocal.ThreadLocalMap.Entry getEntry(java.lang.ThreadLocal) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.ThreadLocal.ThreadLocalMap java.lang.ThreadLocal.ThreadLocalMap.Entry getEntry(java.lang.ThreadLocal)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.ThreadLocal.ThreadLocalMap java.lang.ThreadLocal.ThreadLocalMap.Entry getEntryAfterMiss(java.lang.ThreadLocal, int, java.lang.ThreadLocal.ThreadLocalMap.Entry) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -1589,6 +1687,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;_,_,null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="java.lang.ThreadLocal.ThreadLocalMap void access$100(java.lang.ThreadLocal.ThreadLocalMap, java.lang.ThreadLocal, java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
@@ -1608,6 +1707,9 @@
<item name="java.lang.ThreadLocal.ThreadLocalMap void set(java.lang.ThreadLocal, java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.Throwable java.lang.Throwable getCause()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.Throwable java.lang.Throwable initCause(java.lang.Throwable)">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
diff --git a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/lang/invoke/annotations.xml b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/lang/invoke/annotations.xml
index 42a07af318e1..aa3ff596e37d 100644
--- a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/lang/invoke/annotations.xml
+++ b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/lang/invoke/annotations.xml
@@ -118,19 +118,32 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null,_,_,_-&gt;null;_,!null,_,_-&gt;null;_,_,_,!null-&gt;null;_,_,_,null-&gt;null;_,null,_,_-&gt;null;null,_,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="java.lang.invoke.AdapterMethodHandle java.lang.invoke.MethodHandle makeCheckCast(java.lang.invoke.MethodType, java.lang.invoke.MethodHandle, int, java.lang.Class&lt;?&gt;) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.invoke.AdapterMethodHandle java.lang.invoke.MethodHandle makeCheckCast(java.lang.invoke.MethodType, java.lang.invoke.MethodHandle, int, java.lang.Class&lt;?&gt;)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.AdapterMethodHandle java.lang.invoke.MethodHandle makeDropArguments(java.lang.invoke.MethodType, java.lang.invoke.MethodHandle, int, int) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.invoke.AdapterMethodHandle java.lang.invoke.MethodHandle makeDropArguments(java.lang.invoke.MethodType, java.lang.invoke.MethodHandle, int, int)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.AdapterMethodHandle java.lang.invoke.MethodHandle makeDupArguments(java.lang.invoke.MethodType, java.lang.invoke.MethodHandle, int, int) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.invoke.AdapterMethodHandle java.lang.invoke.MethodHandle makeDupArguments(java.lang.invoke.MethodType, java.lang.invoke.MethodHandle, int, int)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.AdapterMethodHandle java.lang.invoke.MethodHandle makePairwiseConvert(java.lang.invoke.MethodType, java.lang.invoke.MethodHandle) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.invoke.AdapterMethodHandle java.lang.invoke.MethodHandle makePairwiseConvert(java.lang.invoke.MethodType, java.lang.invoke.MethodHandle)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.AdapterMethodHandle java.lang.invoke.MethodHandle makePermutation(java.lang.invoke.MethodType, java.lang.invoke.MethodHandle, int[]) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -144,16 +157,26 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="java.lang.invoke.AdapterMethodHandle java.lang.invoke.MethodHandle makeRetype(java.lang.invoke.MethodType, java.lang.invoke.MethodHandle, boolean) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.invoke.AdapterMethodHandle java.lang.invoke.MethodHandle makeRetype(java.lang.invoke.MethodType, java.lang.invoke.MethodHandle, boolean)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.AdapterMethodHandle java.lang.invoke.MethodHandle makeRetypeOnly(java.lang.invoke.MethodType, java.lang.invoke.MethodHandle) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.invoke.AdapterMethodHandle java.lang.invoke.MethodHandle makeRetypeOnly(java.lang.invoke.MethodType, java.lang.invoke.MethodHandle)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.AdapterMethodHandle java.lang.invoke.MethodHandle makeRetypeRaw(java.lang.invoke.MethodType, java.lang.invoke.MethodHandle) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.invoke.AdapterMethodHandle java.lang.invoke.MethodHandle makeRetypeRaw(java.lang.invoke.MethodType, java.lang.invoke.MethodHandle)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.AdapterMethodHandle java.lang.invoke.MethodHandle makeRotateArguments(java.lang.invoke.MethodType, java.lang.invoke.MethodHandle, int, int, int) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -161,14 +184,19 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_,_,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="java.lang.invoke.AdapterMethodHandle java.lang.invoke.MethodHandle makeSpreadArguments(java.lang.invoke.MethodType, java.lang.invoke.MethodHandle, java.lang.Class&lt;?&gt;, int, int) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.invoke.AdapterMethodHandle java.lang.invoke.MethodHandle makeSpreadArguments(java.lang.invoke.MethodType, java.lang.invoke.MethodHandle, java.lang.Class&lt;?&gt;, int, int)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.AdapterMethodHandle java.lang.invoke.MethodHandle makeSwapArguments(java.lang.invoke.MethodType, java.lang.invoke.MethodHandle, int, int)">
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;_,null,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="java.lang.invoke.AdapterMethodHandle java.lang.invoke.MethodHandle makeUnboxArgument(java.lang.invoke.MethodType, java.lang.invoke.MethodHandle, int, java.lang.Class&lt;?&gt;) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
@@ -176,6 +204,9 @@
<item name="java.lang.invoke.AdapterMethodHandle java.lang.invoke.MethodHandle makeUnboxArgument(java.lang.invoke.MethodType, java.lang.invoke.MethodHandle, int, java.lang.Class&lt;?&gt;) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.invoke.AdapterMethodHandle java.lang.invoke.MethodHandle makeUnboxArgument(java.lang.invoke.MethodType, java.lang.invoke.MethodHandle, int, java.lang.Class&lt;?&gt;)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.AdapterMethodHandle java.lang.invoke.MethodHandle makeVarargsCollector(java.lang.invoke.MethodHandle, java.lang.Class&lt;?&gt;) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -236,6 +267,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null,_,_-&gt;!null;null,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="java.lang.invoke.BoundMethodHandle java.lang.RuntimeException badBoundArgumentException(java.lang.Object, java.lang.invoke.MethodHandle, int) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -271,6 +303,9 @@
<item name="java.lang.invoke.CallSite java.lang.invoke.CallSite makeSite(java.lang.invoke.MethodHandle, java.lang.String, java.lang.invoke.MethodType, java.lang.Object, java.lang.invoke.MemberName, int) 4">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.invoke.CallSite java.lang.invoke.MethodHandle makeDynamicInvoker()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.CallSite java.lang.invoke.WrongMethodTypeException wrongTargetType(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -328,6 +363,9 @@
<item name="java.lang.invoke.FilterGeneric java.lang.invoke.FilterGeneric.Adapter findAdapter(java.lang.invoke.MethodType, java.lang.invoke.FilterGeneric.Kind, int) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.invoke.FilterGeneric java.lang.invoke.FilterGeneric.Adapter findAdapter(java.lang.invoke.MethodType, java.lang.invoke.FilterGeneric.Kind, int)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.FilterGeneric java.lang.invoke.FilterGeneric.Adapter getAdapter(java.lang.invoke.FilterGeneric.Kind, int) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -389,6 +427,9 @@
<item name="java.lang.invoke.FilterGeneric.Adapter java.lang.Class&lt;? extends java.lang.invoke.FilterGeneric.Adapter&gt; findSubClass(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="java.lang.invoke.FilterGeneric.Adapter java.lang.Class&lt;? extends java.lang.invoke.FilterGeneric.Adapter&gt; findSubClass(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.FilterGeneric.F0 F0(java.lang.invoke.MethodHandle) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -667,6 +708,9 @@
<item name="java.lang.invoke.FromGeneric java.lang.invoke.FromGeneric.Adapter findAdapter(java.lang.invoke.MethodType) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.invoke.FromGeneric java.lang.invoke.FromGeneric.Adapter findAdapter(java.lang.invoke.MethodType)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.FromGeneric java.lang.invoke.FromGeneric.Adapter makeInstance(java.lang.invoke.MethodHandle) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -826,6 +870,9 @@
<item name="java.lang.invoke.FromGeneric.Adapter java.lang.Class&lt;? extends java.lang.invoke.FromGeneric.Adapter&gt; findSubClass(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="java.lang.invoke.FromGeneric.Adapter java.lang.Class&lt;? extends java.lang.invoke.FromGeneric.Adapter&gt; findSubClass(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.InvokeGeneric boolean returnConversionNeeded(java.lang.invoke.MethodType, java.lang.invoke.MethodHandle) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -863,6 +910,9 @@
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
</item>
+ <item name="java.lang.invoke.InvokeGeneric java.lang.invoke.MethodHandle makeInitialInvoker()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.Invokers Invokers(java.lang.invoke.MethodType) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -893,6 +943,12 @@
<item name="java.lang.invoke.MemberName int access$200(java.lang.invoke.MemberName) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.invoke.MemberName java.lang.Class&lt;?&gt; getFieldType()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.lang.invoke.MemberName java.lang.ClassLoader getClassLoader()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.MemberName java.lang.IllegalAccessException makeAccessException(java.lang.String, java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -913,6 +969,9 @@
<val val="&quot;_,!null-&gt;!null;_,null-&gt;null&quot;"/>
</annotation>
</item>
+ <item name="java.lang.invoke.MemberName java.lang.Object getType()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.MemberName java.lang.ReflectiveOperationException makeAccessException(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -930,6 +989,9 @@
<val val="&quot;_,!null-&gt;!null;_,null-&gt;null&quot;"/>
</annotation>
</item>
+ <item name="java.lang.invoke.MemberName java.lang.String getName()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.MemberName java.lang.String getName(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -938,12 +1000,21 @@
<val val="&quot;null-&gt;!null&quot;"/>
</annotation>
</item>
+ <item name="java.lang.invoke.MemberName java.lang.String getSignature()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.lang.invoke.MemberName java.lang.invoke.MethodType getMethodType()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.MemberName.Factory boolean resolveInPlace(java.lang.invoke.MemberName, boolean, java.lang.Class&lt;?&gt;) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
<item name="java.lang.invoke.MemberName.Factory java.lang.invoke.MemberName resolveOrNull(java.lang.invoke.MemberName, boolean, java.lang.Class&lt;?&gt;) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.invoke.MemberName.Factory java.lang.invoke.MemberName resolveOrNull(java.lang.invoke.MemberName, boolean, java.lang.Class&lt;?&gt;)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.MemberName.Factory java.util.List&lt;java.lang.invoke.MemberName&gt; getMembers(java.lang.Class&lt;?&gt;, java.lang.String, java.lang.Object, int, java.lang.Class&lt;?&gt;) 2">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -1005,10 +1076,14 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="java.lang.invoke.MethodHandleImpl java.lang.invoke.MethodHandle collectArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType, int, java.lang.invoke.MethodHandle) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.invoke.MethodHandleImpl java.lang.invoke.MethodHandle collectArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType, int, java.lang.invoke.MethodHandle)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.MethodHandleImpl java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType, int) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -1030,6 +1105,9 @@
<item name="java.lang.invoke.MethodHandleImpl java.lang.invoke.MethodHandle foldArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType, java.lang.invoke.MethodHandle) 2">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.invoke.MethodHandleImpl java.lang.invoke.MethodHandle foldArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType, java.lang.invoke.MethodHandle)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.MethodHandleImpl java.lang.invoke.MethodHandle makeAllocator(java.lang.invoke.MethodHandle) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -1039,15 +1117,24 @@
<item name="java.lang.invoke.MethodHandleImpl java.lang.invoke.MethodHandle makeGuardWithCatch(java.lang.invoke.MethodHandle, java.lang.Class&lt;? extends java.lang.Throwable&gt;, java.lang.invoke.MethodHandle) 2">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.invoke.MethodHandleImpl java.lang.invoke.MethodHandle makeGuardWithCatch(java.lang.invoke.MethodHandle, java.lang.Class&lt;? extends java.lang.Throwable&gt;, java.lang.invoke.MethodHandle)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.MethodHandleImpl java.lang.invoke.MethodHandle makeGuardWithTest(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
<item name="java.lang.invoke.MethodHandleImpl java.lang.invoke.MethodHandle makeGuardWithTest(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.invoke.MethodHandleImpl java.lang.invoke.MethodHandle makeGuardWithTest(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.MethodHandleImpl java.lang.invoke.MethodHandle spreadArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType, int) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.invoke.MethodHandleImpl java.lang.invoke.MethodHandle throwException(java.lang.invoke.MethodType)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.MethodHandleImpl sun.invoke.empty.Empty throwException(T) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -1057,6 +1144,9 @@
<item name="java.lang.invoke.MethodHandleImpl.AllocateObject java.lang.invoke.MethodHandle make(java.lang.Class&lt;?&gt;, java.lang.invoke.MethodHandle) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.invoke.MethodHandleImpl.AllocateObject java.lang.invoke.MethodHandle make(java.lang.Class&lt;?&gt;, java.lang.invoke.MethodHandle)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.MethodHandleImpl.AllocateObject java.lang.invoke.MethodType makeConType(java.lang.invoke.MethodHandle) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -1093,6 +1183,9 @@
<item name="java.lang.invoke.MethodHandleImpl.FieldAccessor java.lang.Object staticBase(java.lang.invoke.MemberName) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.invoke.MethodHandleImpl.FieldAccessor java.lang.Object staticBase(java.lang.invoke.MemberName)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.MethodHandleImpl.FieldAccessor java.lang.String aname(java.lang.Class&lt;?&gt;, boolean) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -1165,6 +1258,9 @@
<item name="java.lang.invoke.MethodHandleImpl.GuardWithTest java.lang.invoke.MethodHandle make(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.invoke.MethodHandleImpl.GuardWithTest java.lang.invoke.MethodHandle make(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.MethodHandleNatives java.lang.Object[] makeTarget(java.lang.Class&lt;?&gt;, java.lang.String, java.lang.String, int, java.lang.Class&lt;?&gt;)">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -1271,9 +1367,15 @@
<item name="java.lang.invoke.MethodHandles java.lang.Object access$200(java.lang.Object, java.lang.reflect.Method, java.lang.Object[]) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.invoke.MethodHandles java.lang.Object access$200(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.MethodHandles java.lang.Object callObjectMethod(java.lang.Object, java.lang.reflect.Method, java.lang.Object[]) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.invoke.MethodHandles java.lang.Object callObjectMethod(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.MethodHandles java.lang.RuntimeException misMatchedTypes(java.lang.String, java.lang.invoke.MethodType, java.lang.invoke.MethodType) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -1304,6 +1406,9 @@
<item name="java.lang.invoke.MethodHandles java.lang.invoke.MethodHandle catchException(java.lang.invoke.MethodHandle, java.lang.Class&lt;? extends java.lang.Throwable&gt;, java.lang.invoke.MethodHandle) 2">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.invoke.MethodHandles java.lang.invoke.MethodHandle catchException(java.lang.invoke.MethodHandle, java.lang.Class&lt;? extends java.lang.Throwable&gt;, java.lang.invoke.MethodHandle)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.MethodHandles java.lang.invoke.MethodHandle collectArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -1350,12 +1455,18 @@
<item name="java.lang.invoke.MethodHandles java.lang.invoke.MethodHandle filterReturnValue(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.invoke.MethodHandles java.lang.invoke.MethodHandle filterReturnValue(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.MethodHandles java.lang.invoke.MethodHandle foldArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
<item name="java.lang.invoke.MethodHandles java.lang.invoke.MethodHandle foldArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.invoke.MethodHandles java.lang.invoke.MethodHandle foldArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.MethodHandles java.lang.invoke.MethodHandle genericInvoker(java.lang.invoke.MethodType) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -1368,6 +1479,12 @@
<item name="java.lang.invoke.MethodHandles java.lang.invoke.MethodHandle guardWithTest(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle) 2">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.invoke.MethodHandles java.lang.invoke.MethodHandle guardWithTest(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.lang.invoke.MethodHandles java.lang.invoke.MethodHandle identity(java.lang.Class&lt;?&gt;)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.MethodHandles java.lang.invoke.MethodHandle insertArguments(java.lang.invoke.MethodHandle, int, java.lang.Object...) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -1395,6 +1512,9 @@
<item name="java.lang.invoke.MethodHandles java.lang.invoke.MethodHandle throwException(java.lang.Class&lt;?&gt;, java.lang.Class&lt;? extends java.lang.Throwable&gt;) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.invoke.MethodHandles java.lang.invoke.MethodHandle throwException(java.lang.Class&lt;?&gt;, java.lang.Class&lt;? extends java.lang.Throwable&gt;)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.MethodHandles java.lang.invoke.MethodHandle wrapperInstanceTarget(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -1404,9 +1524,15 @@
<item name="java.lang.invoke.MethodHandles java.lang.reflect.Constructor getSingleConstructor(java.lang.Class&lt;?&gt;) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.invoke.MethodHandles java.lang.reflect.Constructor getSingleConstructor(java.lang.Class&lt;?&gt;)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.MethodHandles java.lang.reflect.Method getSingleMethod(java.lang.Class&lt;?&gt;) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.invoke.MethodHandles java.lang.reflect.Method getSingleMethod(java.lang.Class&lt;?&gt;)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.MethodHandles sun.invoke.WrapperInstance asWrapperInstance(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -1433,6 +1559,12 @@
<item name="java.lang.invoke.MethodHandles.1 java.lang.Object invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[]) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.invoke.MethodHandles.1 java.lang.Object invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.lang.invoke.MethodHandles.Lookup java.lang.Class&lt;?&gt; lookupClassOrNull()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.MethodHandles.Lookup java.lang.String accessFailedMessage(java.lang.Class&lt;?&gt;, java.lang.invoke.MemberName) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -1674,10 +1806,14 @@
<item name="java.lang.invoke.MethodTypeForm int[] primsAtEndOrder(java.lang.invoke.MethodType) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.invoke.MethodTypeForm int[] primsAtEndOrder(java.lang.invoke.MethodType)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.MethodTypeForm java.lang.Class&lt;?&gt; canonicalize(java.lang.Class&lt;?&gt;, int)">
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="java.lang.invoke.MethodTypeForm java.lang.Class&lt;?&gt;[] canonicalizes(java.lang.Class&lt;?&gt;[], int) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
@@ -1688,6 +1824,9 @@
<item name="java.lang.invoke.MethodTypeForm java.lang.invoke.MethodType canonicalize(java.lang.invoke.MethodType, int, int) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.invoke.MethodTypeForm java.lang.invoke.MethodType canonicalize(java.lang.invoke.MethodType, int, int)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.MethodTypeForm java.lang.invoke.MethodType reorderParameters(java.lang.invoke.MethodType, int[], java.lang.Class&lt;?&gt;[]) 1">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -1747,6 +1886,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;_,null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="java.lang.invoke.SpreadGeneric.Adapter Adapter(java.lang.invoke.SpreadGeneric, java.lang.invoke.MethodHandle) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
@@ -1754,6 +1894,9 @@
<item name="java.lang.invoke.SpreadGeneric.Adapter java.lang.Class&lt;? extends java.lang.invoke.SpreadGeneric.Adapter&gt; findSubClass(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="java.lang.invoke.SpreadGeneric.Adapter java.lang.Class&lt;? extends java.lang.invoke.SpreadGeneric.Adapter&gt; findSubClass(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.SpreadGeneric.S0 S0(java.lang.invoke.SpreadGeneric, java.lang.invoke.MethodHandle) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -1857,6 +2000,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;_,null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="java.lang.invoke.SwitchPoint void invalidateAll(java.lang.invoke.SwitchPoint[]) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
@@ -1873,6 +2017,9 @@
<item name="java.lang.invoke.ToGeneric java.lang.invoke.MethodHandle computeReturnConversion(java.lang.invoke.MethodType, java.lang.invoke.MethodType, boolean) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.invoke.ToGeneric java.lang.invoke.MethodHandle computeReturnConversion(java.lang.invoke.MethodType, java.lang.invoke.MethodType, boolean)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.ToGeneric java.lang.invoke.MethodHandle make(java.lang.invoke.MethodType, java.lang.invoke.MethodHandle) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -1886,6 +2033,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="java.lang.invoke.ToGeneric java.lang.invoke.ToGeneric of(java.lang.invoke.MethodType) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
@@ -1896,6 +2044,9 @@
<item name="java.lang.invoke.ToGeneric java.lang.invoke.ToGeneric.Adapter findAdapter(java.lang.invoke.MethodType) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.lang.invoke.ToGeneric java.lang.invoke.ToGeneric.Adapter findAdapter(java.lang.invoke.MethodType)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.ToGeneric java.lang.invoke.ToGeneric.Adapter makeInstance(java.lang.invoke.MethodType, java.lang.invoke.MethodHandle) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -2040,6 +2191,9 @@
<item name="java.lang.invoke.ToGeneric.Adapter java.lang.Class&lt;? extends java.lang.invoke.ToGeneric.Adapter&gt; findSubClass(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="java.lang.invoke.ToGeneric.Adapter java.lang.Class&lt;? extends java.lang.invoke.ToGeneric.Adapter&gt; findSubClass(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.lang.invoke.VolatileCallSite VolatileCallSite(java.lang.invoke.MethodHandle) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
diff --git a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/net/annotations.xml b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/net/annotations.xml
index be6006068f41..5a53068cca3b 100644
--- a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/net/annotations.xml
+++ b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/net/annotations.xml
@@ -41,6 +41,18 @@
<item name="java.net.DatagramSocket DatagramSocket(java.net.SocketAddress) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="java.net.DatagramSocket java.net.InetAddress getLocalAddress()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.net.DatagramSocket java.net.SocketAddress getLocalSocketAddress()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.net.DatagramSocket java.net.SocketAddress getRemoteSocketAddress()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.net.DatagramSocket java.nio.channels.DatagramChannel getChannel()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.net.DatagramSocket void connect(java.net.InetAddress, int) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -67,6 +79,9 @@
<val val="&quot;!null-&gt;false;null-&gt;false&quot;"/>
</annotation>
</item>
+ <item name="java.net.InetAddress byte[] getAddress()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.net.InetAddress int checkNumericZone(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -74,13 +89,20 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="java.net.InetAddress java.lang.Object getCachedAddress(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.net.InetAddress java.lang.Object getCachedAddress(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.net.InetAddress java.lang.Object readResolve()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.net.InetAddress java.lang.String getHostAddress()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.net.InetAddress java.lang.String getHostFromNameService(java.net.InetAddress, boolean) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -127,12 +149,21 @@
<item name="java.net.ServerSocket java.lang.String toString()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.net.ServerSocket java.net.InetAddress getInetAddress()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.net.ServerSocket java.net.Socket accept()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.net.ServerSocket java.net.SocketAddress getLocalSocketAddress()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.net.ServerSocket java.net.SocketImpl access$000(java.net.ServerSocket) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.net.ServerSocket java.nio.channels.ServerSocketChannel getChannel()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.net.ServerSocket void implAccept(java.net.Socket) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -163,6 +194,18 @@
<item name="java.net.Socket java.lang.String toString()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.net.Socket java.net.InetAddress getInetAddress()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.net.Socket java.net.SocketAddress getLocalSocketAddress()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.net.Socket java.net.SocketAddress getRemoteSocketAddress()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.net.Socket java.nio.channels.SocketChannel getChannel()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.net.Socket void bind(java.net.SocketAddress) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -572,9 +615,15 @@
<item name="java.net.URLConnection int readBytes(int[], int, java.io.InputStream) 2">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.net.URLConnection java.lang.String getContentEncoding()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.net.URLConnection java.lang.String getContentHandlerPkgPrefixes()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.net.URLConnection java.lang.String getContentType()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.net.URLConnection java.lang.String getDefaultRequestProperty(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -582,6 +631,10 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null-&gt;null;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.net.URLConnection java.lang.String getHeaderField(int)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="java.net.URLConnection java.lang.String getHeaderField(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -590,10 +643,20 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null-&gt;null;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.net.URLConnection java.lang.String getHeaderFieldKey(int)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.net.URLConnection java.lang.String getRequestProperty(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="java.net.URLConnection java.lang.String guessContentTypeFromStream(java.io.InputStream) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.net.URLConnection java.lang.String guessContentTypeFromStream(java.io.InputStream)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.net.URLConnection java.lang.String stripOffParameters(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -601,6 +664,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null-&gt;!null;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="java.net.URLConnection java.lang.String toString()">
<annotation name="org.jetbrains.annotations.NotNull"/>
diff --git a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/security/annotations.xml b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/security/annotations.xml
index 597b80fe0d3f..b99175ab871b 100644
--- a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/security/annotations.xml
+++ b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/security/annotations.xml
@@ -45,6 +45,12 @@
<item name="java.security.Provider java.lang.String[] getTypeAndAlgorithm(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.security.Provider java.lang.String[] getTypeAndAlgorithm(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.security.Provider java.security.Provider.Service getService(java.lang.String, java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.security.Provider java.util.Collection values()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -120,6 +126,9 @@
<item name="java.security.Security java.lang.String getAlgorithmProperty(java.lang.String, java.lang.String) 1">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="java.security.Security java.lang.String getAlgorithmProperty(java.lang.String, java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.security.Security java.lang.String getProviderProperty(java.lang.String, java.security.Provider) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -135,9 +144,18 @@
<item name="java.security.Security java.security.Provider[] getProviders(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.security.Security java.security.Provider[] getProviders(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.security.Security java.security.Provider[] getProviders(java.util.Map) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.security.Security java.security.Provider[] getProviders(java.util.Map)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.security.Security java.security.Security.ProviderProperty getProviderProperty(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.security.Security java.util.LinkedHashSet getAllQualifyingCandidates(java.lang.String, java.lang.String, java.security.Provider[]) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
diff --git a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/sql/annotations.xml b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/sql/annotations.xml
index 1938616b2fff..194509a466c5 100644
--- a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/sql/annotations.xml
+++ b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/sql/annotations.xml
@@ -23,6 +23,9 @@
<item name="java.sql.BatchUpdateException BatchUpdateException(java.lang.String, java.lang.String, int[], java.lang.Throwable) 2">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="java.sql.BatchUpdateException int[] getUpdateCounts()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.sql.Date java.lang.String toString()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -89,6 +92,12 @@
<item name="java.sql.DriverManager void setLogWriter(java.io.PrintWriter) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="java.sql.DriverManager.2 java.lang.Object run()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.sql.DriverManager.2 java.lang.Void run()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.sql.SQLException java.util.Iterator&lt;java.lang.Throwable&gt; iterator()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
diff --git a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/util/annotations.xml b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/util/annotations.xml
index 5e73e2012e79..b00729c52c66 100644
--- a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/util/annotations.xml
+++ b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/util/annotations.xml
@@ -61,6 +61,9 @@
<item name="java.util.AbstractMap V get(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="java.util.AbstractMap V get(java.lang.Object)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.util.AbstractMap V put(K, V) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -70,6 +73,9 @@
<item name="java.util.AbstractMap V remove(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="java.util.AbstractMap V remove(java.lang.Object)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.util.AbstractMap boolean containsKey(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -1101,6 +1107,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null-&gt;null;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="java.util.Collections.EmptyMap boolean containsKey(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -1172,6 +1179,9 @@
<item name="java.util.Collections.SingletonMap V get(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="java.util.Collections.SingletonMap V get(java.lang.Object)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.util.Collections.SingletonMap boolean containsKey(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -1392,6 +1402,9 @@
<item name="java.util.Date int compareTo(java.util.Date) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.util.Date java.lang.Object clone()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.util.Date long parse(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -1442,13 +1455,23 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="java.util.HashMap V get(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="java.util.HashMap V get(java.lang.Object)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.util.HashMap V put(K, V) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="java.util.HashMap V put(K, V)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.util.HashMap V remove(java.lang.Object)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.util.HashMap boolean containsKey(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -1476,6 +1499,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="java.util.HashMap java.util.Iterator&lt;K&gt; newKeyIterator()">
<annotation name="org.jetbrains.annotations.NotNull"/>
@@ -1510,15 +1534,24 @@
<item name="java.util.Hashtable V get(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.util.Hashtable V get(java.lang.Object)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.util.Hashtable V put(K, V) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
<item name="java.util.Hashtable V put(K, V) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.util.Hashtable V put(K, V)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.util.Hashtable V remove(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.util.Hashtable V remove(java.lang.Object)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.util.Hashtable boolean contains(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -1615,12 +1648,21 @@
<item name="java.util.IdentityHashMap V get(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="java.util.IdentityHashMap V get(java.lang.Object)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.util.IdentityHashMap V put(K, V) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="java.util.IdentityHashMap V put(K, V)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.util.IdentityHashMap V remove(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="java.util.IdentityHashMap V remove(java.lang.Object)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.util.IdentityHashMap boolean access$1500(java.util.IdentityHashMap, java.lang.Object, java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -1676,6 +1718,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="java.util.IdentityHashMap java.lang.Object maskNull(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -1689,6 +1732,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="java.util.IdentityHashMap java.lang.Object[] access$100(java.util.IdentityHashMap) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
@@ -1711,6 +1755,9 @@
<item name="java.util.IdentityHashMap.EntryIterator.Entry Entry(java.util.IdentityHashMap.EntryIterator, int, java.util.IdentityHashMap.1) 2">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="java.util.IdentityHashMap.EntryIterator.Entry K getKey()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.util.IdentityHashMap.EntryIterator.Entry boolean equals(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -1751,6 +1798,9 @@
<item name="java.util.IdentityHashMap.IdentityHashMapIterator IdentityHashMapIterator(java.util.IdentityHashMap, java.util.IdentityHashMap.1) 1">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="java.util.IdentityHashMap.KeyIterator K next()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.util.IdentityHashMap.KeyIterator KeyIterator(java.util.IdentityHashMap, java.util.IdentityHashMap.1) 1">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -1835,6 +1885,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;_,null-&gt;!null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="java.util.Locale java.lang.String toLowerCase(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
@@ -1944,6 +1995,15 @@
<item name="java.util.TreeMap TreeMap(java.util.SortedMap&lt;K,? extends V&gt;) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.util.TreeMap V get(java.lang.Object)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.util.TreeMap V put(K, V)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.util.TreeMap V remove(java.lang.Object)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.util.TreeMap boolean access$500(java.lang.Object, java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -1997,12 +2057,18 @@
<item name="java.util.TreeMap java.util.TreeMap.Entry access$1100(java.util.TreeMap, java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.util.TreeMap java.util.TreeMap.Entry access$1100(java.util.TreeMap, java.lang.Object)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.util.TreeMap java.util.TreeMap.Entry access$1300(java.util.TreeMap) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
<item name="java.util.TreeMap java.util.TreeMap.Entry access$1400(java.util.TreeMap, java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.util.TreeMap java.util.TreeMap.Entry access$1400(java.util.TreeMap, java.lang.Object)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.util.TreeMap java.util.TreeMap.Entry access$300(java.util.TreeMap) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -2016,10 +2082,26 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;_,null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="java.util.TreeMap java.util.TreeMap.Entry access$800(java.util.TreeMap, java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.util.TreeMap java.util.TreeMap.Entry access$800(java.util.TreeMap, java.lang.Object)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.util.TreeMap java.util.TreeMap.Entry&lt;K,V&gt; buildFromSorted(int, int, int, int, java.util.Iterator, java.io.ObjectInputStream, V)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.util.TreeMap java.util.TreeMap.Entry&lt;K,V&gt; getCeilEntry(K)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.util.TreeMap java.util.TreeMap.Entry&lt;K,V&gt; getEntry(java.lang.Object)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.util.TreeMap java.util.TreeMap.Entry&lt;K,V&gt; getPrecedingEntry(K)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.util.TreeMap java.util.TreeMap.Entry&lt;K,V&gt; leftOf(java.util.TreeMap.Entry&lt;K,V&gt;) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -2027,6 +2109,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="java.util.TreeMap java.util.TreeMap.Entry&lt;K,V&gt; parentOf(java.util.TreeMap.Entry&lt;K,V&gt;) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2035,6 +2118,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="java.util.TreeMap java.util.TreeMap.Entry&lt;K,V&gt; rightOf(java.util.TreeMap.Entry&lt;K,V&gt;) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2043,6 +2127,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="java.util.TreeMap java.util.TreeMap.Entry&lt;K,V&gt; successor(java.util.TreeMap.Entry&lt;K,V&gt;) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2051,6 +2136,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="java.util.TreeMap void access$600(java.util.TreeMap, java.util.TreeMap.Entry) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
diff --git a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/util/concurrent/locks/annotations.xml b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/util/concurrent/locks/annotations.xml
index 08c07b4d957f..56dd8599d15d 100644
--- a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/util/concurrent/locks/annotations.xml
+++ b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/java/util/concurrent/locks/annotations.xml
@@ -29,6 +29,12 @@
<item name="java.util.concurrent.locks.AbstractQueuedSynchronizer java.lang.String toString()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.util.concurrent.locks.AbstractQueuedSynchronizer java.lang.Thread fullGetFirstQueuedThread()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="java.util.concurrent.locks.AbstractQueuedSynchronizer java.lang.Thread getFirstQueuedThread()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.util.concurrent.locks.AbstractQueuedSynchronizer java.util.Collection&lt;java.lang.Thread&gt; getWaitingThreads(java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -83,12 +89,18 @@
<item name="java.util.concurrent.locks.ReentrantLock java.lang.String toString()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.util.concurrent.locks.ReentrantLock java.lang.Thread getOwner()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.util.concurrent.locks.ReentrantLock java.util.Collection&lt;java.lang.Thread&gt; getWaitingThreads(java.util.concurrent.locks.Condition) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
<item name="java.util.concurrent.locks.ReentrantLock java.util.concurrent.locks.Condition newCondition()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.util.concurrent.locks.ReentrantLock.Sync java.lang.Thread getOwner()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.util.concurrent.locks.ReentrantLock.Sync java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject newCondition()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -104,6 +116,9 @@
<item name="java.util.concurrent.locks.ReentrantReadWriteLock java.lang.String toString()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.util.concurrent.locks.ReentrantReadWriteLock java.lang.Thread getOwner()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.util.concurrent.locks.ReentrantReadWriteLock java.util.Collection&lt;java.lang.Thread&gt; getWaitingThreads(java.util.concurrent.locks.Condition) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -119,6 +134,9 @@
<item name="java.util.concurrent.locks.ReentrantReadWriteLock.Sync java.lang.IllegalMonitorStateException unmatchedUnlockException()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="java.util.concurrent.locks.ReentrantReadWriteLock.Sync java.lang.Thread getOwner()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="java.util.concurrent.locks.ReentrantReadWriteLock.Sync java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject newCondition()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
diff --git a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/javax/swing/annotations.xml b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/javax/swing/annotations.xml
index 910842a47153..80dbfdb022ed 100644
--- a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/javax/swing/annotations.xml
+++ b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/javax/swing/annotations.xml
@@ -5,9 +5,15 @@
<item name="javax.swing.AbstractButton boolean isListener(java.lang.Class, java.awt.event.ActionListener) 1">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="javax.swing.AbstractButton java.awt.Insets getMargin()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="javax.swing.AbstractButton java.beans.PropertyChangeListener createActionPropertyChangeListener(javax.swing.Action)">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="javax.swing.AbstractButton java.lang.Object[] getSelectedObjects()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="javax.swing.AbstractButton java.lang.String paramString()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -63,6 +69,9 @@
<item name="javax.swing.JComponent byte getWriteObjCounter(javax.swing.JComponent) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="javax.swing.JComponent java.awt.Container getTopLevelAncestor()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="javax.swing.JComponent java.awt.Dimension getSize(java.awt.Dimension) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -94,6 +103,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null-&gt;null;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="javax.swing.JComponent java.awt.Point getToolTipLocation(java.awt.event.MouseEvent) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -102,6 +112,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null-&gt;null;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="javax.swing.JComponent java.awt.Rectangle getBounds(java.awt.Rectangle) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -114,6 +125,12 @@
<item name="javax.swing.JComponent java.awt.Rectangle getVisibleRect()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="javax.swing.JComponent java.awt.event.ActionListener getActionForKeyStroke(javax.swing.KeyStroke)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="javax.swing.JComponent java.lang.Object getClientProperty(java.lang.Object)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="javax.swing.JComponent java.lang.String getToolTipText(java.awt.event.MouseEvent) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -123,6 +140,27 @@
<item name="javax.swing.JComponent java.lang.String paramString()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="javax.swing.JComponent javax.swing.ActionMap getActionMap()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="javax.swing.JComponent javax.swing.ActionMap getActionMap(boolean)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="javax.swing.JComponent javax.swing.InputMap getInputMap()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="javax.swing.JComponent javax.swing.InputMap getInputMap(int)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="javax.swing.JComponent javax.swing.InputMap getInputMap(int, boolean)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="javax.swing.JComponent javax.swing.JPopupMenu getPopupMenu()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="javax.swing.JComponent javax.swing.JRootPane getRootPane()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="javax.swing.JComponent javax.swing.JToolTip createToolTip()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -178,10 +216,20 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="javax.swing.JComponent.AccessibleJComponent java.lang.String getTitledBorderText()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="javax.swing.JComponent.AccessibleJComponent java.lang.String getToolTipText()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="javax.swing.JComponent.AccessibleJComponent javax.accessibility.AccessibleExtendedComponent getAccessibleExtendedComponent()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="javax.swing.JComponent.AccessibleJComponent javax.accessibility.AccessibleKeyBinding getAccessibleKeyBinding()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="javax.swing.JComponent.AccessibleJComponent javax.swing.JComponent access$100(javax.swing.JComponent.AccessibleJComponent) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -245,6 +293,9 @@
<item name="javax.swing.JScrollPane java.awt.Component getCorner(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="javax.swing.JScrollPane java.awt.Component getCorner(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="javax.swing.JScrollPane java.awt.Rectangle getViewportBorderBounds()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -343,6 +394,9 @@
<item name="javax.swing.JTable javax.swing.table.JTableHeader createDefaultTableHeader()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="javax.swing.JTable javax.swing.table.TableCellEditor getCellEditor(int, int)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="javax.swing.JTable javax.swing.table.TableCellEditor getDefaultEditor(java.lang.Class) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -350,6 +404,10 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="javax.swing.JTable javax.swing.table.TableCellRenderer getCellRenderer(int, int)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="javax.swing.JTable javax.swing.table.TableCellRenderer getDefaultRenderer(java.lang.Class) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -358,6 +416,10 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="javax.swing.JTable javax.swing.table.TableColumn getResizingColumn()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="javax.swing.JTable javax.swing.table.TableColumnModel createDefaultColumnModel()">
<annotation name="org.jetbrains.annotations.NotNull"/>
@@ -521,12 +583,21 @@
<item name="javax.swing.SwingUtilities java.awt.Component findFocusOwner(java.awt.Component) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="javax.swing.SwingUtilities java.awt.Component findFocusOwner(java.awt.Component)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="javax.swing.SwingUtilities java.awt.Component getDeepestComponentAt(java.awt.Component, int, int) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="javax.swing.SwingUtilities java.awt.Component getDeepestComponentAt(java.awt.Component, int, int)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="javax.swing.SwingUtilities java.awt.Component getRoot(java.awt.Component) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="javax.swing.SwingUtilities java.awt.Component getRoot(java.awt.Component)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="javax.swing.SwingUtilities java.awt.Container getAncestorNamed(java.lang.String, java.awt.Component) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -537,6 +608,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;_,null-&gt;null;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="javax.swing.SwingUtilities java.awt.Container getAncestorOfClass(java.lang.Class, java.awt.Component) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -548,6 +620,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;_,null-&gt;null;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="javax.swing.SwingUtilities java.awt.Point convertPoint(java.awt.Component, int, int, java.awt.Component)">
<annotation name="org.jetbrains.annotations.Contract">
@@ -575,6 +648,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="javax.swing.SwingUtilities java.awt.Rectangle computeIntersection(int, int, int, int, java.awt.Rectangle) 4">
<annotation name="org.jetbrains.annotations.NotNull"/>
@@ -613,9 +687,15 @@
<item name="javax.swing.SwingUtilities java.awt.Window getWindowAncestor(java.awt.Component) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="javax.swing.SwingUtilities java.awt.Window getWindowAncestor(java.awt.Component)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="javax.swing.SwingUtilities java.awt.Window windowForComponent(java.awt.Component) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="javax.swing.SwingUtilities java.awt.Window windowForComponent(java.awt.Component)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="javax.swing.SwingUtilities java.awt.event.MouseEvent convertMouseEvent(java.awt.Component, java.awt.event.MouseEvent, java.awt.Component) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -686,6 +766,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="javax.swing.SwingUtilities javax.accessibility.Accessible getAccessibleChild(java.awt.Component, int) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
@@ -696,12 +777,18 @@
<item name="javax.swing.SwingUtilities javax.swing.ActionMap getUIActionMap(javax.swing.JComponent) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="javax.swing.SwingUtilities javax.swing.ActionMap getUIActionMap(javax.swing.JComponent)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="javax.swing.SwingUtilities javax.swing.CellRendererPane getCellRendererPane(java.awt.Component, java.awt.Container) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
<item name="javax.swing.SwingUtilities javax.swing.InputMap getUIInputMap(javax.swing.JComponent, int) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="javax.swing.SwingUtilities javax.swing.InputMap getUIInputMap(javax.swing.JComponent, int)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="javax.swing.SwingUtilities javax.swing.JRootPane getRootPane(java.awt.Component) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -709,6 +796,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="javax.swing.SwingUtilities void convertPointFromScreen(java.awt.Point, java.awt.Component) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
diff --git a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/collections/annotations.xml b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/collections/annotations.xml
index 89a90c53dae2..2cce3e65d8e3 100644
--- a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/collections/annotations.xml
+++ b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/collections/annotations.xml
@@ -20,6 +20,15 @@
<item name="org.apache.commons.collections.ExtendedProperties java.lang.String escape(java.lang.String)">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.commons.collections.ExtendedProperties java.lang.String getString(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="org.apache.commons.collections.ExtendedProperties java.lang.String getString(java.lang.String, java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="org.apache.commons.collections.ExtendedProperties java.lang.String interpolate(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.collections.ExtendedProperties java.lang.String interpolateHelper(java.lang.String, java.util.List) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -27,10 +36,14 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null,_-&gt;!null;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.collections.ExtendedProperties java.lang.String testBoolean(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.commons.collections.ExtendedProperties java.lang.String testBoolean(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.collections.ExtendedProperties java.lang.String unescape(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -40,6 +53,9 @@
<item name="org.apache.commons.collections.ExtendedProperties org.apache.commons.collections.ExtendedProperties convertProperties(java.util.Properties) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.commons.collections.ExtendedProperties org.apache.commons.collections.ExtendedProperties subset(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.collections.ExtendedProperties void combine(org.apache.commons.collections.ExtendedProperties) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -52,6 +68,9 @@
<item name="org.apache.commons.collections.ExtendedProperties void setInclude(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.commons.collections.ExtendedProperties.PropertiesReader java.lang.String readProperty()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.collections.ExtendedProperties.PropertiesTokenizer java.lang.String nextToken()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
diff --git a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/collections/map/annotations.xml b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/collections/map/annotations.xml
index bd99ae8b862d..57a09af56b91 100644
--- a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/collections/map/annotations.xml
+++ b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/collections/map/annotations.xml
@@ -24,6 +24,9 @@
<item name="org.apache.commons.collections.map.AbstractHashedMap int hash(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.commons.collections.map.AbstractHashedMap java.lang.Object clone()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.collections.map.AbstractHashedMap java.lang.Object convertKey(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -38,6 +41,15 @@
<item name="org.apache.commons.collections.map.AbstractHashedMap java.lang.Object entryValue(org.apache.commons.collections.map.AbstractHashedMap.HashEntry) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.commons.collections.map.AbstractHashedMap java.lang.Object get(java.lang.Object)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="org.apache.commons.collections.map.AbstractHashedMap java.lang.Object put(java.lang.Object, java.lang.Object)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="org.apache.commons.collections.map.AbstractHashedMap java.lang.Object remove(java.lang.Object)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.collections.map.AbstractHashedMap java.lang.String toString()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -47,6 +59,9 @@
<item name="org.apache.commons.collections.map.AbstractHashedMap org.apache.commons.collections.map.AbstractHashedMap.HashEntry entryNext(org.apache.commons.collections.map.AbstractHashedMap.HashEntry) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.commons.collections.map.AbstractHashedMap org.apache.commons.collections.map.AbstractHashedMap.HashEntry getEntry(java.lang.Object)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.collections.map.AbstractHashedMap void destroyEntry(org.apache.commons.collections.map.AbstractHashedMap.HashEntry) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -93,6 +108,9 @@
<item name="org.apache.commons.collections.map.AbstractHashedMap.HashEntry boolean equals(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.commons.collections.map.AbstractHashedMap.HashEntry java.lang.Object getKey()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.collections.map.AbstractHashedMap.HashEntry java.lang.String toString()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -117,6 +135,12 @@
<item name="org.apache.commons.collections.map.AbstractLinkedMap boolean containsValue(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.commons.collections.map.AbstractLinkedMap java.lang.Object nextKey(java.lang.Object)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="org.apache.commons.collections.map.AbstractLinkedMap java.lang.Object previousKey(java.lang.Object)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.collections.map.AbstractLinkedMap org.apache.commons.collections.map.AbstractHashedMap.HashEntry createEntry(org.apache.commons.collections.map.AbstractHashedMap.HashEntry, int, java.lang.Object, java.lang.Object)">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -167,6 +191,9 @@
<val val="&quot;!null-&gt;true;null-&gt;true&quot;"/>
</annotation>
</item>
+ <item name="org.apache.commons.collections.map.LRUMap java.lang.Object get(java.lang.Object)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.collections.map.LRUMap void doReadObject(java.io.ObjectInputStream) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
diff --git a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/lang/annotations.xml b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/lang/annotations.xml
index 7115dfb72473..e825ad4c8fa7 100644
--- a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/lang/annotations.xml
+++ b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/lang/annotations.xml
@@ -161,6 +161,9 @@
<item name="org.apache.commons.lang.ArrayUtils boolean[] addAll(boolean[], boolean[]) 1">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.commons.lang.ArrayUtils boolean[] addAll(boolean[], boolean[])">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.ArrayUtils boolean[] clone(boolean[]) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -168,10 +171,14 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils boolean[] remove(boolean[], int) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.commons.lang.ArrayUtils boolean[] removeElement(boolean[], boolean)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.ArrayUtils boolean[] subarray(boolean[], int, int) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -179,6 +186,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils boolean[] toPrimitive(java.lang.Boolean[]) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -187,6 +195,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils boolean[] toPrimitive(java.lang.Boolean[], boolean) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -195,6 +204,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils byte[] add(byte[], byte) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -205,6 +215,9 @@
<item name="org.apache.commons.lang.ArrayUtils byte[] addAll(byte[], byte[]) 1">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.commons.lang.ArrayUtils byte[] addAll(byte[], byte[])">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.ArrayUtils byte[] clone(byte[]) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -212,10 +225,14 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils byte[] remove(byte[], int) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.commons.lang.ArrayUtils byte[] removeElement(byte[], byte)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.ArrayUtils byte[] subarray(byte[], int, int) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -223,6 +240,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils byte[] toPrimitive(java.lang.Byte[]) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -231,6 +249,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils byte[] toPrimitive(java.lang.Byte[], byte) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -239,6 +258,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils char[] add(char[], char) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -249,6 +269,9 @@
<item name="org.apache.commons.lang.ArrayUtils char[] addAll(char[], char[]) 1">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.commons.lang.ArrayUtils char[] addAll(char[], char[])">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.ArrayUtils char[] clone(char[]) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -256,10 +279,14 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils char[] remove(char[], int) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.commons.lang.ArrayUtils char[] removeElement(char[], char)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.ArrayUtils char[] subarray(char[], int, int) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -267,6 +294,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils char[] toPrimitive(java.lang.Character[]) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -275,6 +303,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils char[] toPrimitive(java.lang.Character[], char) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -283,6 +312,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils double[] add(double[], double) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -293,6 +323,9 @@
<item name="org.apache.commons.lang.ArrayUtils double[] addAll(double[], double[]) 1">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.commons.lang.ArrayUtils double[] addAll(double[], double[])">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.ArrayUtils double[] clone(double[]) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -300,10 +333,14 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils double[] remove(double[], int) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.commons.lang.ArrayUtils double[] removeElement(double[], double)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.ArrayUtils double[] subarray(double[], int, int) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -311,6 +348,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils double[] toPrimitive(java.lang.Double[]) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -319,6 +357,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils double[] toPrimitive(java.lang.Double[], double) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -327,6 +366,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils float[] add(float[], float) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -337,6 +377,9 @@
<item name="org.apache.commons.lang.ArrayUtils float[] addAll(float[], float[]) 1">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.commons.lang.ArrayUtils float[] addAll(float[], float[])">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.ArrayUtils float[] clone(float[]) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -344,10 +387,14 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils float[] remove(float[], int) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.commons.lang.ArrayUtils float[] removeElement(float[], float)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.ArrayUtils float[] subarray(float[], int, int) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -355,6 +402,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils float[] toPrimitive(java.lang.Float[]) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -363,6 +411,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils float[] toPrimitive(java.lang.Float[], float) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -371,6 +420,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils int getLength(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -468,6 +518,9 @@
<item name="org.apache.commons.lang.ArrayUtils int[] addAll(int[], int[]) 1">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.commons.lang.ArrayUtils int[] addAll(int[], int[])">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.ArrayUtils int[] clone(int[]) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -475,10 +528,14 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils int[] remove(int[], int) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.commons.lang.ArrayUtils int[] removeElement(int[], int)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.ArrayUtils int[] subarray(int[], int, int) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -486,6 +543,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils int[] toPrimitive(java.lang.Integer[]) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -494,6 +552,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils int[] toPrimitive(java.lang.Integer[], int) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -502,6 +561,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils java.lang.Boolean[] toObject(boolean[]) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -510,6 +570,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils java.lang.Byte[] toObject(byte[]) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -518,6 +579,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils java.lang.Character[] toObject(char[]) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -526,6 +588,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils java.lang.Double[] toObject(double[]) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -534,6 +597,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils java.lang.Float[] toObject(float[]) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -542,6 +606,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils java.lang.Integer[] toObject(int[]) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -550,6 +615,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils java.lang.Long[] toObject(long[]) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -558,6 +624,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils java.lang.Object copyArrayGrow1(java.lang.Object, java.lang.Class) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -574,6 +641,9 @@
<item name="org.apache.commons.lang.ArrayUtils java.lang.Object[] addAll(java.lang.Object[], java.lang.Object[]) 1">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.commons.lang.ArrayUtils java.lang.Object[] addAll(java.lang.Object[], java.lang.Object[])">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.ArrayUtils java.lang.Object[] clone(java.lang.Object[]) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -581,6 +651,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils java.lang.Object[] remove(java.lang.Object[], int) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
@@ -588,6 +659,9 @@
<item name="org.apache.commons.lang.ArrayUtils java.lang.Object[] removeElement(java.lang.Object[], java.lang.Object) 1">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.commons.lang.ArrayUtils java.lang.Object[] removeElement(java.lang.Object[], java.lang.Object)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.ArrayUtils java.lang.Object[] subarray(java.lang.Object[], int, int) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -595,6 +669,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils java.lang.Short[] toObject(short[]) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -603,6 +678,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils java.lang.String toString(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -617,6 +693,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils long[] add(long[], long) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -627,6 +704,9 @@
<item name="org.apache.commons.lang.ArrayUtils long[] addAll(long[], long[]) 1">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.commons.lang.ArrayUtils long[] addAll(long[], long[])">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.ArrayUtils long[] clone(long[]) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -634,10 +714,14 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils long[] remove(long[], int) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.commons.lang.ArrayUtils long[] removeElement(long[], long)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.ArrayUtils long[] subarray(long[], int, int) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -645,6 +729,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils long[] toPrimitive(java.lang.Long[]) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -653,6 +738,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils long[] toPrimitive(java.lang.Long[], long) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -661,6 +747,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils short[] add(short[], short) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -671,6 +758,9 @@
<item name="org.apache.commons.lang.ArrayUtils short[] addAll(short[], short[]) 1">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.commons.lang.ArrayUtils short[] addAll(short[], short[])">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.ArrayUtils short[] clone(short[]) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -678,10 +768,14 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils short[] remove(short[], int) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.commons.lang.ArrayUtils short[] removeElement(short[], short)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.ArrayUtils short[] subarray(short[], int, int) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -689,6 +783,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils short[] toPrimitive(java.lang.Short[]) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -697,6 +792,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils short[] toPrimitive(java.lang.Short[], short) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -705,6 +801,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ArrayUtils void reverse(boolean[]) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -794,6 +891,10 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="org.apache.commons.lang.BooleanUtils java.lang.Boolean toBooleanObject(int, int, int, int)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.BooleanUtils java.lang.Boolean toBooleanObject(java.lang.Integer) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -802,6 +903,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.BooleanUtils java.lang.Boolean toBooleanObject(java.lang.Integer, java.lang.Integer, java.lang.Integer, java.lang.Integer) 1">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -812,9 +914,15 @@
<item name="org.apache.commons.lang.BooleanUtils java.lang.Boolean toBooleanObject(java.lang.Integer, java.lang.Integer, java.lang.Integer, java.lang.Integer) 3">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.commons.lang.BooleanUtils java.lang.Boolean toBooleanObject(java.lang.Integer, java.lang.Integer, java.lang.Integer, java.lang.Integer)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.BooleanUtils java.lang.Boolean toBooleanObject(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.commons.lang.BooleanUtils java.lang.Boolean toBooleanObject(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.BooleanUtils java.lang.Boolean toBooleanObject(java.lang.String, java.lang.String, java.lang.String, java.lang.String) 1">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -824,6 +932,9 @@
<item name="org.apache.commons.lang.BooleanUtils java.lang.Boolean toBooleanObject(java.lang.String, java.lang.String, java.lang.String, java.lang.String) 3">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.commons.lang.BooleanUtils java.lang.Boolean toBooleanObject(java.lang.String, java.lang.String, java.lang.String, java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.BooleanUtils java.lang.Boolean xor(java.lang.Boolean[]) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -834,6 +945,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.BooleanUtils java.lang.Integer toIntegerObject(java.lang.Boolean, java.lang.Integer, java.lang.Integer, java.lang.Integer) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -877,6 +989,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null-&gt;!null;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.CharSet void add(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -904,6 +1017,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null,_-&gt;!null;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.CharSetUtils java.lang.String keep(java.lang.String, java.lang.String[]) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -915,6 +1029,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null,_-&gt;!null;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.CharSetUtils java.lang.String modify(java.lang.String, java.lang.String[], boolean) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
@@ -950,6 +1065,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null-&gt;!null;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.CharUtils char toChar(java.lang.Character) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
@@ -970,6 +1086,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.CharUtils java.lang.String toString(java.lang.Character) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -978,6 +1095,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.CharUtils java.lang.String unicodeEscaped(char)">
<annotation name="org.jetbrains.annotations.NotNull"/>
@@ -989,6 +1107,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null-&gt;!null;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ClassUtils boolean isAssignable(java.lang.Class, java.lang.Class) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -1027,6 +1146,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ClassUtils java.lang.Class[] toClass(java.lang.Object[]) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -1035,6 +1155,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ClassUtils java.lang.Class[] wrappersToPrimitives(java.lang.Class[]) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -1043,6 +1164,10 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="org.apache.commons.lang.ClassUtils java.lang.String getCanonicalName(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ClassUtils java.lang.String getPackageCanonicalName(java.lang.Class) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -1136,6 +1261,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ClassUtils java.util.List convertClassesToClassNames(java.util.List) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -1144,6 +1270,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ClassUtils java.util.List getAllInterfaces(java.lang.Class) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -1152,6 +1279,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ClassUtils java.util.List getAllSuperclasses(java.lang.Class) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -1160,6 +1288,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.Entities java.io.StringWriter createStringWriter(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
@@ -1197,6 +1326,12 @@
<item name="org.apache.commons.lang.Entities.ArrayEntityMap int value(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.commons.lang.Entities.ArrayEntityMap java.lang.String name(int)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="org.apache.commons.lang.Entities.BinaryEntityMap java.lang.String name(int)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.IllegalClassException IllegalClassException(java.lang.Class, java.lang.Class) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -1216,6 +1351,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.IncompleteArgumentException IncompleteArgumentException(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -1233,10 +1369,20 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.IntHashMap boolean contains(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.commons.lang.IntHashMap java.lang.Object get(int)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="org.apache.commons.lang.IntHashMap java.lang.Object put(int, java.lang.Object)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="org.apache.commons.lang.IntHashMap java.lang.Object remove(int)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.LocaleUtils java.util.List localeLookupList(java.util.Locale)">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -1253,6 +1399,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null-&gt;!null;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.NotImplementedException NotImplementedException(java.lang.Class) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -1263,6 +1410,9 @@
<item name="org.apache.commons.lang.NotImplementedException NotImplementedException(java.lang.String, java.lang.Throwable) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.commons.lang.NotImplementedException java.lang.String getMessage()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.NullArgumentException NullArgumentException(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -1351,6 +1501,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.NumberUtils java.math.BigDecimal createBigDecimal(java.lang.String)">
<annotation name="org.jetbrains.annotations.NotNull"/>
@@ -1388,6 +1539,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null-&gt;!null;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ObjectUtils java.lang.String toString(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -1410,6 +1562,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;_,!null-&gt;!null;_,null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.ObjectUtils void identityToString(java.lang.StringBuffer, java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
@@ -1462,15 +1615,27 @@
<item name="org.apache.commons.lang.RandomStringUtils java.lang.String randomNumeric(int)">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.commons.lang.SerializationUtils java.lang.Object clone(java.io.Serializable)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.SerializationUtils java.lang.Object deserialize(byte[]) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.commons.lang.SerializationUtils java.lang.Object deserialize(byte[])">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.SerializationUtils java.lang.Object deserialize(java.io.InputStream) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.commons.lang.SerializationUtils java.lang.Object deserialize(java.io.InputStream)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.SerializationUtils void serialize(java.io.Serializable, java.io.OutputStream) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.commons.lang.StringEscapeUtils java.lang.String escapeCsv(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.StringEscapeUtils java.lang.String escapeHtml(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -1478,13 +1643,20 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringEscapeUtils java.lang.String escapeJava(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.commons.lang.StringEscapeUtils java.lang.String escapeJava(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.StringEscapeUtils java.lang.String escapeJavaScript(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.commons.lang.StringEscapeUtils java.lang.String escapeJavaScript(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.StringEscapeUtils java.lang.String escapeJavaStyleString(java.lang.String, boolean) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -1492,6 +1664,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringEscapeUtils java.lang.String escapeSql(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -1500,6 +1673,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null-&gt;!null;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringEscapeUtils java.lang.String escapeXml(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -1508,6 +1682,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringEscapeUtils java.lang.String hex(char)">
<annotation name="org.jetbrains.annotations.NotNull"/>
@@ -1519,6 +1694,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringEscapeUtils java.lang.String unescapeHtml(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -1527,6 +1703,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringEscapeUtils java.lang.String unescapeJava(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -1535,10 +1712,14 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringEscapeUtils java.lang.String unescapeJavaScript(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.commons.lang.StringEscapeUtils java.lang.String unescapeJavaScript(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.StringEscapeUtils java.lang.String unescapeXml(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -1546,6 +1727,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringEscapeUtils void escapeHtml(java.io.Writer, java.lang.String) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
@@ -1898,6 +2080,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null,_-&gt;!null;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String abbreviate(java.lang.String, int, int) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -1906,6 +2089,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null,_,_-&gt;!null;null,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String capitalise(java.lang.String)">
<annotation name="org.jetbrains.annotations.Contract">
@@ -1926,16 +2110,19 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String center(java.lang.String, int, char)">
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String center(java.lang.String, int, java.lang.String)">
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String chomp(java.lang.String)">
<annotation name="org.jetbrains.annotations.Contract">
@@ -1973,6 +2160,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null-&gt;!null;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String chopNewline(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
@@ -1993,6 +2181,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null-&gt;!null;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String defaultString(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2017,6 +2206,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null-&gt;!null;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String deleteWhitespace(java.lang.String)">
<annotation name="org.jetbrains.annotations.Contract">
@@ -2034,6 +2224,9 @@
<item name="org.apache.commons.lang.StringUtils java.lang.String escape(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.commons.lang.StringUtils java.lang.String escape(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.StringUtils java.lang.String getChomp(java.lang.String, java.lang.String) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -2063,6 +2256,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;_,null-&gt;null;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String getNestedString(java.lang.String, java.lang.String, java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2077,6 +2271,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;_,_,null-&gt;null;_,null,_-&gt;null;null,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String getPrechomp(java.lang.String, java.lang.String) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
@@ -2094,6 +2289,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null-&gt;!null;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String join(java.lang.Object[], char) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2102,6 +2298,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null,_-&gt;!null;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String join(java.lang.Object[], char, int, int) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2110,6 +2307,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null,_,_,_-&gt;!null;null,_,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String join(java.lang.Object[], java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2121,6 +2319,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null,_-&gt;!null;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String join(java.lang.Object[], java.lang.String, int, int) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2132,6 +2331,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null,_,_,_-&gt;!null;null,_,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String join(java.util.Collection, char) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2140,6 +2340,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String join(java.util.Collection, java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2151,6 +2352,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String join(java.util.Iterator, char) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2159,6 +2361,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String join(java.util.Iterator, java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2170,6 +2373,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String left(java.lang.String, int) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2178,6 +2382,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null,_-&gt;!null;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String leftPad(java.lang.String, int) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2186,6 +2391,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String leftPad(java.lang.String, int, char) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2194,6 +2400,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String leftPad(java.lang.String, int, java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2202,6 +2409,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String lowerCase(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2210,6 +2418,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null-&gt;!null;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String mid(java.lang.String, int, int) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2218,6 +2427,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null,_,_-&gt;!null;null,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String overlay(java.lang.String, java.lang.String, int, int) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2229,6 +2439,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null,_,_,_-&gt;!null;null,_,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String overlayString(java.lang.String, java.lang.String, int, int) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
@@ -2290,6 +2501,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null,_-&gt;!null;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String replace(java.lang.String, java.lang.String, java.lang.String) 2">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2314,6 +2526,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null,_,_-&gt;!null;null,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String replaceChars(java.lang.String, java.lang.String, java.lang.String) 2">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2371,6 +2584,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null-&gt;!null;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String reverseDelimited(java.lang.String, char) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2379,6 +2593,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String reverseDelimitedString(java.lang.String, java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2390,6 +2605,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String right(java.lang.String, int) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2398,6 +2614,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null,_-&gt;!null;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String rightPad(java.lang.String, int) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2406,6 +2623,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String rightPad(java.lang.String, int, char) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2414,6 +2632,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String rightPad(java.lang.String, int, java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2422,6 +2641,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String strip(java.lang.String, java.lang.String) 1">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2457,6 +2677,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String substring(java.lang.String, int) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2465,6 +2686,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null,_-&gt;!null;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String substring(java.lang.String, int, int) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2473,6 +2695,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null,_,_-&gt;!null;null,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String substringAfter(java.lang.String, java.lang.String) 1">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2510,6 +2733,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;_,null-&gt;null;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String substringBetween(java.lang.String, java.lang.String, java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2524,6 +2748,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;_,_,null-&gt;null;_,null,_-&gt;null;null,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String swapCase(java.lang.String)">
<annotation name="org.jetbrains.annotations.Contract">
@@ -2537,6 +2762,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null-&gt;!null;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String trimToEmpty(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2551,6 +2777,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String uncapitalise(java.lang.String)">
<annotation name="org.jetbrains.annotations.Contract">
@@ -2569,6 +2796,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null-&gt;!null;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String[] split(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2577,6 +2805,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String[] split(java.lang.String, char) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2585,6 +2814,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String[] split(java.lang.String, java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2596,6 +2826,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String[] split(java.lang.String, java.lang.String, int) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2607,6 +2838,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String[] splitByCharacterType(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2615,6 +2847,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String[] splitByCharacterType(java.lang.String, boolean) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2623,6 +2856,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String[] splitByCharacterTypeCamelCase(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2631,6 +2865,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String[] splitByWholeSeparator(java.lang.String, java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2642,6 +2877,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String[] splitByWholeSeparator(java.lang.String, java.lang.String, int) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2653,6 +2889,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String[] splitByWholeSeparatorPreserveAllTokens(java.lang.String, java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2664,6 +2901,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String[] splitByWholeSeparatorPreserveAllTokens(java.lang.String, java.lang.String, int) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2675,6 +2913,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String[] splitByWholeSeparatorWorker(java.lang.String, java.lang.String, int, boolean) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2686,6 +2925,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String[] splitPreserveAllTokens(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2694,6 +2934,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String[] splitPreserveAllTokens(java.lang.String, char) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2702,6 +2943,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String[] splitPreserveAllTokens(java.lang.String, java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2713,6 +2955,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String[] splitPreserveAllTokens(java.lang.String, java.lang.String, int) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2724,6 +2967,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String[] splitWorker(java.lang.String, char, boolean) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2732,6 +2976,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String[] splitWorker(java.lang.String, java.lang.String, int, boolean) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2743,6 +2988,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.StringUtils java.lang.String[] stripAll(java.lang.String[])">
<annotation name="org.jetbrains.annotations.Contract">
@@ -2764,6 +3010,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.SystemUtils boolean getJavaVersionMatches(java.lang.String)">
<annotation name="org.jetbrains.annotations.Contract">
@@ -2787,6 +3034,12 @@
<item name="org.apache.commons.lang.SystemUtils java.io.File getUserHome()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.commons.lang.SystemUtils java.lang.String getJavaVersionTrimmed()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="org.apache.commons.lang.SystemUtils java.lang.String getSystemProperty(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.Validate void allElementsOfType(java.util.Collection, java.lang.Class) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -2866,6 +3119,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null,_,_,_-&gt;!null;null,_,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.WordUtils java.lang.String capitalize(java.lang.String)">
<annotation name="org.jetbrains.annotations.Contract">
@@ -2931,6 +3185,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null,_-&gt;!null;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.WordUtils java.lang.String wrap(java.lang.String, int, java.lang.String, boolean) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -2942,5 +3197,6 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null,_,_,_-&gt;!null;null,_,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
</root>
diff --git a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/lang/enum/annotations.xml b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/lang/enum/annotations.xml
index 05b15d3460ce..0a18f70a8a8c 100644
--- a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/lang/enum/annotations.xml
+++ b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/lang/enum/annotations.xml
@@ -5,6 +5,9 @@
<item name="org.apache.commons.lang.enum.Enum boolean equals(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.commons.lang.enum.Enum java.lang.Object readResolve()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.enum.Enum java.lang.String getNameInOtherClassLoader(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -20,6 +23,9 @@
<item name="org.apache.commons.lang.enum.Enum org.apache.commons.lang.enum.Enum getEnum(java.lang.Class, java.lang.String) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.commons.lang.enum.Enum org.apache.commons.lang.enum.Enum getEnum(java.lang.Class, java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.enum.Enum org.apache.commons.lang.enum.Enum.Entry createEntry(java.lang.Class) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -38,6 +44,9 @@
<item name="org.apache.commons.lang.enum.EnumUtils org.apache.commons.lang.enum.Enum getEnum(java.lang.Class, java.lang.String) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.commons.lang.enum.EnumUtils org.apache.commons.lang.enum.Enum getEnum(java.lang.Class, java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.enum.EnumUtils org.apache.commons.lang.enum.ValuedEnum getEnum(java.lang.Class, int) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -50,4 +59,7 @@
<item name="org.apache.commons.lang.enum.ValuedEnum org.apache.commons.lang.enum.Enum getEnum(java.lang.Class, int) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.commons.lang.enum.ValuedEnum org.apache.commons.lang.enum.Enum getEnum(java.lang.Class, int)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
</root>
diff --git a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/lang/enums/annotations.xml b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/lang/enums/annotations.xml
index 3b827c118787..88ab27cab4cb 100644
--- a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/lang/enums/annotations.xml
+++ b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/lang/enums/annotations.xml
@@ -5,6 +5,9 @@
<item name="org.apache.commons.lang.enums.Enum boolean equals(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.commons.lang.enums.Enum java.lang.Object readResolve()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.enums.Enum java.lang.String getNameInOtherClassLoader(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -20,6 +23,9 @@
<item name="org.apache.commons.lang.enums.Enum org.apache.commons.lang.enums.Enum getEnum(java.lang.Class, java.lang.String) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.commons.lang.enums.Enum org.apache.commons.lang.enums.Enum getEnum(java.lang.Class, java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.enums.Enum org.apache.commons.lang.enums.Enum.Entry createEntry(java.lang.Class) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -38,6 +44,9 @@
<item name="org.apache.commons.lang.enums.EnumUtils org.apache.commons.lang.enums.Enum getEnum(java.lang.Class, java.lang.String) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.commons.lang.enums.EnumUtils org.apache.commons.lang.enums.Enum getEnum(java.lang.Class, java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.enums.EnumUtils org.apache.commons.lang.enums.ValuedEnum getEnum(java.lang.Class, int) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -50,4 +59,7 @@
<item name="org.apache.commons.lang.enums.ValuedEnum org.apache.commons.lang.enums.Enum getEnum(java.lang.Class, int) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.commons.lang.enums.ValuedEnum org.apache.commons.lang.enums.Enum getEnum(java.lang.Class, int)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
</root>
diff --git a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/lang/exception/annotations.xml b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/lang/exception/annotations.xml
index 585584b958f2..ba729507a8bc 100644
--- a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/lang/exception/annotations.xml
+++ b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/lang/exception/annotations.xml
@@ -86,6 +86,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.exception.ExceptionUtils java.lang.Throwable getCause(java.lang.Throwable, java.lang.String[]) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -94,6 +95,13 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="org.apache.commons.lang.exception.ExceptionUtils java.lang.Throwable getCauseUsingFieldName(java.lang.Throwable, java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="org.apache.commons.lang.exception.ExceptionUtils java.lang.Throwable getCauseUsingMethodName(java.lang.Throwable, java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.exception.ExceptionUtils java.lang.Throwable getCauseUsingWellKnownTypes(java.lang.Throwable) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -102,10 +110,14 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.exception.ExceptionUtils java.lang.Throwable getRootCause(java.lang.Throwable) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.commons.lang.exception.ExceptionUtils java.lang.Throwable getRootCause(java.lang.Throwable)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.exception.ExceptionUtils java.lang.Throwable[] getThrowables(java.lang.Throwable) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -153,4 +165,13 @@
<item name="org.apache.commons.lang.exception.NestableDelegate void trimStackFrames(java.util.List) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.commons.lang.exception.NestableError java.lang.String getMessage()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="org.apache.commons.lang.exception.NestableException java.lang.String getMessage()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="org.apache.commons.lang.exception.NestableRuntimeException java.lang.String getMessage()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
</root>
diff --git a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/lang/math/annotations.xml b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/lang/math/annotations.xml
index 567cb620681f..d0657899989a 100644
--- a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/lang/math/annotations.xml
+++ b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/lang/math/annotations.xml
@@ -302,6 +302,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null-&gt;!null;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.math.NumberUtils java.lang.Float createFloat(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -310,6 +311,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null-&gt;!null;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.math.NumberUtils java.lang.Integer createInteger(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -318,6 +320,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null-&gt;!null;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.math.NumberUtils java.lang.Long createLong(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -326,6 +329,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null-&gt;!null;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.math.NumberUtils java.lang.Number createNumber(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -334,6 +338,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.math.NumberUtils java.math.BigDecimal createBigDecimal(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -342,6 +347,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null-&gt;!null;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.math.NumberUtils java.math.BigInteger createBigInteger(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -350,6 +356,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null-&gt;!null;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.math.NumberUtils long max(long[]) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
diff --git a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/lang/text/annotations.xml b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/lang/text/annotations.xml
index 0e46f59ecbed..044b34e70faf 100644
--- a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/lang/text/annotations.xml
+++ b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/lang/text/annotations.xml
@@ -37,11 +37,13 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;_,_,!null,_-&gt;!null;_,_,null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.text.ExtendedMessageFormat java.text.Format getFormat(java.lang.String)">
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.text.ExtendedMessageFormat java.text.ParsePosition next(java.text.ParsePosition) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
@@ -422,6 +424,9 @@
<item name="org.apache.commons.lang.text.StrLookup org.apache.commons.lang.text.StrLookup mapLookup(java.util.Map)">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.commons.lang.text.StrLookup.MapStrLookup java.lang.String lookup(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.text.StrMatcher int isMatch(char[], int) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -503,6 +508,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.text.StrSubstitutor java.lang.String replace(char[], int, int) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -511,6 +517,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.text.StrSubstitutor java.lang.String replace(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -519,6 +526,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.text.StrSubstitutor java.lang.String replace(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -527,6 +535,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.text.StrSubstitutor java.lang.String replace(java.lang.String, int, int) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -535,6 +544,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.text.StrSubstitutor java.lang.String replace(java.lang.StringBuffer) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -543,6 +553,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.text.StrSubstitutor java.lang.String replace(java.lang.StringBuffer, int, int) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -551,6 +562,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.text.StrSubstitutor java.lang.String replace(org.apache.commons.lang.text.StrBuilder) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -559,6 +571,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.text.StrSubstitutor java.lang.String replace(org.apache.commons.lang.text.StrBuilder, int, int) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -567,10 +580,14 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.text.StrSubstitutor java.lang.String resolveVariable(java.lang.String, org.apache.commons.lang.text.StrBuilder, int, int) 1">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.commons.lang.text.StrSubstitutor java.lang.String resolveVariable(java.lang.String, org.apache.commons.lang.text.StrBuilder, int, int)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.text.StrSubstitutor org.apache.commons.lang.text.StrSubstitutor setVariablePrefix(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -613,6 +630,18 @@
<item name="org.apache.commons.lang.text.StrTokenizer int readWithQuotes(char[], int, int, org.apache.commons.lang.text.StrBuilder, java.util.List, int, int) 3">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.commons.lang.text.StrTokenizer java.lang.Object clone()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="org.apache.commons.lang.text.StrTokenizer java.lang.String getContent()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="org.apache.commons.lang.text.StrTokenizer java.lang.String nextToken()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="org.apache.commons.lang.text.StrTokenizer java.lang.String previousToken()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.text.StrTokenizer java.lang.String toString()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
diff --git a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/lang/time/annotations.xml b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/lang/time/annotations.xml
index 12183165228a..fbd05e4e413c 100644
--- a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/lang/time/annotations.xml
+++ b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/commons/lang/time/annotations.xml
@@ -373,6 +373,9 @@
<val val="&quot;null-&gt;false&quot;"/>
</annotation>
</item>
+ <item name="org.apache.commons.lang.time.DurationFormatUtils.Token java.lang.String toString()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.commons.lang.time.FastDateFormat FastDateFormat(java.lang.String, java.util.TimeZone, java.util.Locale) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -400,6 +403,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null,_-&gt;null;_,!null-&gt;null;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.commons.lang.time.FastDateFormat java.lang.String format(java.util.Calendar)">
<annotation name="org.jetbrains.annotations.NotNull"/>
diff --git a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/annotations.xml b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/annotations.xml
index 7ef87f095569..ae835d69fbff 100644
--- a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/annotations.xml
+++ b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/annotations.xml
@@ -5,4 +5,7 @@
<item name="org.apache.velocity.VelocityContext VelocityContext(java.util.Map, org.apache.velocity.context.Context) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.velocity.VelocityContext java.lang.Object clone()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
</root>
diff --git a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/app/annotations.xml b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/app/annotations.xml
index fac918657687..ee0af29aafee 100644
--- a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/app/annotations.xml
+++ b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/app/annotations.xml
@@ -1,4 +1,7 @@
<root>
+ <item name="org.apache.velocity.app.FieldMethodizer java.lang.Object get(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.app.FieldMethodizer void addObject(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
diff --git a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/app/event/annotations.xml b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/app/event/annotations.xml
index d1987cbafc38..6d0bbb6d0226 100644
--- a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/app/event/annotations.xml
+++ b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/app/event/annotations.xml
@@ -23,6 +23,9 @@
<val val="&quot;null-&gt;false&quot;"/>
</annotation>
</item>
+ <item name="org.apache.velocity.app.event.EventCartridge java.util.Iterator getReferenceInsertionEventHandlers()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.app.event.EventHandlerUtil boolean shouldLogOnNullSet(org.apache.velocity.runtime.RuntimeServices, org.apache.velocity.context.InternalContextAdapter, java.lang.String, java.lang.String) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -95,6 +98,9 @@
<item name="org.apache.velocity.app.event.InvalidReferenceEventHandler.InvalidMethodExecutor void execute(org.apache.velocity.app.event.EventHandler) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.velocity.app.event.InvalidReferenceEventHandler.InvalidSetMethodExecutor java.lang.Object getReturnValue()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.app.event.InvalidReferenceEventHandler.InvalidSetMethodExecutor void execute(org.apache.velocity.app.event.EventHandler) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
diff --git a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/app/event/implement/annotations.xml b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/app/event/implement/annotations.xml
index 643ea130fd54..28deac2b6343 100644
--- a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/app/event/implement/annotations.xml
+++ b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/app/event/implement/annotations.xml
@@ -2,12 +2,18 @@
<item name="org.apache.velocity.app.event.implement.EscapeHtmlReference java.lang.String escape(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.velocity.app.event.implement.EscapeHtmlReference java.lang.String escape(java.lang.Object)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.app.event.implement.EscapeHtmlReference java.lang.String getMatchAttribute()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
<item name="org.apache.velocity.app.event.implement.EscapeJavaScriptReference java.lang.String escape(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.velocity.app.event.implement.EscapeJavaScriptReference java.lang.String escape(java.lang.Object)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.app.event.implement.EscapeJavaScriptReference java.lang.String getMatchAttribute()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -22,12 +28,18 @@
<item name="org.apache.velocity.app.event.implement.EscapeSqlReference java.lang.String escape(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.velocity.app.event.implement.EscapeSqlReference java.lang.String escape(java.lang.Object)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.app.event.implement.EscapeSqlReference java.lang.String getMatchAttribute()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
<item name="org.apache.velocity.app.event.implement.EscapeXmlReference java.lang.String escape(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.velocity.app.event.implement.EscapeXmlReference java.lang.String escape(java.lang.Object)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.app.event.implement.EscapeXmlReference java.lang.String getMatchAttribute()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -37,6 +49,9 @@
<item name="org.apache.velocity.app.event.implement.IncludeNotFound java.lang.String includeEvent(java.lang.String, java.lang.String, java.lang.String) 2">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.velocity.app.event.implement.IncludeNotFound java.lang.String includeEvent(java.lang.String, java.lang.String, java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.app.event.implement.IncludeNotFound void setRuntimeServices(org.apache.velocity.runtime.RuntimeServices) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -102,6 +117,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null,_,_,_,_-&gt;null;_,!null,_,_,_-&gt;null;_,_,!null,_,_-&gt;null;_,_,_,!null,_-&gt;null;_,_,_,_,!null-&gt;null;_,_,_,_,null-&gt;null;_,_,_,null,_-&gt;null;_,_,null,_,_-&gt;null;_,null,_,_,_-&gt;null;null,_,_,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.velocity.app.event.implement.ReportInvalidReferences java.lang.Object invalidMethod(org.apache.velocity.context.Context, java.lang.String, java.lang.Object, java.lang.String, org.apache.velocity.util.introspection.Info) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -119,6 +135,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null,_,_,_,_-&gt;null;_,!null,_,_,_-&gt;null;_,_,!null,_,_-&gt;null;_,_,_,!null,_-&gt;null;_,_,_,_,!null-&gt;null;_,_,_,_,null-&gt;null;_,_,_,null,_-&gt;null;_,_,null,_,_-&gt;null;_,null,_,_,_-&gt;null;null,_,_,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.velocity.app.event.implement.ReportInvalidReferences void reportInvalidReference(java.lang.String, org.apache.velocity.util.introspection.Info) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
diff --git a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/context/annotations.xml b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/context/annotations.xml
index 62279b8f44db..7952023d2550 100644
--- a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/context/annotations.xml
+++ b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/context/annotations.xml
@@ -14,6 +14,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.velocity.context.AbstractContext java.lang.Object put(java.lang.String, java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -22,6 +23,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.velocity.context.AbstractContext java.lang.Object remove(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -30,6 +32,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.velocity.context.EvaluateContext EvaluateContext(org.apache.velocity.context.InternalContextAdapter, org.apache.velocity.runtime.RuntimeServices) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
@@ -37,12 +40,21 @@
<item name="org.apache.velocity.context.EvaluateContext void initContext(org.apache.velocity.runtime.RuntimeServices) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.velocity.context.InternalContextAdapterImpl org.apache.velocity.app.event.EventCartridge attachEventCartridge(org.apache.velocity.app.event.EventCartridge)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="org.apache.velocity.context.InternalContextAdapterImpl org.apache.velocity.app.event.EventCartridge getEventCartridge()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.context.InternalContextAdapterImpl org.apache.velocity.context.InternalContextAdapter getBaseContext()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
<item name="org.apache.velocity.context.ProxyVMContext boolean isConstant(org.apache.velocity.runtime.parser.node.Node) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.velocity.context.ProxyVMContext java.lang.Object remove(java.lang.Object)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.context.ProxyVMContext void addVMProxyArg(org.apache.velocity.context.InternalContextAdapter, java.lang.String, java.lang.String, org.apache.velocity.runtime.Renderable) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
diff --git a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/io/annotations.xml b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/io/annotations.xml
index f55b4257f29a..003fd3e71e3d 100644
--- a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/io/annotations.xml
+++ b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/io/annotations.xml
@@ -1,4 +1,7 @@
<root>
+ <item name="org.apache.velocity.io.UnicodeInputStream java.lang.String readEncoding()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.io.UnicodeInputStream org.apache.velocity.io.UnicodeInputStream.UnicodeBOM match(org.apache.velocity.io.UnicodeInputStream.UnicodeBOM, org.apache.velocity.io.UnicodeInputStream.UnicodeBOM) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
diff --git a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/runtime/annotations.xml b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/runtime/annotations.xml
index 1dd01a70efdd..20fa8692e567 100644
--- a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/runtime/annotations.xml
+++ b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/runtime/annotations.xml
@@ -31,6 +31,12 @@
<val val="&quot;!null,_,_,_-&gt;true;_,!null,_,_-&gt;true;_,_,!null,_-&gt;true;_,_,_,!null-&gt;true;_,_,_,null-&gt;true;_,_,null,_-&gt;true;_,null,_,_-&gt;true;null,_,_,_-&gt;true&quot;"/>
</annotation>
</item>
+ <item name="org.apache.velocity.runtime.RuntimeInstance java.lang.Object getProperty(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="org.apache.velocity.runtime.RuntimeInstance java.lang.String getString(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.runtime.RuntimeInstance org.apache.velocity.app.event.EventHandler initializeSpecificEventHandler(java.lang.String, java.lang.String, java.lang.Class) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -41,6 +47,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;_,_,null-&gt;null;null,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.velocity.runtime.RuntimeInstance org.apache.velocity.runtime.parser.Parser createNewParser()">
<annotation name="org.jetbrains.annotations.NotNull"/>
@@ -101,9 +108,24 @@
<item name="org.apache.velocity.runtime.VelocimacroManager boolean usingNamespaces(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.velocity.runtime.VelocimacroManager java.lang.String getLibraryName(java.lang.String, java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="org.apache.velocity.runtime.VelocimacroManager java.util.Map addNamespace(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="org.apache.velocity.runtime.VelocimacroManager java.util.Map getNamespace(java.lang.String, boolean)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="org.apache.velocity.runtime.VelocimacroManager org.apache.velocity.runtime.directive.VelocimacroProxy get(java.lang.String, java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.runtime.VelocimacroManager org.apache.velocity.runtime.directive.VelocimacroProxy get(java.lang.String, java.lang.String, java.lang.String) 2">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.velocity.runtime.VelocimacroManager org.apache.velocity.runtime.directive.VelocimacroProxy get(java.lang.String, java.lang.String, java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.runtime.VelocimacroManager.MacroEntry MacroEntry(java.lang.String, org.apache.velocity.runtime.parser.node.Node, java.lang.String[], java.lang.String, org.apache.velocity.runtime.RuntimeServices) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
diff --git a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/runtime/directive/annotations.xml b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/runtime/directive/annotations.xml
index e9d35d5e61e8..e3142ca5a771 100644
--- a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/runtime/directive/annotations.xml
+++ b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/runtime/directive/annotations.xml
@@ -11,6 +11,9 @@
<item name="org.apache.velocity.runtime.directive.Block void init(org.apache.velocity.runtime.RuntimeServices, org.apache.velocity.context.InternalContextAdapter, org.apache.velocity.runtime.parser.node.Node) 2">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.velocity.runtime.directive.Block.Reference java.lang.String toString()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.runtime.directive.BlockMacro void init(org.apache.velocity.runtime.RuntimeServices, org.apache.velocity.context.InternalContextAdapter, org.apache.velocity.runtime.parser.node.Node) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -128,6 +131,9 @@
<item name="org.apache.velocity.runtime.directive.Foreach.NullHolderContext NullHolderContext(java.lang.String, org.apache.velocity.context.InternalContextAdapter, org.apache.velocity.runtime.directive.Foreach.1) 2">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.velocity.runtime.directive.Foreach.NullHolderContext java.lang.Object get(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.runtime.directive.ForeachScope ForeachScope(java.lang.Object, java.lang.Object) 1">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -258,6 +264,15 @@
<item name="org.apache.velocity.runtime.directive.Scope.Info Info(org.apache.velocity.runtime.directive.Scope, java.lang.Object) 1">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.velocity.runtime.directive.Scope.Info java.lang.String getName()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="org.apache.velocity.runtime.directive.Scope.Info java.lang.String getTemplate()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="org.apache.velocity.runtime.directive.Scope.Info java.lang.String getType()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.runtime.directive.Scope.Info java.lang.String toString()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
diff --git a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/runtime/parser/node/annotations.xml b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/runtime/parser/node/annotations.xml
index b6a2face76a9..d10a46a0230e 100644
--- a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/runtime/parser/node/annotations.xml
+++ b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/runtime/parser/node/annotations.xml
@@ -14,6 +14,9 @@
<item name="org.apache.velocity.runtime.parser.node.ASTAddNode java.lang.Object handleSpecial(java.lang.Object, java.lang.Object, org.apache.velocity.context.InternalContextAdapter) 2">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.velocity.runtime.parser.node.ASTAddNode java.lang.Object handleSpecial(java.lang.Object, java.lang.Object, org.apache.velocity.context.InternalContextAdapter)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.runtime.parser.node.ASTAndNode java.lang.Object jjtAccept(org.apache.velocity.runtime.parser.node.ParserVisitor, java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -66,6 +69,9 @@
<item name="org.apache.velocity.runtime.parser.node.ASTDivNode java.lang.Number perform(java.lang.Number, java.lang.Number, org.apache.velocity.context.InternalContextAdapter) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.velocity.runtime.parser.node.ASTDivNode java.lang.Number perform(java.lang.Number, java.lang.Number, org.apache.velocity.context.InternalContextAdapter)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.runtime.parser.node.ASTEQNode java.lang.Object jjtAccept(org.apache.velocity.runtime.parser.node.ParserVisitor, java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -156,6 +162,9 @@
<item name="org.apache.velocity.runtime.parser.node.ASTIdentifier java.lang.Object execute(java.lang.Object, org.apache.velocity.context.InternalContextAdapter) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.velocity.runtime.parser.node.ASTIdentifier java.lang.Object execute(java.lang.Object, org.apache.velocity.context.InternalContextAdapter)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.runtime.parser.node.ASTIdentifier java.lang.Object init(org.apache.velocity.context.InternalContextAdapter, java.lang.Object)">
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;_,!null-&gt;!null;_,null-&gt;null&quot;"/>
@@ -189,6 +198,9 @@
<item name="org.apache.velocity.runtime.parser.node.ASTIndex java.lang.Object execute(java.lang.Object, org.apache.velocity.context.InternalContextAdapter) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.velocity.runtime.parser.node.ASTIndex java.lang.Object execute(java.lang.Object, org.apache.velocity.context.InternalContextAdapter)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.runtime.parser.node.ASTIndex java.lang.Object init(org.apache.velocity.context.InternalContextAdapter, java.lang.Object)">
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;_,!null-&gt;!null;_,null-&gt;null&quot;"/>
@@ -208,6 +220,9 @@
<item name="org.apache.velocity.runtime.parser.node.ASTIntegerRange java.lang.Object jjtAccept(org.apache.velocity.runtime.parser.node.ParserVisitor, java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.velocity.runtime.parser.node.ASTIntegerRange java.lang.Object value(org.apache.velocity.context.InternalContextAdapter)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.runtime.parser.node.ASTLENode java.lang.Object jjtAccept(org.apache.velocity.runtime.parser.node.ParserVisitor, java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -230,6 +245,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null,_,_-&gt;null;_,!null,_-&gt;null;_,_,!null-&gt;null;_,_,null-&gt;null;_,null,_-&gt;null;null,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.velocity.runtime.parser.node.ASTMathNode java.lang.Object init(org.apache.velocity.context.InternalContextAdapter, java.lang.Object)">
<annotation name="org.jetbrains.annotations.Contract">
@@ -239,9 +255,15 @@
<item name="org.apache.velocity.runtime.parser.node.ASTMathNode java.lang.Object jjtAccept(org.apache.velocity.runtime.parser.node.ParserVisitor, java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.velocity.runtime.parser.node.ASTMathNode java.lang.Object value(org.apache.velocity.context.InternalContextAdapter)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.runtime.parser.node.ASTMethod java.lang.Object execute(java.lang.Object, org.apache.velocity.context.InternalContextAdapter) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.velocity.runtime.parser.node.ASTMethod java.lang.Object execute(java.lang.Object, org.apache.velocity.context.InternalContextAdapter)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.runtime.parser.node.ASTMethod java.lang.Object handleInvocationException(java.lang.Object, org.apache.velocity.context.InternalContextAdapter, java.lang.Throwable) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -276,6 +298,9 @@
<item name="org.apache.velocity.runtime.parser.node.ASTModNode java.lang.Number perform(java.lang.Number, java.lang.Number, org.apache.velocity.context.InternalContextAdapter) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.velocity.runtime.parser.node.ASTModNode java.lang.Number perform(java.lang.Number, java.lang.Number, org.apache.velocity.context.InternalContextAdapter)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.runtime.parser.node.ASTMulNode java.lang.Number perform(java.lang.Number, java.lang.Number, org.apache.velocity.context.InternalContextAdapter) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -308,6 +333,9 @@
<item name="org.apache.velocity.runtime.parser.node.ASTReference java.lang.Object execute(java.lang.Object, org.apache.velocity.context.InternalContextAdapter) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.velocity.runtime.parser.node.ASTReference java.lang.Object execute(java.lang.Object, org.apache.velocity.context.InternalContextAdapter)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.runtime.parser.node.ASTReference java.lang.Object getVariableValue(org.apache.velocity.context.Context, java.lang.String) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -319,6 +347,9 @@
<item name="org.apache.velocity.runtime.parser.node.ASTReference java.lang.Object jjtAccept(org.apache.velocity.runtime.parser.node.ParserVisitor, java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.velocity.runtime.parser.node.ASTReference java.lang.Object value(org.apache.velocity.context.InternalContextAdapter)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.runtime.parser.node.ASTReference java.lang.String getDollarBang()">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -452,6 +483,9 @@
<item name="org.apache.velocity.runtime.parser.node.GetExecutor GetExecutor(org.apache.velocity.runtime.log.Log, org.apache.velocity.util.introspection.Introspector, java.lang.Class, java.lang.String) 3">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.velocity.runtime.parser.node.GetExecutor java.lang.Object execute(java.lang.Object)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.runtime.parser.node.MapGetExecutor java.lang.Object execute(java.lang.Object) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -541,9 +575,18 @@
<item name="org.apache.velocity.runtime.parser.node.PropertyExecutor PropertyExecutor(org.apache.velocity.runtime.RuntimeLogger, org.apache.velocity.util.introspection.Introspector, java.lang.Class, java.lang.String) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.velocity.runtime.parser.node.PropertyExecutor java.lang.Object execute(java.lang.Object)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.runtime.parser.node.PropertyExecutor void discover(java.lang.Class, java.lang.String) 1">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.velocity.runtime.parser.node.PutExecutor java.lang.Object execute(java.lang.Object, java.lang.Object)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="org.apache.velocity.runtime.parser.node.SetPropertyExecutor java.lang.Object execute(java.lang.Object, java.lang.Object)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.runtime.parser.node.SimpleNode boolean evaluate(org.apache.velocity.context.InternalContextAdapter) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -572,6 +615,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null,_-&gt;null;_,!null-&gt;null;_,null-&gt;null;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.velocity.runtime.parser.node.SimpleNode java.lang.Object init(org.apache.velocity.context.InternalContextAdapter, java.lang.Object)">
<annotation name="org.jetbrains.annotations.Contract">
@@ -588,6 +632,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null-&gt;null;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.velocity.runtime.parser.node.SimpleNode java.lang.String getLocation(org.apache.velocity.context.InternalContextAdapter) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
diff --git a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/runtime/resource/annotations.xml b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/runtime/resource/annotations.xml
index 6d9f27bfe3ff..cbc6c2b8383a 100644
--- a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/runtime/resource/annotations.xml
+++ b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/runtime/resource/annotations.xml
@@ -2,10 +2,22 @@
<item name="org.apache.velocity.runtime.resource.ResourceFactory org.apache.velocity.runtime.resource.Resource getResource(java.lang.String, int) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.velocity.runtime.resource.ResourceFactory org.apache.velocity.runtime.resource.Resource getResource(java.lang.String, int)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="org.apache.velocity.runtime.resource.ResourceManagerImpl java.lang.String getLoaderNameForResource(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.runtime.resource.ResourceManagerImpl org.apache.velocity.runtime.resource.Resource createResource(java.lang.String, int) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.velocity.runtime.resource.ResourceManagerImpl org.apache.velocity.runtime.resource.Resource createResource(java.lang.String, int)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.runtime.resource.ResourceManagerImpl org.apache.velocity.runtime.resource.Resource refreshResource(org.apache.velocity.runtime.resource.Resource, java.lang.String) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.velocity.runtime.resource.ResourceManagerImpl org.apache.velocity.runtime.resource.loader.ResourceLoader getLoaderForResource(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
</root>
diff --git a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/runtime/resource/loader/annotations.xml b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/runtime/resource/loader/annotations.xml
index ca5b1efb729c..315bc40466a1 100644
--- a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/runtime/resource/loader/annotations.xml
+++ b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/runtime/resource/loader/annotations.xml
@@ -72,6 +72,9 @@
<item name="org.apache.velocity.runtime.resource.loader.FileResourceLoader java.io.InputStream findTemplate(java.lang.String, java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.velocity.runtime.resource.loader.FileResourceLoader java.io.InputStream findTemplate(java.lang.String, java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.runtime.resource.loader.FileResourceLoader java.io.InputStream getResourceStream(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -87,6 +90,9 @@
<item name="org.apache.velocity.runtime.resource.loader.JarHolder JarHolder(org.apache.velocity.runtime.RuntimeServices, java.lang.String) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.velocity.runtime.resource.loader.JarHolder java.io.InputStream getResource(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.runtime.resource.loader.JarResourceLoader boolean isSourceModified(org.apache.velocity.runtime.resource.Resource) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
diff --git a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/util/annotations.xml b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/util/annotations.xml
index 8b1334446ad3..7bcfa1afe805 100644
--- a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/util/annotations.xml
+++ b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/util/annotations.xml
@@ -5,14 +5,23 @@
<item name="org.apache.velocity.util.ClassUtils java.io.InputStream getResourceAsStream(java.lang.Class, java.lang.String) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.velocity.util.ClassUtils java.lang.Object getNewInstance(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.util.ClassUtils org.apache.velocity.util.introspection.VelMethod getMethod(java.lang.String, java.lang.Object[], java.lang.Class[], java.lang.Object, org.apache.velocity.context.InternalContextAdapter, org.apache.velocity.runtime.parser.node.SimpleNode, boolean) 4">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.velocity.util.ClassUtils org.apache.velocity.util.introspection.VelMethod getMethod(java.lang.String, java.lang.Object[], java.lang.Class[], java.lang.Object, org.apache.velocity.context.InternalContextAdapter, org.apache.velocity.runtime.parser.node.SimpleNode, boolean)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.util.ExceptionUtils java.lang.Throwable createWithCause(java.lang.Class, java.lang.String, java.lang.Throwable)">
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_,_-&gt;null&quot;"/>
</annotation>
</item>
+ <item name="org.apache.velocity.util.SimplePool java.lang.Object get()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.util.StringUtils boolean allEmpty(java.util.List) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -68,6 +77,9 @@
<item name="org.apache.velocity.util.StringUtils java.lang.String normalizePath(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.velocity.util.StringUtils java.lang.String normalizePath(java.lang.String)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.util.StringUtils java.lang.String nullTrim(java.lang.String) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -75,6 +87,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null-&gt;!null;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.velocity.util.StringUtils java.lang.String removeAndHump(java.lang.String)">
<annotation name="org.jetbrains.annotations.NotNull"/>
@@ -89,6 +102,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.velocity.util.StringUtils java.lang.String sub(java.lang.String, java.lang.String, java.lang.String) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
@@ -114,5 +128,6 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;!null-&gt;!null;null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
</root>
diff --git a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/util/introspection/annotations.xml b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/util/introspection/annotations.xml
index 4fd41ea336be..3f4478e881e8 100644
--- a/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/util/introspection/annotations.xml
+++ b/java/java-tests/testData/codeInspection/bytecodeAnalysis/annotations/org/apache/velocity/util/introspection/annotations.xml
@@ -1,7 +1,22 @@
<root>
+ <item name="org.apache.velocity.util.introspection.AbstractChainableUberspector java.util.Iterator getIterator(java.lang.Object, org.apache.velocity.util.introspection.Info)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="org.apache.velocity.util.introspection.AbstractChainableUberspector org.apache.velocity.util.introspection.VelMethod getMethod(java.lang.Object, java.lang.String, java.lang.Object[], org.apache.velocity.util.introspection.Info)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="org.apache.velocity.util.introspection.AbstractChainableUberspector org.apache.velocity.util.introspection.VelPropertyGet getPropertyGet(java.lang.Object, java.lang.String, org.apache.velocity.util.introspection.Info)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
+ <item name="org.apache.velocity.util.introspection.AbstractChainableUberspector org.apache.velocity.util.introspection.VelPropertySet getPropertySet(java.lang.Object, java.lang.String, java.lang.Object, org.apache.velocity.util.introspection.Info)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.util.introspection.ClassMap java.lang.reflect.Method findMethod(java.lang.String, java.lang.Object[]) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.velocity.util.introspection.ClassMap java.lang.reflect.Method findMethod(java.lang.String, java.lang.Object[])">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.util.introspection.ClassMap void populateMethodCacheWithInterface(org.apache.velocity.util.introspection.ClassMap.MethodCache, java.lang.Class) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -17,6 +32,9 @@
<item name="org.apache.velocity.util.introspection.ClassMap.MethodCache java.lang.reflect.Method get(java.lang.String, java.lang.Object[]) 1">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.velocity.util.introspection.ClassMap.MethodCache java.lang.reflect.Method get(java.lang.String, java.lang.Object[])">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.util.introspection.ClassMap.MethodCache void access$100(org.apache.velocity.util.introspection.ClassMap.MethodCache, java.lang.reflect.Method) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
@@ -48,6 +66,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.velocity.util.introspection.IntrospectorBase java.lang.reflect.Method getMethod(java.lang.Class, java.lang.String, java.lang.Object[]) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
@@ -86,6 +105,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;_,null-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.velocity.util.introspection.MethodMap java.lang.reflect.Method getBestMatch(java.util.List, java.lang.Class[]) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
@@ -100,6 +120,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;_,_,null-&gt;null;null,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.velocity.util.introspection.SecureUberspector java.util.Iterator getIterator(java.lang.Object, org.apache.velocity.util.introspection.Info) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -111,6 +132,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.velocity.util.introspection.UberspectImpl java.util.Iterator getIterator(java.lang.Object, org.apache.velocity.util.introspection.Info) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
@@ -118,6 +140,9 @@
<item name="org.apache.velocity.util.introspection.UberspectImpl java.util.Iterator getIterator(java.lang.Object, org.apache.velocity.util.introspection.Info) 1">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
+ <item name="org.apache.velocity.util.introspection.UberspectImpl java.util.Iterator getIterator(java.lang.Object, org.apache.velocity.util.introspection.Info)">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.util.introspection.UberspectImpl org.apache.velocity.util.introspection.VelMethod getMethod(java.lang.Object, java.lang.String, java.lang.Object[], org.apache.velocity.util.introspection.Info) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
</item>
@@ -128,6 +153,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.velocity.util.introspection.UberspectImpl org.apache.velocity.util.introspection.VelPropertyGet getPropertyGet(java.lang.Object, java.lang.String, org.apache.velocity.util.introspection.Info) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -139,6 +165,7 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.velocity.util.introspection.UberspectImpl org.apache.velocity.util.introspection.VelPropertySet getPropertySet(java.lang.Object, java.lang.String, java.lang.Object, org.apache.velocity.util.introspection.Info) 0">
<annotation name="org.jetbrains.annotations.Nullable"/>
@@ -150,11 +177,18 @@
<annotation name="org.jetbrains.annotations.Contract">
<val val="&quot;null,_,_,_-&gt;null&quot;"/>
</annotation>
+ <annotation name="org.jetbrains.annotations.Nullable"/>
</item>
<item name="org.apache.velocity.util.introspection.UberspectImpl void setRuntimeLogger(org.apache.velocity.runtime.RuntimeLogger) 0">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.velocity.util.introspection.UberspectImpl.VelGetterImpl java.lang.String getMethodName()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
<item name="org.apache.velocity.util.introspection.UberspectImpl.VelMethodImpl java.lang.Object[] handleVarArg(java.lang.Class, int, java.lang.Object[]) 2">
<annotation name="org.jetbrains.annotations.NotNull"/>
</item>
+ <item name="org.apache.velocity.util.introspection.UberspectImpl.VelSetterImpl java.lang.String getMethodName()">
+ <annotation name="org.jetbrains.annotations.Nullable"/>
+ </item>
</root>
diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/RootThrowableCause.java b/java/java-tests/testData/inspection/dataFlow/fixture/RootThrowableCause.java
index 6086c92b40d4..1197fe817e8e 100644
--- a/java/java-tests/testData/inspection/dataFlow/fixture/RootThrowableCause.java
+++ b/java/java-tests/testData/inspection/dataFlow/fixture/RootThrowableCause.java
@@ -1,3 +1,6 @@
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.Nullable;
+
class Doo {
void foo(Throwable e) {
@@ -9,4 +12,18 @@ class Doo {
}
}
+}
+
+abstract class Test04 {
+ @Nullable
+ @Contract(pure = true)
+ abstract Test04 getParent();
+
+ Test04 getTopParent() {
+ Test04 top = this;
+ while (top.getParent() != null) {
+ top = top.getParent();
+ }
+ return top;
+ }
} \ No newline at end of file
diff --git a/java/java-tests/testData/refactoring/extractMethodObject4Debugger/AnonymousClassParams.java b/java/java-tests/testData/refactoring/extractMethodObject4Debugger/AnonymousClassParams.java
new file mode 100644
index 000000000000..3a722d36aeea
--- /dev/null
+++ b/java/java-tests/testData/refactoring/extractMethodObject4Debugger/AnonymousClassParams.java
@@ -0,0 +1,8 @@
+interface I {
+ void foo(int i) {}
+}
+class Sample {
+ void foo() {
+ System.out.println("hello <caret>world");
+ }
+} \ No newline at end of file
diff --git a/java/java-tests/testData/refactoring/extractMethodObject4Debugger/InnerClass.java b/java/java-tests/testData/refactoring/extractMethodObject4Debugger/InnerClass.java
new file mode 100644
index 000000000000..448724bf0543
--- /dev/null
+++ b/java/java-tests/testData/refactoring/extractMethodObject4Debugger/InnerClass.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+class Sample {
+
+ void a() {
+ System.out.println("<caret>");
+ }
+
+ class I {
+ public I(int i) {
+ }
+
+ void foo() {
+ bar();
+ }
+ }
+}
diff --git a/java/java-tests/testData/refactoring/extractMethodObject4Debugger/InvokeReturnType.java b/java/java-tests/testData/refactoring/extractMethodObject4Debugger/InvokeReturnType.java
new file mode 100644
index 000000000000..353941357c68
--- /dev/null
+++ b/java/java-tests/testData/refactoring/extractMethodObject4Debugger/InvokeReturnType.java
@@ -0,0 +1,9 @@
+package my;
+
+class Sample {
+ static void foo() {
+ int x =5;
+ int y =5;
+ int <caret>z =5;
+ }
+} \ No newline at end of file
diff --git a/java/java-tests/testData/refactoring/extractMethodObject4Debugger/OffsetsAtCallSite.java b/java/java-tests/testData/refactoring/extractMethodObject4Debugger/OffsetsAtCallSite.java
new file mode 100644
index 000000000000..353564c51240
--- /dev/null
+++ b/java/java-tests/testData/refactoring/extractMethodObject4Debugger/OffsetsAtCallSite.java
@@ -0,0 +1,44 @@
+package my;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+class Java8Private {
+ public static void main(String[] args) {
+ new Java8Private().foo();
+ }
+
+ private void foo() {
+ final Map<Integer,Integer> map = new HashMap<Integer,Integer>();
+ map.put(1, 2);
+ //evaluate here map.entrySet().stream().filter((a) -> (a.getKey()>0));
+ <caret>new Inner(map).invoke();
+ map.put(3, 5);
+ }
+
+ private void zoo(int a) {
+ System.out.println("DONE " + a);
+ }
+
+
+ public class Inner extends MagicAccessorBridge {
+ final Map<Integer,Integer> map;
+
+ public Inner(Map<Integer, Integer> map) {
+ this.map = map;
+ }
+
+ void invoke() {
+ map.entrySet().stream().forEach((a) -> accessorZoo(Java8Private.this, a.getValue()));
+ }
+
+ // accessor
+ void accessorZoo(Java8Private obj, int a) {
+ obj.zoo(a);
+ }
+ }
+}
+
+class MagicAccessorBridge {
+} \ No newline at end of file
diff --git a/java/java-tests/testData/refactoring/extractMethodObject4Debugger/ResultExpr.java b/java/java-tests/testData/refactoring/extractMethodObject4Debugger/ResultExpr.java
new file mode 100644
index 000000000000..7a83d4c57bf3
--- /dev/null
+++ b/java/java-tests/testData/refactoring/extractMethodObject4Debugger/ResultExpr.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+class Sample {
+
+ void a() {
+ System.out.println("<caret>");
+ }
+
+ private int foo() {
+ return 1;
+ }
+}
diff --git a/java/java-tests/testData/refactoring/extractMethodObject4Debugger/ResultStatements.java b/java/java-tests/testData/refactoring/extractMethodObject4Debugger/ResultStatements.java
new file mode 100644
index 000000000000..20d69ea477b4
--- /dev/null
+++ b/java/java-tests/testData/refactoring/extractMethodObject4Debugger/ResultStatements.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+class Sample {
+
+ void a() {
+ System.out.println("<caret>");
+ }
+
+ int foo() {
+ return 1;
+ }
+}
diff --git a/java/java-tests/testData/refactoring/extractMethodObject4Debugger/SimpleGeneration.java b/java/java-tests/testData/refactoring/extractMethodObject4Debugger/SimpleGeneration.java
new file mode 100644
index 000000000000..873f2205e1af
--- /dev/null
+++ b/java/java-tests/testData/refactoring/extractMethodObject4Debugger/SimpleGeneration.java
@@ -0,0 +1,5 @@
+class Sample {
+ void foo() {
+ System.out.println("hello <caret>world");
+ }
+} \ No newline at end of file
diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartType18CompletionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartType18CompletionTest.java
index eb3c4c4577b6..68aba5eca978 100644
--- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartType18CompletionTest.java
+++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartType18CompletionTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,9 +17,6 @@ package com.intellij.codeInsight.completion;
import com.intellij.JavaTestUtil;
import com.intellij.codeInsight.lookup.Lookup;
-import com.intellij.psi.JavaPsiFacade;
-import com.intellij.psi.impl.source.resolve.PsiResolveHelperImpl;
-import com.intellij.psi.impl.source.resolve.graphInference.PsiGraphInferenceHelper;
import com.intellij.testFramework.LightProjectDescriptor;
import org.jetbrains.annotations.NotNull;
@@ -117,16 +114,9 @@ public class SmartType18CompletionTest extends LightFixtureCompletionTestCase {
}
public void testInferFromRawType() throws Exception {
- final PsiResolveHelperImpl helper = (PsiResolveHelperImpl)JavaPsiFacade.getInstance(getProject()).getResolveHelper();
- helper.setTestHelper(new PsiGraphInferenceHelper(getPsiManager()));
- try {
- configureByFile("/" + getTestName(false) + ".java");
- assertNotNull(myItems);
- assertTrue(myItems.length == 0);
- }
- finally {
- helper.setTestHelper(null);
- }
+ configureByFile("/" + getTestName(false) + ".java");
+ assertNotNull(myItems);
+ assertTrue(myItems.length == 0);
}
public void testDiamondsInsideMethodCall() throws Exception {
diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java
index 967de28820e8..2db5b7fbbfea 100644
--- a/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java
+++ b/java/java-tests/testSrc/com/intellij/codeInsight/completion/SmartTypeCompletionTest.java
@@ -701,6 +701,8 @@ public class SmartTypeCompletionTest extends LightFixtureCompletionTestCase {
doTest();
}
+ public void testNoSemicolonInsideParentheses() { doTest(); }
+
public void testAssignFromTheSameFieldOfAnotherObject() throws Throwable {
doTest();
}
diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java
index 09225b64bc1d..ac57a71e9c9f 100644
--- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java
+++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java
@@ -372,6 +372,9 @@ public class GenericsHighlightingTest extends LightDaemonAnalyzerTestCase {
public void testIDEA126633() { doTest(LanguageLevel.JDK_1_7, JavaSdkVersion.JDK_1_7, false); }
public void testIDEA124363() { doTest(LanguageLevel.JDK_1_7, JavaSdkVersion.JDK_1_7, false); }
public void testIDEA78402() { doTest(LanguageLevel.JDK_1_7, JavaSdkVersion.JDK_1_7, false); }
+ public void testIDEA106985() { doTest(LanguageLevel.JDK_1_7, JavaSdkVersion.JDK_1_7, false); }
+ public void testIDEA114797() { doTest(LanguageLevel.JDK_1_7, JavaSdkVersion.JDK_1_7, false); }
+ public void testCaptureWildcardFromUnboundCaptureWildcard() { doTest(LanguageLevel.JDK_1_7, JavaSdkVersion.JDK_1_7, false); }
public void testSuperCaptureSubstitutionWhenTypeParameterHasUpperBounds() { doTest(LanguageLevel.JDK_1_7, JavaSdkVersion.JDK_1_7, false); }
public void testParameterBoundsWithCapturedWildcard() { doTest(LanguageLevel.JDK_1_7, JavaSdkVersion.JDK_1_7, false); }
//jdk should propagate LL 1.4 but actually it provides LL 1.7?!
diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/ConstraintsInferenceMiscTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/ConstraintsInferenceMiscTest.java
index 42433d327e2d..08857080b060 100644
--- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/ConstraintsInferenceMiscTest.java
+++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/ConstraintsInferenceMiscTest.java
@@ -54,8 +54,12 @@ public class ConstraintsInferenceMiscTest extends LightDaemonAnalyzerTestCase {
doTest(false);
}
+ public void testIntersectionTypeStrictSubtypingConstraint() throws Exception {
+ doTest(false);
+ }
+
private void doTest(final boolean checkWarnings) {
- doTestNewInference(BASE_PATH + "/" + getTestName(false) + ".java", checkWarnings, false);
+ doTest(BASE_PATH + "/" + getTestName(false) + ".java", checkWarnings, false);
}
@Override
diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/Diamond8HighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/Diamond8HighlightingTest.java
index eb73906a5f15..62c96e148ea1 100644
--- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/Diamond8HighlightingTest.java
+++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/Diamond8HighlightingTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -36,7 +36,7 @@ public class Diamond8HighlightingTest extends LightDaemonAnalyzerTestCase {
}
private void doTest() throws Exception {
- doTestNewInference(BASE_PATH + "/" + getTestName(false) + ".java", false, false);
+ doTest(BASE_PATH + "/" + getTestName(false) + ".java", false, false);
}
@Override
diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/ExceptionVariablesInferenceTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/ExceptionVariablesInferenceTest.java
index 0384c0f074db..c55c6ae2e775 100644
--- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/ExceptionVariablesInferenceTest.java
+++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/ExceptionVariablesInferenceTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -54,6 +54,6 @@ public class ExceptionVariablesInferenceTest extends LightDaemonAnalyzerTestCase
}
private void doTest(final boolean checkWarnings) throws Exception {
- doTestNewInference(BASE_PATH + "/" + getTestName(false) + ".java", checkWarnings, false);
+ doTest(BASE_PATH + "/" + getTestName(false) + ".java", checkWarnings, false);
}
}
diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/FunctionalExpressionIncompleteHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/FunctionalExpressionIncompleteHighlightingTest.java
index e47f6acc9afc..5e34b963e321 100644
--- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/FunctionalExpressionIncompleteHighlightingTest.java
+++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/FunctionalExpressionIncompleteHighlightingTest.java
@@ -47,7 +47,7 @@ public class FunctionalExpressionIncompleteHighlightingTest extends LightDaemonA
}
private void doTest(final boolean checkWarnings) {
- doTestNewInference(BASE_PATH + "/" + getTestName(false) + ".java", checkWarnings, false);
+ doTest(BASE_PATH + "/" + getTestName(false) + ".java", checkWarnings, false);
}
@Override
diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/FunctionalTypeWildcardParameterizationTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/FunctionalTypeWildcardParameterizationTest.java
index 599ae74cd00d..72f709a48697 100644
--- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/FunctionalTypeWildcardParameterizationTest.java
+++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/FunctionalTypeWildcardParameterizationTest.java
@@ -38,7 +38,7 @@ public class FunctionalTypeWildcardParameterizationTest extends LightDaemonAnaly
private void doTest() {
IdeaTestUtil.setTestVersion(JavaSdkVersion.JDK_1_8, getModule(), getTestRootDisposable());
- doTestNewInference(BASE_PATH + "/" + getTestName(false) + ".java", false, false);
+ doTest(BASE_PATH + "/" + getTestName(false) + ".java", false, false);
}
@Override
diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GenericsHighlighting8Test.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GenericsHighlighting8Test.java
index a66d999b283c..a919843a3164 100644
--- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GenericsHighlighting8Test.java
+++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GenericsHighlighting8Test.java
@@ -1,11 +1,11 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http:www.apache.org/licenses/LICENSE-2.0
+ * 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,
@@ -24,9 +24,6 @@ import com.intellij.openapi.projectRoots.JavaSdkVersion;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.LanguageLevelProjectExtension;
import com.intellij.pom.java.LanguageLevel;
-import com.intellij.psi.JavaPsiFacade;
-import com.intellij.psi.impl.source.resolve.PsiResolveHelperImpl;
-import com.intellij.psi.impl.source.resolve.graphInference.PsiGraphInferenceHelper;
import com.intellij.testFramework.IdeaTestUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -772,14 +769,7 @@ public class GenericsHighlighting8Test extends LightDaemonAnalyzerTestCase {
private void doTest(boolean warnings) {
LanguageLevelProjectExtension.getInstance(getJavaFacade().getProject()).setLanguageLevel(LanguageLevel.JDK_1_8);
IdeaTestUtil.setTestVersion(JavaSdkVersion.JDK_1_8, getModule(), myTestRootDisposable);
- final PsiResolveHelperImpl helper = (PsiResolveHelperImpl)JavaPsiFacade.getInstance(getProject()).getResolveHelper();
- helper.setTestHelper(new PsiGraphInferenceHelper(getPsiManager()));
- try {
- doTest(BASE_PATH + "/" + getTestName(false) + ".java", warnings, false);
- }
- finally {
- helper.setTestHelper(null);
- }
+ doTest(BASE_PATH + "/" + getTestName(false) + ".java", warnings, false);
}
diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java
index 7585d661b289..69afb0db23bb 100644
--- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java
+++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -236,13 +236,21 @@ public class GraphInferenceHighlightingTest extends LightDaemonAnalyzerTestCase
doTest();
}
+ public void testIncompatibleBoundsFromAssignment() throws Exception {
+ doTest();
+ }
+
+ public void testFreshVariablesCreatedDuringResolveDependingOnAlreadyResolvedVariables() throws Exception {
+ doTest();
+ }
+
private void doTest() throws Exception {
doTest(false);
}
private void doTest(final boolean checkWarnings) throws Exception {
IdeaTestUtil.setTestVersion(JavaSdkVersion.JDK_1_8, getModule(), getTestRootDisposable());
- doTestNewInference(BASE_PATH + "/" + getTestName(false) + ".java", checkWarnings, false);
+ doTest(BASE_PATH + "/" + getTestName(false) + ".java", checkWarnings, false);
}
@Override
diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaHighlightingTest.java
index a3a326cfcf81..5ecab96d8926 100644
--- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaHighlightingTest.java
+++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaHighlightingTest.java
@@ -112,7 +112,7 @@ public class LambdaHighlightingTest extends LightDaemonAnalyzerTestCase {
}
private void doTest(final boolean checkWarnings) {
- doTestNewInference(BASE_PATH + "/" + getTestName(false) + ".java", checkWarnings, false);
+ doTest(BASE_PATH + "/" + getTestName(false) + ".java", checkWarnings, false);
}
@Override
diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaInferenceTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaInferenceTest.java
index 96e60587a225..b13cfbc22e02 100644
--- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaInferenceTest.java
+++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaInferenceTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,6 +30,6 @@ public class LambdaInferenceTest extends LightDaemonAnalyzerTestCase {
}
private void doTest() throws Exception {
- doTestNewInference(BASE_PATH + "/" + getTestName(false) + ".java", false, false);
+ doTest(BASE_PATH + "/" + getTestName(false) + ".java", false, false);
}
}
diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaParamsTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaParamsTest.java
index 94ca90df2d02..faf1608c1cf0 100644
--- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaParamsTest.java
+++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaParamsTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,6 +30,6 @@ public class LambdaParamsTest extends LightDaemonAnalyzerTestCase {
public void testInferFromFormal() { doTest(); }
private void doTest() {
- doTestNewInference(BASE_PATH + "/" + getTestName(false) + ".java", false, false);
+ doTest(BASE_PATH + "/" + getTestName(false) + ".java", false, false);
}
}
diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaRedundantCastTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaRedundantCastTest.java
index 36f98aa91cc6..ae5a97933ca8 100644
--- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaRedundantCastTest.java
+++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LambdaRedundantCastTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -35,6 +35,6 @@ public class LambdaRedundantCastTest extends LightDaemonAnalyzerTestCase {
public void testIntersection() { doTest(); }
public void testSer() { doTest(); }
private void doTest() {
- doTestNewInference(BASE_PATH + "/" + getTestName(false) + ".java", true, false);
+ doTest(BASE_PATH + "/" + getTestName(false) + ".java", true, false);
}
}
diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LightAdvHighlightingJdk8Test.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LightAdvHighlightingJdk8Test.java
index 630acb0404b7..08a2b63550ff 100644
--- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LightAdvHighlightingJdk8Test.java
+++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/LightAdvHighlightingJdk8Test.java
@@ -18,7 +18,6 @@ package com.intellij.codeInsight.daemon.lambda;
import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase;
import com.intellij.codeInspection.LocalInspectionTool;
import com.intellij.codeInspection.compiler.JavacQuirksInspection;
-import com.intellij.codeInspection.unusedSymbol.UnusedSymbolLocalInspection;
import com.intellij.openapi.projectRoots.JavaSdkVersion;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.testFramework.IdeaTestUtil;
@@ -42,7 +41,7 @@ public class LightAdvHighlightingJdk8Test extends LightDaemonAnalyzerTestCase {
private void doTest() {
IdeaTestUtil.setTestVersion(JavaSdkVersion.JDK_1_8, getModule(), getTestRootDisposable());
- doTestNewInference(BASE_PATH + "/" + getTestName(false) + ".java", true, false);
+ doTest(BASE_PATH + "/" + getTestName(false) + ".java", true, false);
}
@Override
diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/MethodRefHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/MethodRefHighlightingTest.java
index 156aac5613c1..d0bed5e9d5df 100644
--- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/MethodRefHighlightingTest.java
+++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/MethodRefHighlightingTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -116,7 +116,7 @@ public class MethodRefHighlightingTest extends LightDaemonAnalyzerTestCase {
private void doTest(boolean warnings) {
IdeaTestUtil.setTestVersion(JavaSdkVersion.JDK_1_8, getModule(), getTestRootDisposable());
- doTestNewInference(BASE_PATH + "/" + getTestName(false) + ".java", warnings, false);
+ doTest(BASE_PATH + "/" + getTestName(false) + ".java", warnings, false);
}
@Override
diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/MostSpecificResolutionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/MostSpecificResolutionTest.java
index 9bb7d4801944..294a3cc8a4f6 100644
--- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/MostSpecificResolutionTest.java
+++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/MostSpecificResolutionTest.java
@@ -121,7 +121,7 @@ public class MostSpecificResolutionTest extends LightDaemonAnalyzerTestCase {
private void doTest(boolean warnings) {
IdeaTestUtil.setTestVersion(JavaSdkVersion.JDK_1_8, getModule(), getTestRootDisposable());
- doTestNewInference(BASE_PATH + "/" + getTestName(false) + ".java", warnings, false);
+ doTest(BASE_PATH + "/" + getTestName(false) + ".java", warnings, false);
}
@Override
diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java
index 1da75f51ba6f..712df26e356f 100644
--- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java
+++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewLambdaHighlightingTest.java
@@ -22,6 +22,8 @@ import com.intellij.idea.Bombed;
import com.intellij.openapi.projectRoots.JavaSdkVersion;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.testFramework.IdeaTestUtil;
+import junit.framework.Test;
+import junit.framework.TestSuite;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -71,21 +73,23 @@ public class NewLambdaHighlightingTest extends LightDaemonAnalyzerTestCase {
public void testIDEA121315() { doTest(); }
public void testIDEA118965comment() { doTest(); }
public void testIDEA122074() { doTest(); }
+ @Bombed(day = 30, month = Calendar.SEPTEMBER)
public void testIDEA122084() { doTest(); }
public void testAdditionalConstraintDependsOnNonMentionedVars() { doTest(); }
public void testIDEA122616() { doTest(); }
public void testIDEA122700() { doTest(); }
public void testIDEA122406() { doTest(); }
- @Bombed(day = 30, month = Calendar.SEPTEMBER)
public void testNestedCallsInsideLambdaReturnExpression() { doTest(); }
@Bombed(day = 30, month = Calendar.SEPTEMBER)
public void testIDEA123731() { doTest(); }
public void testIDEA123869() { doTest(); }
+ @Bombed(day = 30, month = Calendar.SEPTEMBER)
public void testIDEA123848() { doTest(); }
public void testOnlyLambdaAtTypeParameterPlace() { doTest(); }
public void testLiftedIntersectionType() { doTest(); }
public void testInferenceFromReturnStatements() { doTest(); }
public void testDownUpThroughLambdaReturnStatements() { doTest(); }
+ @Bombed(day = 30, month = Calendar.SEPTEMBER)
public void testIDEA124547() { doTest(); }
public void testIDEA118362() { doTest(); }
public void testIDEA126056() { doTest(); }
@@ -94,12 +98,17 @@ public class NewLambdaHighlightingTest extends LightDaemonAnalyzerTestCase {
public void testIDEA126109() { doTest(); }
public void testIDEA126809() { doTest(); }
public void testIDEA124424() { doTest(); }
+ public void testNestedLambdaExpressions1() { doTest(); }
+ public void testNestedLambdaExpressionsNoFormalParams() { doTest(); }
+ @Bombed(day = 30, month = Calendar.SEPTEMBER)
+ public void testNestedLambdaExpressionsNoFormalParams1() { doTest(); }
+ public void testDeepNestedLambdaExpressionsNoFormalParams() { doTest(); }
+ public void testNestedLambdaExpressionsNoFormalParamsStopAtStandalone() { doTest(); }
public void testIDEA127596() throws Exception {
doTest();
}
- @Bombed(day = 30, month = Calendar.SEPTEMBER)
public void testIDEA124983() throws Exception {
doTest();
}
@@ -115,17 +124,34 @@ public class NewLambdaHighlightingTest extends LightDaemonAnalyzerTestCase {
doTest();
}
+ public void testParenthesizedExpressionsDuringConstrainsCollection() throws Exception {
+ doTest();
+ }
+
+ @Bombed(day = 30, month = Calendar.SEPTEMBER)
+ public void testIDEA126778() throws Exception {
+ doTest();
+ }
+
private void doTest() {
doTest(false);
}
private void doTest(boolean warnings) {
IdeaTestUtil.setTestVersion(JavaSdkVersion.JDK_1_8, getModule(), getTestRootDisposable());
- doTestNewInference(BASE_PATH + "/" + getTestName(false) + ".java", warnings, false);
+ doTest(BASE_PATH + "/" + getTestName(false) + ".java", warnings, false);
}
@Override
protected Sdk getProjectJDK() {
return IdeaTestUtil.getMockJdk18();
}
+/*
+ public static Test suite() {
+ final TestSuite suite = new TestSuite();
+ for (int i = 0; i < 100; i++) {
+ suite.addTestSuite(NewLambdaHighlightingTest.class);
+ }
+ return suite;
+ }*/
}
diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewMethodRefHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewMethodRefHighlightingTest.java
index c981137d0253..0b8a66fe5b39 100644
--- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewMethodRefHighlightingTest.java
+++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/NewMethodRefHighlightingTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -288,7 +288,6 @@ public class NewMethodRefHighlightingTest extends LightDaemonAnalyzerTestCase {
doTest();
}
- @Bombed(day = 30, month = Calendar.SEPTEMBER)
public void testIDEA127275_() throws Exception {
doTest();
}
@@ -305,7 +304,6 @@ public class NewMethodRefHighlightingTest extends LightDaemonAnalyzerTestCase {
doTest();
}
- @Bombed(day = 30, month = Calendar.SEPTEMBER)
public void testAdditionalConstraints3Level() throws Exception {
doTest();
}
@@ -320,7 +318,7 @@ public class NewMethodRefHighlightingTest extends LightDaemonAnalyzerTestCase {
private void doTest(boolean warnings) {
IdeaTestUtil.setTestVersion(JavaSdkVersion.JDK_1_8, getModule(), getTestRootDisposable());
- doTestNewInference(BASE_PATH + "/" + getTestName(false) + ".java", warnings, false);
+ doTest(BASE_PATH + "/" + getTestName(false) + ".java", warnings, false);
}
@Override
diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/OverloadResolutionTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/OverloadResolutionTest.java
new file mode 100644
index 000000000000..0e5c5a2f3d78
--- /dev/null
+++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/OverloadResolutionTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.codeInsight.daemon.lambda;
+
+import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase;
+import com.intellij.codeInspection.LocalInspectionTool;
+import com.intellij.codeInspection.unusedSymbol.UnusedSymbolLocalInspection;
+import com.intellij.openapi.projectRoots.JavaSdkVersion;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.testFramework.IdeaTestUtil;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+public class OverloadResolutionTest extends LightDaemonAnalyzerTestCase {
+ @NonNls static final String BASE_PATH = "/codeInsight/daemonCodeAnalyzer/lambda/overloadResolution";
+
+ @NotNull
+ @Override
+ protected LocalInspectionTool[] configureLocalInspectionTools() {
+ return new LocalInspectionTool[]{
+ new UnusedSymbolLocalInspection(),
+ };
+ }
+
+ public void testPertinentToApplicabilityOfExplicitlyTypedLambda() throws Exception {
+ doTest();
+ }
+
+ public void testVoidValueCompatibilityOfImplicitlyTypedLambda() throws Exception {
+ doTest();
+ }
+
+ public void testIDEA102800() throws Exception {
+ doTest();
+ }
+
+ private void doTest() {
+ doTest(true);
+ }
+
+ private void doTest(boolean warnings) {
+ IdeaTestUtil.setTestVersion(JavaSdkVersion.JDK_1_8, getModule(), getTestRootDisposable());
+ doTest(BASE_PATH + "/" + getTestName(false) + ".java", warnings, false);
+ }
+
+ @Override
+ protected Sdk getProjectJDK() {
+ return IdeaTestUtil.getMockJdk18();
+ }
+}
diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy
index 095de51543af..3907b9828888 100644
--- a/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy
+++ b/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy
@@ -578,10 +578,14 @@ class Test {
return 0;
}
+ int arrayMethod(int param)[] {
+ return new int[];
+ }
+
}"""
PsiClass fooClass = JavaPsiFacade.getInstance(project).findClass('Foo', GlobalSearchScope.allScope(project))
def regions = myFixture.editor.foldingModel.allFoldRegions.sort { it.startOffset }
- assert regions.size() == 3
+ assert regions.size() == 4
checkAccessorFolding(regions[0], regions[1], fooClass.methods[0])
}
diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/generation/surroundWith/JavaSurroundWithTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/generation/surroundWith/JavaSurroundWithTest.java
index 60be917bde7c..8bd53fdabfbf 100644
--- a/java/java-tests/testSrc/com/intellij/codeInsight/generation/surroundWith/JavaSurroundWithTest.java
+++ b/java/java-tests/testSrc/com/intellij/codeInsight/generation/surroundWith/JavaSurroundWithTest.java
@@ -17,6 +17,7 @@ package com.intellij.codeInsight.generation.surroundWith;
import com.intellij.codeInsight.template.impl.TemplateManagerImpl;
import com.intellij.codeInsight.template.impl.TemplateState;
+import com.intellij.ide.highlighter.JavaFileType;
import com.intellij.lang.LanguageSurrounders;
import com.intellij.lang.java.JavaLanguage;
import com.intellij.lang.surroundWith.SurroundDescriptor;
@@ -24,6 +25,7 @@ import com.intellij.lang.surroundWith.Surrounder;
import com.intellij.openapi.editor.SelectionModel;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
+import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.testFramework.LightCodeInsightTestCase;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
@@ -156,6 +158,18 @@ public class JavaSurroundWithTest extends LightCodeInsightTestCase {
doTest(getTestName(false), new JavaWithIfElseExpressionSurrounder());
}
+ public void testSurroundWithTryFinallyUsingIndents() {
+ CommonCodeStyleSettings.IndentOptions indentOptions = getCurrentCodeStyleSettings().getIndentOptions(JavaFileType.INSTANCE);
+ boolean oldUseTabs = indentOptions.USE_TAB_CHARACTER;
+ try {
+ indentOptions.USE_TAB_CHARACTER = true;
+ doTest(getTestName(false), new JavaWithTryFinallySurrounder());
+ }
+ finally {
+ indentOptions.USE_TAB_CHARACTER = oldUseTabs;
+ }
+ }
+
private void doTest(@NotNull String fileName, final Surrounder surrounder) {
configureByFile(BASE_PATH + fileName + ".java");
diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/javadoc/JavaDocInfoGeneratorTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/javadoc/JavaDocInfoGeneratorTest.java
index 8bac921916d3..409ebcc681c1 100644
--- a/java/java-tests/testSrc/com/intellij/codeInsight/javadoc/JavaDocInfoGeneratorTest.java
+++ b/java/java-tests/testSrc/com/intellij/codeInsight/javadoc/JavaDocInfoGeneratorTest.java
@@ -99,11 +99,26 @@ public class JavaDocInfoGeneratorTest extends CodeInsightTestCase {
public void testEnumConstantOrdinal() throws Exception {
PsiClass psiClass = getTestClass();
PsiField field = psiClass.getFields() [0];
- final File htmlPath = new File(JavaTestUtil.getJavaTestDataPath() + "/codeInsight/javadocIG/" + getTestName(true) + ".html");
- String htmlText = FileUtil.loadFile(htmlPath);
- String docInfo = new JavaDocumentationProvider().getQuickNavigateInfo(field, field);
+ String docInfo = new JavaDocumentationProvider().generateDoc(field, field);
assertNotNull(docInfo);
- assertEquals(StringUtil.convertLineSeparators(htmlText.trim()), StringUtil.convertLineSeparators(docInfo.trim()));
+ assertEquals(exampleHtmlFileText(getTestName(true)), StringUtil.convertLineSeparators(docInfo.trim()));
+
+ docInfo = new JavaDocumentationProvider().getQuickNavigateInfo(field, field);
+ assertNotNull(docInfo);
+ assertEquals(exampleHtmlFileText(getTestName(true) + "_quick"), StringUtil.convertLineSeparators(docInfo.trim()));
+ }
+
+ public void testClickableFieldReference() throws Exception {
+ PsiClass aClass = getTestClass();
+ PsiTypeElement element = aClass.getFields()[0].getTypeElement();
+ String docInfo = new JavaDocumentationProvider().generateDoc(element.getInnermostComponentReferenceElement().resolve(), element);
+ assertNotNull(docInfo);
+ assertEquals(exampleHtmlFileText(getTestName(true)), StringUtil.convertLineSeparators(docInfo.trim()));
+ }
+
+ private static String exampleHtmlFileText(String name) throws IOException {
+ final File htmlPath = new File(JavaTestUtil.getJavaTestDataPath() + "/codeInsight/javadocIG/" + name + ".html");
+ return StringUtil.convertLineSeparators(FileUtil.loadFile(htmlPath).trim());
}
public void testClassTypeParamsPresentation() throws Exception {
@@ -111,11 +126,10 @@ public class JavaDocInfoGeneratorTest extends CodeInsightTestCase {
final PsiReferenceList extendsList = psiClass.getExtendsList();
final PsiJavaCodeReferenceElement referenceElement = extendsList.getReferenceElements()[0];
final PsiClass superClass = extendsList.getReferencedTypes()[0].resolve();
- final File htmlPath = new File(JavaTestUtil.getJavaTestDataPath() + "/codeInsight/javadocIG/" + getTestName(true) + ".html");
- String htmlText = FileUtil.loadFile(htmlPath);
+
String docInfo = new JavaDocumentationProvider().getQuickNavigateInfo(superClass, referenceElement);
assertNotNull(docInfo);
- assertEquals(StringUtil.convertLineSeparators(htmlText.trim()), StringUtil.convertLineSeparators(docInfo.trim()));
+ assertEquals(exampleHtmlFileText(getTestName(true)), StringUtil.convertLineSeparators(docInfo.trim()));
}
private void doTestField() throws Exception {
@@ -136,11 +150,9 @@ public class JavaDocInfoGeneratorTest extends CodeInsightTestCase {
}
private void verifyJavaDoc(final PsiElement field) throws IOException {
- final File htmlPath = new File(JavaTestUtil.getJavaTestDataPath() + "/codeInsight/javadocIG/" + getTestName(true) + ".html");
- String htmlText = FileUtil.loadFile(htmlPath);
String docInfo = new JavaDocInfoGenerator(getProject(), field).generateDocInfo(null);
assertNotNull(docInfo);
- assertEquals(StringUtil.convertLineSeparators(htmlText.trim()), StringUtil.convertLineSeparators(docInfo.trim()));
+ assertEquals(exampleHtmlFileText(getTestName(true)), StringUtil.convertLineSeparators(docInfo.trim()));
}
public void testPackageInfo() throws Exception {
diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/template/LiveTemplateTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/template/LiveTemplateTest.groovy
index d866ddd783cf..6abd2e809cdd 100644
--- a/java/java-tests/testSrc/com/intellij/codeInsight/template/LiveTemplateTest.groovy
+++ b/java/java-tests/testSrc/com/intellij/codeInsight/template/LiveTemplateTest.groovy
@@ -14,16 +14,14 @@
* limitations under the License.
*/
package com.intellij.codeInsight.template
+
import com.intellij.JavaTestUtil
import com.intellij.codeInsight.CodeInsightSettings
import com.intellij.codeInsight.lookup.LookupManager
import com.intellij.codeInsight.lookup.impl.LookupImpl
import com.intellij.codeInsight.lookup.impl.LookupManagerImpl
import com.intellij.codeInsight.template.impl.*
-import com.intellij.codeInsight.template.macro.ClassNameCompleteMacro
-import com.intellij.codeInsight.template.macro.CompleteMacro
-import com.intellij.codeInsight.template.macro.MethodReturnTypeMacro
-import com.intellij.codeInsight.template.macro.SnakeCaseMacro
+import com.intellij.codeInsight.template.macro.*
import com.intellij.openapi.Disposable
import com.intellij.openapi.command.WriteCommandAction
import com.intellij.openapi.editor.Editor
@@ -39,6 +37,7 @@ import com.intellij.util.ui.UIUtil
import org.jetbrains.annotations.NotNull
import static com.intellij.codeInsight.template.Template.Property.USE_STATIC_IMPORT_IF_POSSIBLE
+
/**
* @author spleaner
*/
@@ -462,7 +461,8 @@ class Foo {
@Override
protected void invokeTestRunnable(@NotNull final Runnable runnable) throws Exception {
- if (name in ["testNavigationActionsDontTerminateTemplate", "testTemplateWithEnd", "testDisappearingVar", "test escape string characters in soutv"]) {
+ if (name in ["testNavigationActionsDontTerminateTemplate", "testTemplateWithEnd", "testDisappearingVar",
+ "test escape string characters in soutv", "test do not replace macro value with empty result"]) {
runnable.run();
return;
}
@@ -823,4 +823,38 @@ class Foo {
}
"""
}
+
+ public void "test do not replace macro value with empty result"() {
+ myFixture.configureByText "a.java", """\
+class Foo {
+ {
+ <caret>
+ }
+}
+"""
+ final TemplateManager manager = TemplateManager.getInstance(getProject());
+ final Template template = manager.createTemplate("xxx", "user", '$VAR1$ $VAR2$ $VAR1$');
+ template.addVariable("VAR1", "", "", true)
+ template.addVariable("VAR2", new MacroCallNode(new FileNameMacro()), new ConstantNode("default"), true)
+ ((TemplateImpl)template).templateContext.setEnabled(contextType(JavaCodeContextType.class), true)
+ addTemplate(template, testRootDisposable)
+
+ startTemplate(template);
+ myFixture.checkResult """\
+class Foo {
+ {
+ <caret> a.java
+ }
+}
+"""
+ myFixture.type 'test'
+
+ myFixture.checkResult """\
+class Foo {
+ {
+ test<caret> a.java test
+ }
+}
+"""
+ }
}
diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/ContractInferenceFromSourceTest.groovy b/java/java-tests/testSrc/com/intellij/codeInspection/ContractInferenceFromSourceTest.groovy
index c3bb014d8342..d8b6fb2c53df 100644
--- a/java/java-tests/testSrc/com/intellij/codeInspection/ContractInferenceFromSourceTest.groovy
+++ b/java/java-tests/testSrc/com/intellij/codeInspection/ContractInferenceFromSourceTest.groovy
@@ -161,11 +161,10 @@ class ContractInferenceFromSourceTest extends LightCodeInsightFixtureTestCase {
assert c == ['null -> fail']
}
- void "_test no NotNull duplication"() {
+ void "test no return value NotNull duplication"() {
def c = inferContracts("""
- boolean smth(@org.jetbrains.annotations.NotNull Object o) {
- if (o == null) throw new RuntimeException();
- return o.hashCode() == 1;
+ @org.jetbrains.annotations.NotNull String smth(Object o) {
+ return "abc";
}
""")
assert c == []
@@ -334,29 +333,41 @@ class ContractInferenceFromSourceTest extends LightCodeInsightFixtureTestCase {
assert c == ['null -> null']
}
- public void "test go inside try"() {
+ public void "test use invoked method notnull"() {
def c = inferContracts("""
final Object foo(Object bar) {
- try {
- if (bar == null) return null;
- bar = smth(bar);
- } finally {}
- return new String("abc");
+ if (bar == null) return null;
+ return doo();
}
+
+ @org.jetbrains.annotations.NotNull Object doo() {}
""")
- assert c == ['null -> null']
+ assert c == ['null -> null', '!null -> !null']
}
- public void "test use invoked method notnull"() {
+ public void "test use delegated method notnull"() {
def c = inferContracts("""
final Object foo(Object bar) {
- if (bar == null) return null;
return doo();
}
@org.jetbrains.annotations.NotNull Object doo() {}
""")
- assert c == ['null -> null', '!null -> !null']
+ assert c == ['_ -> !null']
+ }
+
+ public void "test use delegated method notnull with contracts"() {
+ def c = inferContracts("""
+ final Object foo(Object bar, Object o2) {
+ return doo(o2);
+ }
+
+ @org.jetbrains.annotations.NotNull Object doo(Object o) {
+ if (o == null) throw new RuntimeException();
+ return smth();
+ }
+ """)
+ assert c == ['_, null -> fail', '_, _ -> !null']
}
private String inferContract(String method) {
diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java
index a10d02d31fca..0acf071bbf4a 100644
--- a/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java
+++ b/java/java-tests/testSrc/com/intellij/codeInspection/DataFlowInspectionTest.java
@@ -113,7 +113,8 @@ public class DataFlowInspectionTest extends LightCodeInsightFixtureTestCase {
public void testReturningNullFromVoidMethod() throws Throwable { doTest(); }
public void testCatchRuntimeException() throws Throwable { doTest(); }
- public void testCatchThrowable() throws Throwable { doTest(); }
+ // IDEA-129331
+ //public void testCatchThrowable() throws Throwable { doTest(); }
public void testNotNullCatchParameter() { doTest(); }
public void testAssertFailInCatch() throws Throwable {
diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisIntegrationTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisIntegrationTest.java
index ab6d92263162..8cde2d7f1bc2 100644
--- a/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisIntegrationTest.java
+++ b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisIntegrationTest.java
@@ -133,22 +133,37 @@ public class BytecodeAnalysisIntegrationTest extends JavaCodeInsightFixtureTestC
return;
}
- // not null-result
- String externalOutAnnotation =
- myExternalAnnotationsManager.findExternalAnnotation(method, AnnotationUtil.NOT_NULL) == null ? "null" : "@NotNull";
- String inferredOutAnnotation =
- myInferredAnnotationsManager.findInferredAnnotation(method, AnnotationUtil.NOT_NULL) == null ? "null" : "@NotNull";
String methodKey = PsiFormatUtil.getExternalName(method, false, Integer.MAX_VALUE);
- if (!externalOutAnnotation.equals(inferredOutAnnotation)) {
- diffs.add(methodKey + ": " + externalOutAnnotation + " != " + inferredOutAnnotation);
+ {
+ // @NotNull method
+ String externalNotNullMethodAnnotation =
+ myExternalAnnotationsManager.findExternalAnnotation(method, AnnotationUtil.NOT_NULL) == null ? "null" : "@NotNull";
+ String inferredNotNullMethodAnnotation =
+ myInferredAnnotationsManager.findInferredAnnotation(method, AnnotationUtil.NOT_NULL) == null ? "null" : "@NotNull";
+
+ if (!externalNotNullMethodAnnotation.equals(inferredNotNullMethodAnnotation)) {
+ diffs.add(methodKey + ": " + externalNotNullMethodAnnotation + " != " + inferredNotNullMethodAnnotation);
+ }
+ }
+
+ {
+ // @Nullable method
+ String externalNullableMethodAnnotation =
+ myExternalAnnotationsManager.findExternalAnnotation(method, AnnotationUtil.NULLABLE) == null ? "null" : "@Nullable";
+ String inferredNullableMethodAnnotation =
+ myInferredAnnotationsManager.findInferredAnnotation(method, AnnotationUtil.NULLABLE) == null ? "null" : "@Nullable";
+
+ if (!externalNullableMethodAnnotation.equals(inferredNullableMethodAnnotation)) {
+ diffs.add(methodKey + ": " + externalNullableMethodAnnotation + " != " + inferredNullableMethodAnnotation);
+ }
}
for (PsiParameter parameter : method.getParameterList().getParameters()) {
String parameterKey = PsiFormatUtil.getExternalName(parameter, false, Integer.MAX_VALUE);
{
- // @NotNull
+ // @NotNull parameter
String externalNotNull =
myExternalAnnotationsManager.findExternalAnnotation(parameter, AnnotationUtil.NOT_NULL) == null ? "null" : "@NotNull";
String inferredNotNull =
@@ -159,7 +174,7 @@ public class BytecodeAnalysisIntegrationTest extends JavaCodeInsightFixtureTestC
}
{
- // @Nullable
+ // @Nullable parameter
String externalNullable =
myExternalAnnotationsManager.findExternalAnnotation(parameter, AnnotationUtil.NULLABLE) == null ? "null" : "@Nullable";
String inferredNullable =
@@ -170,6 +185,7 @@ public class BytecodeAnalysisIntegrationTest extends JavaCodeInsightFixtureTestC
}
}
+ // @Contract
PsiAnnotation externalContractAnnotation =
myExternalAnnotationsManager.findExternalAnnotation(method, ORG_JETBRAINS_ANNOTATIONS_CONTRACT);
PsiAnnotation inferredContractAnnotation =
diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisTest.java
index 2cbf3fbdfd6c..abae78e2a8e5 100644
--- a/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisTest.java
+++ b/java/java-tests/testSrc/com/intellij/codeInspection/bytecodeAnalysis/BytecodeAnalysisTest.java
@@ -184,14 +184,13 @@ public class BytecodeAnalysisTest extends JavaCodeInsightFixtureTestCase {
}
private void checkCompoundId(Method method, PsiMethod psiMethod, boolean noKey) throws IOException {
- Direction direction = new Out();
System.out.println();
System.out.println(method.internalClassName);
System.out.println(method.methodName);
System.out.println(method.methodDesc);
- HKey psiKey = BytecodeAnalysisConverter.psiKey(psiMethod, direction, myMessageDigest);
+ HKey psiKey = BytecodeAnalysisConverter.psiKey(psiMethod, Direction.Out, myMessageDigest);
if (noKey) {
assertTrue(null == psiKey);
return;
@@ -199,7 +198,7 @@ public class BytecodeAnalysisTest extends JavaCodeInsightFixtureTestCase {
else {
assertFalse(null == psiKey);
}
- HKey asmKey = BytecodeAnalysisConverter.asmKey(new Key(method, direction, true), myMessageDigest);
+ HKey asmKey = BytecodeAnalysisConverter.asmKey(new Key(method, Direction.Out, true), myMessageDigest);
Assert.assertEquals(asmKey, psiKey);
}
diff --git a/java/java-tests/testSrc/com/intellij/execution/configurations/JavaCommandLineTest.java b/java/java-tests/testSrc/com/intellij/execution/configurations/JavaCommandLineTest.java
index 2708ac91181c..e4d0bc039c5d 100644
--- a/java/java-tests/testSrc/com/intellij/execution/configurations/JavaCommandLineTest.java
+++ b/java/java-tests/testSrc/com/intellij/execution/configurations/JavaCommandLineTest.java
@@ -48,6 +48,14 @@ public class JavaCommandLineTest extends LightIdeaTestCase {
}
}
+ public void testJarParameter() throws CantRunException {
+ JavaParameters javaParameters = new JavaParameters();
+ javaParameters.setJdk(getProjectJDK());
+ javaParameters.setJarPath("my-jar-file.jar");
+ String commandLineString = CommandLineBuilder.createFromJavaParameters(javaParameters).getCommandLineString();
+ assertTrue(commandLineString, commandLineString.contains("-jar my-jar-file.jar"));
+ }
+
public void testClasspath() throws CantRunException {
JavaParameters javaParameters;
String commandLineString;
@@ -55,12 +63,14 @@ public class JavaCommandLineTest extends LightIdeaTestCase {
javaParameters = new JavaParameters();
final Sdk internalJdk = JavaAwareProjectJdkTableImpl.getInstanceEx().getInternalJdk();
javaParameters.setJdk(internalJdk);
+ javaParameters.getClassPath().add("my-jar-file.jar");
javaParameters.setMainClass("Main");
commandLineString = CommandLineBuilder.createFromJavaParameters(javaParameters).getCommandLineString();
assertTrue(containsClassPath(commandLineString));
javaParameters = new JavaParameters();
javaParameters.setJdk(internalJdk);
+ javaParameters.getClassPath().add("my-jar-file.jar");
javaParameters.setMainClass("Main");
javaParameters.getVMParametersList().add("-cp");
javaParameters.getVMParametersList().add("..");
@@ -70,6 +80,7 @@ public class JavaCommandLineTest extends LightIdeaTestCase {
javaParameters = new JavaParameters();
javaParameters.setJdk(internalJdk);
+ javaParameters.getClassPath().add("my-jar-file.jar");
javaParameters.setMainClass("Main");
javaParameters.getVMParametersList().add("-classpath");
javaParameters.getVMParametersList().add("..");
diff --git a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterWrapTest.java b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterWrapTest.java
index c06370b06743..b16e23e83e37 100644
--- a/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterWrapTest.java
+++ b/java/java-tests/testSrc/com/intellij/psi/formatter/java/JavaFormatterWrapTest.java
@@ -16,7 +16,6 @@
package com.intellij.psi.formatter.java;
import com.intellij.idea.Bombed;
-import com.intellij.lang.java.JavaLanguage;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
@@ -448,4 +447,34 @@ public class JavaFormatterWrapTest extends AbstractJavaFormatterTest {
" public @TA String m();\n" +
"}");
}
+
+ public void testKeepSingleFieldAnnotationOnSameLine() {
+ getJavaSettings().DO_NOT_WRAP_AFTER_SINGLE_ANNOTATION = true;
+ doClassTest(
+ "@NotNull public String result = \"OK\"\n" +
+ "@NotNull String newResult = \"OK\"\n" +
+ "@NotNull\n" +
+ "@Deprecated public String bad = \"bad\"",
+
+ "@NotNull public String result = \"OK\"\n" +
+ "@NotNull String newResult = \"OK\"\n" +
+ "@NotNull\n" +
+ "@Deprecated\n" +
+ "public String bad = \"bad\""
+ );
+ }
+
+ public void testMoveSingleAnnotationOnSameLine() {
+ getJavaSettings().DO_NOT_WRAP_AFTER_SINGLE_ANNOTATION = true;
+ getSettings().KEEP_LINE_BREAKS = false;
+ doClassTest(
+ "@NotNull\n" +
+ "public String test = \"tst\";\n" +
+ "String ok = \"ok\";\n",
+ "@NotNull public String test = \"tst\";\n" +
+ "String ok = \"ok\";\n"
+ );
+ }
+
+
}
diff --git a/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodObject4DebuggerTest.java b/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodObject4DebuggerTest.java
new file mode 100644
index 000000000000..9321cf9a6695
--- /dev/null
+++ b/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodObject4DebuggerTest.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * User: anna
+ * Date: 06-May-2008
+ */
+package com.intellij.refactoring;
+
+import com.intellij.JavaTestUtil;
+import com.intellij.idea.Bombed;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.psi.*;
+import com.intellij.refactoring.extractMethodObject.ExtractLightMethodObjectHandler;
+import com.intellij.testFramework.IdeaTestUtil;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Calendar;
+
+public class ExtractMethodObject4DebuggerTest extends LightRefactoringTestCase {
+ @NotNull
+ @Override
+ protected String getTestDataPath() {
+ return JavaTestUtil.getJavaTestDataPath();
+ }
+
+ private void doTest(String evaluatedText, String expectedCallSite, String expectedClass) throws Exception {
+ final String testName = getTestName(false);
+ configureByFile("/refactoring/extractMethodObject4Debugger/" + testName + ".java");
+ final int offset = getEditor().getCaretModel().getOffset();
+ final PsiElement context = getFile().findElementAt(offset);
+ final JavaCodeFragment fragment = JavaCodeFragmentFactory.getInstance(getProject()).createCodeBlockCodeFragment(evaluatedText, context, false);
+ final ExtractLightMethodObjectHandler.ExtractedData extractedData =
+ ExtractLightMethodObjectHandler.extractLightMethodObject(getProject(), getFile(), fragment, "test");
+ assertNotNull(extractedData);
+ assertEquals(expectedCallSite, extractedData.getGeneratedCallText());
+ final PsiClass innerClass = extractedData.getGeneratedInnerClass();
+ assertEquals(expectedClass, innerClass.getText());
+ }
+
+ public void testSimpleGeneration() throws Exception {
+ doTest("int i = 0; int j = 0;", "Test test = new Test().invoke();int i = test.getI();int j = test.getJ();",
+
+ "public class Test {\n" +
+ " private int i;\n" +
+ " private int j;\n" +
+ "\n" +
+ " public int getI() {\n" +
+ " return i;\n" +
+ " }\n" +
+ "\n" +
+ " public int getJ() {\n" +
+ " return j;\n" +
+ " }\n" +
+ "\n" +
+ " public Test invoke() {\n" +
+ " i = 0;\n" +
+ " j = 0;\n" +
+ " return this;\n" +
+ " }\n" +
+ " }");
+ }
+
+ public void testInvokeReturnType() throws Exception {
+ doTest("x = 6; y = 6;", "Test test = new Test().invoke();x = test.getX();y = test.getY();",
+
+ "public static class Test {\n" +
+ " private int x;\n" +
+ " private int y;\n" +
+ "\n" +
+ " public int getX() {\n" +
+ " return x;\n" +
+ " }\n" +
+ "\n" +
+ " public int getY() {\n" +
+ " return y;\n" +
+ " }\n" +
+ "\n" +
+ " public Test invoke() {\n" +
+ " x = 6;\n" +
+ " y = 6;\n" +
+ " return this;\n" +
+ " }\n" +
+ " }");
+ }
+
+ public void testAnonymousClassParams() throws Exception {
+ doTest("new I() {public void foo(int i) {i++;}};", "I result = new Test().invoke();",
+
+ "public class Test {\n" +
+ " public I invoke() {\n" +
+ " return new I() {\n" +
+ " public void foo(int i) {\n" +
+ " i++;\n" +
+ " }\n" +
+ " };\n" +
+ " }\n" +
+ " }");
+ }
+
+ public void testInnerClass() throws Exception {
+ doTest(" new I(2).foo()", "new Test().invoke();",
+
+ "public class Test {\n" +
+ " public void invoke() {\n" +
+ " new Sample.I(2).foo();\n" +
+ " }\n" +
+ " }");
+ }
+
+ public void testResultExpr() throws Exception {
+ doTest(" foo()", "int result = new Test().invoke();",
+
+ "public class Test {\n" +
+ " public int invoke() {\n" +
+ " return foo();\n" +
+ " }\n" +
+ " }");
+ }
+
+ public void testResultStatements() throws Exception {
+ doTest("int i = 0;\nfoo()", "Test test = new Test().invoke();int i = test.getI();int result = test.getResult();",
+
+ "public class Test {\n" +
+ " private int i;\n" +
+ " private int result;\n" +
+ "\n" +
+ " public int getI() {\n" +
+ " return i;\n" +
+ " }\n" +
+ "\n" +
+ " public int getResult() {\n" +
+ " return result;\n" +
+ " }\n" +
+ "\n" +
+ " public Test invoke() {\n" +
+ " i = 0;\n" +
+ " result = foo();\n" +
+ " return this;\n" +
+ " }\n" +
+ " }");
+ }
+
+
+ public void testOffsetsAtCallSite() throws Exception {
+ doTest("map.entrySet().stream().filter((a) -> (a.getKey()>0));",
+ "java.util.stream.Stream<Map.Entry<Integer,Integer>> result = new Test(map).invoke();",
+ "public class Test {\n" +
+ " private Map<Integer, Integer> map;\n" +
+ "\n" +
+ " public Test(Map<Integer, Integer> map) {\n" +
+ " this.map = map;\n" +
+ " }\n" +
+ "\n" +
+ " public Stream<Map.Entry<Integer, Integer>> invoke() {\n" +
+ " return map.entrySet().stream().filter((a) -> (a.getKey() > 0));\n" +
+ " }\n" +
+ " }");
+ }
+
+ @Override
+ protected Sdk getProjectJDK() {
+ return IdeaTestUtil.getMockJdk18();
+ }
+}
diff --git a/java/java-tests/testSrc/com/intellij/refactoring/IntroduceVariableTest.java b/java/java-tests/testSrc/com/intellij/refactoring/IntroduceVariableTest.java
index 34745372977e..6ef80d01903e 100644
--- a/java/java-tests/testSrc/com/intellij/refactoring/IntroduceVariableTest.java
+++ b/java/java-tests/testSrc/com/intellij/refactoring/IntroduceVariableTest.java
@@ -18,9 +18,10 @@ package com.intellij.refactoring;
import com.intellij.JavaTestUtil;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
-import com.intellij.psi.*;
-import com.intellij.psi.impl.source.resolve.PsiResolveHelperImpl;
-import com.intellij.psi.impl.source.resolve.graphInference.PsiGraphInferenceHelper;
+import com.intellij.psi.CommonClassNames;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiExpression;
+import com.intellij.psi.PsiType;
import com.intellij.refactoring.introduce.inplace.OccurrencesChooser;
import com.intellij.refactoring.introduceVariable.InputValidator;
import com.intellij.refactoring.introduceVariable.IntroduceVariableBase;
@@ -95,15 +96,8 @@ public class IntroduceVariableTest extends LightCodeInsightTestCase {
}
public void testExpectedType8Inference() {
- final PsiResolveHelperImpl helper = (PsiResolveHelperImpl)JavaPsiFacade.getInstance(getProject()).getResolveHelper();
- helper.setTestHelper(new PsiGraphInferenceHelper(getPsiManager()));
- try {
- doTest(new MockIntroduceVariableHandler("temp", true, false, false,
- "java.util.Map<java.lang.String,java.util.List<java.lang.String>>"));
- }
- finally {
- helper.setTestHelper(null);
- }
+ doTest(new MockIntroduceVariableHandler("temp", true, false, false,
+ "java.util.Map<java.lang.String,java.util.List<java.lang.String>>"));
}
public void testMethodCall() {
diff --git a/java/openapi/src/com/intellij/execution/filters/ExceptionWorker.java b/java/openapi/src/com/intellij/execution/filters/ExceptionWorker.java
index 680ae8f744ce..c912e57999dd 100644
--- a/java/openapi/src/com/intellij/execution/filters/ExceptionWorker.java
+++ b/java/openapi/src/com/intellij/execution/filters/ExceptionWorker.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -48,18 +48,6 @@ public class ExceptionWorker {
private static final String AT_PREFIX = AT + " ";
private static final String STANDALONE_AT = " " + AT + " ";
- private static final TextAttributes HYPERLINK_ATTRIBUTES;
- private static final TextAttributes LIBRARY_HYPERLINK_ATTRIBUTES;
-
- static {
- HYPERLINK_ATTRIBUTES = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(CodeInsightColors.HYPERLINK_ATTRIBUTES);
-
- LIBRARY_HYPERLINK_ATTRIBUTES = HYPERLINK_ATTRIBUTES.clone();
- Color libTextColor = UIUtil.getInactiveTextColor();
- LIBRARY_HYPERLINK_ATTRIBUTES.setForegroundColor(libTextColor);
- LIBRARY_HYPERLINK_ATTRIBUTES.setEffectColor(libTextColor);
- }
-
private final Project myProject;
private Filter.Result myResult;
private PsiClass[] myClasses = PsiClass.EMPTY_ARRAY;
@@ -129,13 +117,16 @@ public class ExceptionWorker {
}
List<VirtualFile> virtualFiles;
- TextAttributes attributes;
+ TextAttributes attributes = EditorColorsManager.getInstance().getGlobalScheme().getAttributes(CodeInsightColors.HYPERLINK_ATTRIBUTES);
if (virtualFilesInContent.isEmpty()) {
- attributes = LIBRARY_HYPERLINK_ATTRIBUTES;
+ Color libTextColor = UIUtil.getInactiveTextColor();
+ attributes = attributes.clone();
+ attributes.setForegroundColor(libTextColor);
+ attributes.setEffectColor(libTextColor);
+
virtualFiles = virtualFilesInLibraries;
}
else {
- attributes = HYPERLINK_ATTRIBUTES;
virtualFiles = virtualFilesInContent;
}
HyperlinkInfo linkInfo = HyperlinkInfoFactory.getInstance().createMultipleFilesHyperlinkInfo(virtualFiles, lineNumber - 1, myProject);
diff --git a/java/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/deployment/debug/JavaDebuggerLauncherImpl.java b/java/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/deployment/debug/JavaDebuggerLauncherImpl.java
index 0ff284e054dd..c56597c938c2 100644
--- a/java/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/deployment/debug/JavaDebuggerLauncherImpl.java
+++ b/java/remote-servers/impl/src/com/intellij/remoteServer/impl/runtime/deployment/debug/JavaDebuggerLauncherImpl.java
@@ -7,7 +7,6 @@ import com.intellij.debugger.engine.DebugProcess;
import com.intellij.debugger.engine.DebugProcessAdapter;
import com.intellij.debugger.engine.RemoteDebugProcessHandler;
import com.intellij.debugger.ui.DebuggerPanelsManager;
-import com.intellij.diagnostic.logging.LogFilesManager;
import com.intellij.execution.*;
import com.intellij.execution.configurations.RemoteConnection;
import com.intellij.execution.configurations.RunProfile;
@@ -98,10 +97,6 @@ public class JavaDebuggerLauncherImpl extends JavaDebuggerLauncher {
}
@Override
- public void initLogs(RunContentDescriptor content, LogFilesManager logFilesManager) {
- }
-
- @Override
public void initActions(RunContentDescriptor content, DefaultActionGroup actionGroup) {
actionGroup.add(new CloseAction(myExecutionEnvironment.getExecutor(), content, myExecutionEnvironment.getProject()));
}
diff --git a/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaReplaceHandler.java b/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaReplaceHandler.java
index 562c8aee753c..3164a297a8b9 100644
--- a/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaReplaceHandler.java
+++ b/java/structuralsearch-java/src/com/intellij/structuralsearch/JavaReplaceHandler.java
@@ -477,7 +477,17 @@ public class JavaReplaceHandler extends StructuralReplaceHandler {
return;
}
super.visitReferenceExpression(expression);
- if (offset + expression.getTextLength() < finalStartOffset)
+ if (offset + expression.getTextLength() < finalStartOffset) {
+ return;
+ }
+ final PsiElement target = expression.resolve();
+ if (!(target instanceof PsiMember)) {
+ return;
+ }
+ final PsiMember member = (PsiMember)target;
+ if (!member.hasModifierProperty(PsiModifier.STATIC)) {
+ return;
+ }
if (expression.getQualifierExpression() == null) {
return;
}
diff --git a/java/testFramework/src/com/intellij/codeInsight/daemon/LightDaemonAnalyzerTestCase.java b/java/testFramework/src/com/intellij/codeInsight/daemon/LightDaemonAnalyzerTestCase.java
index ff98bd23b858..d2b25c6d3d04 100644
--- a/java/testFramework/src/com/intellij/codeInsight/daemon/LightDaemonAnalyzerTestCase.java
+++ b/java/testFramework/src/com/intellij/codeInsight/daemon/LightDaemonAnalyzerTestCase.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,11 +24,8 @@ import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.vfs.VirtualFileFilter;
-import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
-import com.intellij.psi.impl.source.resolve.PsiResolveHelperImpl;
-import com.intellij.psi.impl.source.resolve.graphInference.PsiGraphInferenceHelper;
import com.intellij.testFramework.ExpectedHighlightingData;
import com.intellij.testFramework.FileTreeAccessFilter;
import com.intellij.testFramework.HighlightTestInfo;
@@ -83,18 +80,6 @@ public abstract class LightDaemonAnalyzerTestCase extends LightCodeInsightTestCa
doTestConfiguredFile(checkWarnings, checkInfos, filePath);
}
- protected void doTestNewInference(@NonNls String filePath, boolean checkWarnings, boolean checkInfos) {
- final PsiResolveHelperImpl helper = (PsiResolveHelperImpl)JavaPsiFacade.getInstance(getProject()).getResolveHelper();
- helper.setTestHelper(new PsiGraphInferenceHelper(getPsiManager()));
- try {
- configureByFile(filePath);
- doTestConfiguredFile(checkWarnings, checkInfos, filePath);
- }
- finally {
- helper.setTestHelper(null);
- }
- }
-
protected void doTest(@NonNls String filePath, boolean checkWarnings, boolean checkWeakWarnings, boolean checkInfos) {
configureByFile(filePath);
doTestConfiguredFile(checkWarnings, checkWeakWarnings, checkInfos, filePath);
diff --git a/java/testFramework/src/com/intellij/compiler/CompilerTestUtil.java b/java/testFramework/src/com/intellij/compiler/CompilerTestUtil.java
index 0f8f11ce6788..e5a9ee47daed 100644
--- a/java/testFramework/src/com/intellij/compiler/CompilerTestUtil.java
+++ b/java/testFramework/src/com/intellij/compiler/CompilerTestUtil.java
@@ -8,10 +8,15 @@ import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.application.ex.ApplicationManagerEx;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.fileTypes.impl.FileTypeManagerImpl;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.ProjectJdkTable;
+import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.impl.JavaAwareProjectJdkTableImpl;
import com.intellij.openapi.projectRoots.impl.ProjectJdkTableImpl;
+import com.intellij.openapi.roots.ModuleRootManager;
+import com.intellij.openapi.roots.ModuleRootModificationUtil;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.util.WriteExternalException;
@@ -27,6 +32,7 @@ import org.jetbrains.jps.model.serialization.JpsGlobalLoader;
import java.io.File;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -91,8 +97,20 @@ public class CompilerTestUtil {
new WriteAction() {
protected void run(final Result result) {
ApplicationManagerEx.getApplicationEx().doNotSave(true);
+ Module[] modules = ModuleManager.getInstance(project).getModules();
JavaAwareProjectJdkTableImpl table = JavaAwareProjectJdkTableImpl.getInstanceEx();
- table.removeJdk(table.getInternalJdk());
+ Sdk internalJdk = table.getInternalJdk();
+ List<Module> modulesToRestore = new ArrayList<Module>();
+ for (Module module : modules) {
+ Sdk sdk = ModuleRootManager.getInstance(module).getSdk();
+ if (sdk != null && sdk.equals(internalJdk)) {
+ modulesToRestore.add(module);
+ }
+ }
+ table.removeJdk(internalJdk);
+ for (Module module : modulesToRestore) {
+ ModuleRootModificationUtil.setModuleSdk(module, internalJdk);
+ }
BuildManager.getInstance().clearState(project);
}
}.execute();
diff --git a/java/testFramework/src/com/intellij/debugger/DebuggerTestCase.java b/java/testFramework/src/com/intellij/debugger/DebuggerTestCase.java
index 2ec9ae61e17b..06ebf7875e6e 100644
--- a/java/testFramework/src/com/intellij/debugger/DebuggerTestCase.java
+++ b/java/testFramework/src/com/intellij/debugger/DebuggerTestCase.java
@@ -28,17 +28,16 @@ import com.intellij.debugger.settings.DebuggerSettings;
import com.intellij.debugger.settings.NodeRendererSettings;
import com.intellij.debugger.ui.breakpoints.BreakpointManager;
import com.intellij.execution.ExecutionException;
-import com.intellij.execution.ExecutionResult;
import com.intellij.execution.Executor;
import com.intellij.execution.configurations.*;
import com.intellij.execution.executors.DefaultDebugExecutor;
import com.intellij.execution.process.ProcessAdapter;
import com.intellij.execution.process.ProcessEvent;
+import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.process.ProcessOutputTypes;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.runners.ExecutionEnvironmentBuilder;
import com.intellij.execution.runners.ProgramRunner;
-import com.intellij.execution.ui.ExecutionConsole;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.editor.Document;
@@ -46,7 +45,10 @@ import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.options.SettingsEditor;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.*;
+import com.intellij.openapi.util.Computable;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.Key;
+import com.intellij.openapi.util.WriteExternalException;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiClass;
@@ -88,11 +90,11 @@ public abstract class DebuggerTestCase extends ExecutionWithDebuggerToolsTestCas
protected void runTest() throws Throwable {
super.runTest();
if(getDebugProcess() != null) {
- getDebugProcess().getExecutionResult().getProcessHandler().startNotify();
- waitProcess(getDebugProcess().getExecutionResult().getProcessHandler());
+ getDebugProcess().getProcessHandler().startNotify();
+ waitProcess(getDebugProcess().getProcessHandler());
waitForCompleted();
//disposeSession(myDebuggerSession);
- assertNull(DebuggerManagerEx.getInstanceEx(myProject).getDebugProcess(getDebugProcess().getExecutionResult().getProcessHandler()));
+ assertNull(DebuggerManagerEx.getInstanceEx(myProject).getDebugProcess(getDebugProcess().getProcessHandler()));
myDebuggerSession = null;
}
if(myConsoleBuffer != null) {
@@ -119,11 +121,6 @@ public abstract class DebuggerTestCase extends ExecutionWithDebuggerToolsTestCas
@Override
protected void tearDown() throws Exception {
FileEditorManagerEx.getInstanceEx(getProject()).closeAllFiles();
- ExecutionResult executionResult = myDebugProcess == null ? null : myDebugProcess.getExecutionResult();
- ExecutionConsole console = executionResult == null ? null : executionResult.getExecutionConsole();
- if (console != null) {
- Disposer.dispose(console);
- }
myConsoleBuffer = null;
super.tearDown();
}
@@ -134,7 +131,7 @@ public abstract class DebuggerTestCase extends ExecutionWithDebuggerToolsTestCas
myDebugProcess = myDebuggerSession.getProcess();
}
- protected DebuggerSession createLocalSession(final JavaParameters javaParameters, final String sessionName) throws ExecutionException, InterruptedException {
+ protected DebuggerSession createLocalSession(final JavaParameters javaParameters) throws ExecutionException, InterruptedException {
createBreakpoints(javaParameters.getMainClass());
DebuggerSettings.getInstance().DEBUGGER_TRANSPORT = DebuggerSettings.SOCKET_TRANSPORT;
@@ -145,7 +142,7 @@ public abstract class DebuggerTestCase extends ExecutionWithDebuggerToolsTestCas
ExecutionEnvironment environment = new ExecutionEnvironmentBuilder(myProject, DefaultDebugExecutor.getDebugExecutorInstance())
.runnerSettings(debuggerRunnerSettings)
- .setRunProfile(new MockConfiguration())
+ .runProfile(new MockConfiguration())
.build();
final JavaCommandLineState javaCommandLineState = new JavaCommandLineState(environment){
@Override
@@ -241,7 +238,7 @@ public abstract class DebuggerTestCase extends ExecutionWithDebuggerToolsTestCas
}
});
- final ExecutionResult executionResult = debuggerSession[0].getProcess().getExecutionResult();
+ final ProcessHandler processHandler = debuggerSession[0].getProcess().getProcessHandler();
debuggerSession[0].getProcess().addProcessListener(new ProcessAdapter() {
@Override
public void onTextAvailable(ProcessEvent event, Key outputType) {
@@ -250,7 +247,7 @@ public abstract class DebuggerTestCase extends ExecutionWithDebuggerToolsTestCas
});
DebugProcessImpl process =
- (DebugProcessImpl)DebuggerManagerEx.getInstanceEx(myProject).getDebugProcess(executionResult.getProcessHandler());
+ (DebugProcessImpl)DebuggerManagerEx.getInstanceEx(myProject).getDebugProcess(processHandler);
assertNotNull(process);
return debuggerSession[0];
}
@@ -293,9 +290,9 @@ public abstract class DebuggerTestCase extends ExecutionWithDebuggerToolsTestCas
debuggerSession = attachVM(remoteConnection, true);
}
- ExecutionResult executionResult = debuggerSession.getProcess().getExecutionResult();
+ ProcessHandler processHandler = debuggerSession.getProcess().getProcessHandler();
DebugProcessImpl process = (DebugProcessImpl)DebuggerManagerEx.getInstanceEx(myProject)
- .getDebugProcess(executionResult.getProcessHandler());
+ .getDebugProcess(processHandler);
assertNotNull(process);
return debuggerSession;
@@ -319,7 +316,7 @@ public abstract class DebuggerTestCase extends ExecutionWithDebuggerToolsTestCas
}
}
});
- debuggerSession[0].getProcess().getExecutionResult().getProcessHandler().addProcessListener(new ProcessAdapter() {
+ debuggerSession[0].getProcess().getProcessHandler().addProcessListener(new ProcessAdapter() {
@Override
public void onTextAvailable(ProcessEvent event, Key outputType) {
print(event.getText(), outputType);
diff --git a/java/testFramework/src/com/intellij/debugger/ExecutionWithDebuggerToolsTestCase.java b/java/testFramework/src/com/intellij/debugger/ExecutionWithDebuggerToolsTestCase.java
index f295ee6dd40e..c4f7d920969d 100644
--- a/java/testFramework/src/com/intellij/debugger/ExecutionWithDebuggerToolsTestCase.java
+++ b/java/testFramework/src/com/intellij/debugger/ExecutionWithDebuggerToolsTestCase.java
@@ -26,7 +26,6 @@ import com.intellij.debugger.impl.PositionUtil;
import com.intellij.debugger.impl.PrioritizedTask;
import com.intellij.debugger.impl.SynchronizationBasedSemaphore;
import com.intellij.debugger.jdi.StackFrameProxyImpl;
-import com.intellij.debugger.settings.DebuggerSettings;
import com.intellij.debugger.ui.breakpoints.Breakpoint;
import com.intellij.debugger.ui.breakpoints.BreakpointManager;
import com.intellij.execution.ExecutionException;
@@ -62,7 +61,7 @@ public abstract class ExecutionWithDebuggerToolsTestCase extends ExecutionTestCa
private final SynchronizationBasedSemaphore myScriptRunnablesSema = new SynchronizationBasedSemaphore();
protected static final int RATHER_LATER_INVOKES_N = 10;
public DebugProcessImpl myDebugProcess = null;
- private final CompositeException exception = new CompositeException();
+ private final CompositeException myException = new CompositeException();
private class InvokeRatherLaterRequest {
private final DebuggerCommandImpl myDebuggerCommand;
@@ -107,7 +106,9 @@ public abstract class ExecutionWithDebuggerToolsTestCase extends ExecutionTestCa
@Override
protected void tearDown() throws Exception {
super.tearDown();
- if (!exception.isEmpty()) throw exception;
+ synchronized (myException) {
+ if (!myException.isEmpty()) throw myException;
+ }
}
protected void onBreakpoint(SuspendContextRunnable runnable) {
@@ -131,11 +132,11 @@ public abstract class ExecutionWithDebuggerToolsTestCase extends ExecutionTestCa
suspendContextRunnable.run(suspendContext);
}
catch (Exception e) {
- exception.add(e);
+ addException(e);
error(e);
}
catch (AssertionError e) {
- exception.add(e);
+ addException(e);
}
if (myScriptRunnables.isEmpty()) {
@@ -270,6 +271,11 @@ public abstract class ExecutionWithDebuggerToolsTestCase extends ExecutionTestCa
});
}
+ protected void addException(Throwable e) {
+ synchronized (myException) {
+ myException.add(e);
+ }
+ }
protected void error(Throwable th) {
fail(StringUtil.getThrowableText(th));
diff --git a/java/testFramework/src/com/intellij/testFramework/CompilerTester.java b/java/testFramework/src/com/intellij/testFramework/CompilerTester.java
index a3c05c6ec3fd..27f36509f60e 100644
--- a/java/testFramework/src/com/intellij/testFramework/CompilerTester.java
+++ b/java/testFramework/src/com/intellij/testFramework/CompilerTester.java
@@ -46,18 +46,24 @@ import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
/**
* @author peter
*/
public class CompilerTester {
-
- private Module myModule;
+ private Project myProject;
+ private List<Module> myModules;
private TempDirTestFixture myMainOutput;
public CompilerTester(Module module) throws Exception {
- myModule = module;
+ this(module.getProject(), Collections.singletonList(module));
+ }
+
+ public CompilerTester(Project project, List<Module> modules) throws Exception {
+ myProject = project;
+ myModules = modules;
myMainOutput = new TempDirTestFixtureImpl();
myMainOutput.setUp();
@@ -67,10 +73,11 @@ public class CompilerTester {
//noinspection ConstantConditions
CompilerProjectExtension.getInstance(getProject()).setCompilerOutputUrl(myMainOutput.findOrCreateDir("out").getUrl());
CompilerTestUtil.enableExternalCompiler();
- ModuleRootModificationUtil.setModuleSdk(myModule, JavaAwareProjectJdkTableImpl.getInstanceEx().getInternalJdk());
+ for (Module module : myModules) {
+ ModuleRootModificationUtil.setModuleSdk(module, JavaAwareProjectJdkTableImpl.getInstanceEx().getInternalJdk());
+ }
}
}.execute();
-
}
public void tearDown() {
@@ -84,12 +91,12 @@ public class CompilerTester {
}
finally {
myMainOutput = null;
- myModule = null;
+ myModules = null;
}
}
private Project getProject() {
- return myModule.getProject();
+ return myProject;
}
public void deleteClassFile(final String className) throws IOException {
@@ -173,6 +180,15 @@ public class CompilerTester {
});
}
+ public List<CompilerMessage> make(final CompileScope scope) {
+ return runCompiler(new Consumer<ErrorReportingCallback>() {
+ @Override
+ public void consume(ErrorReportingCallback callback) {
+ CompilerManager.getInstance(getProject()).make(scope, callback);
+ }
+ });
+ }
+
public List<CompilerMessage> compileFiles(final VirtualFile... files) {
return runCompiler(new Consumer<ErrorReportingCallback>() {
@Override
@@ -192,11 +208,13 @@ public class CompilerTester {
try {
getProject().save();
CompilerTestUtil.saveApplicationSettings();
- final VirtualFile moduleFile = myModule.getModuleFile();
- File ioFile = VfsUtil.virtualToIoFile(moduleFile);
- if (!ioFile.exists()) {
- getProject().save();
- assert ioFile.exists() : "File does not exist: " + ioFile.getPath();
+ for (Module module : myModules) {
+ final VirtualFile moduleFile = module.getModuleFile();
+ File ioFile = VfsUtil.virtualToIoFile(moduleFile);
+ if (!ioFile.exists()) {
+ getProject().save();
+ assert ioFile.exists() : "File does not exist: " + ioFile.getPath();
+ }
}
runnable.consume(callback);
}
diff --git a/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ChangeClassParametersIntention.java b/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ChangeClassParametersIntention.java
index 9571807cd229..b65e5364f57b 100644
--- a/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ChangeClassParametersIntention.java
+++ b/java/typeMigration/src/com/intellij/refactoring/typeMigration/intentions/ChangeClassParametersIntention.java
@@ -48,7 +48,9 @@ public class ChangeClassParametersIntention extends PsiElementBaseIntentionActio
final PsiMember member = PsiTreeUtil.getParentOfType(parameterList, PsiMember.class);
if (member instanceof PsiAnonymousClass) {
final PsiClassType.ClassResolveResult result = ((PsiAnonymousClass)member).getBaseClassType().resolveGenerics();
- return result.getElement() != null && ((PsiAnonymousClass)member).getBaseClassReference().getParameterList() == parameterList;
+ final PsiClass baseClass = result.getElement();
+ return baseClass != null && baseClass.getTypeParameters().length == parameterList.getTypeParameterElements().length &&
+ ((PsiAnonymousClass)member).getBaseClassReference().getParameterList() == parameterList;
}
}
return false;
diff --git a/jps/jps-builders/jps-builders.iml b/jps/jps-builders/jps-builders.iml
index 993bfad6f750..cfafe90aa84a 100644
--- a/jps/jps-builders/jps-builders.iml
+++ b/jps/jps-builders/jps-builders.iml
@@ -31,7 +31,7 @@
<orderEntry type="library" name="Log4J" level="project" />
<orderEntry type="library" scope="TEST" name="JUnit4" level="project" />
<orderEntry type="module" module-name="testFramework" scope="TEST" />
- <orderEntry type="library" scope="RUNTIME" name="Eclipse" level="project" />
+ <orderEntry type="library" scope="TEST" name="Eclipse" level="project" />
<orderEntry type="module" module-name="jps-model-api" />
<orderEntry type="module" module-name="jps-model-serialization" />
<orderEntry type="module" module-name="jps-model-impl" />
diff --git a/jps/jps-builders/src/org/jetbrains/jps/api/GlobalOptions.java b/jps/jps-builders/src/org/jetbrains/jps/api/GlobalOptions.java
index b1f36a69cb1e..223d57a532f9 100644
--- a/jps/jps-builders/src/org/jetbrains/jps/api/GlobalOptions.java
+++ b/jps/jps-builders/src/org/jetbrains/jps/api/GlobalOptions.java
@@ -21,7 +21,6 @@ package org.jetbrains.jps.api;
*/
public interface GlobalOptions {
String USE_MEMORY_TEMP_CACHE_OPTION = "use.memory.temp.cache";
- String USE_EXTERNAL_JAVAC_OPTION = "use.external.javac.process";
String GENERATE_CLASSPATH_INDEX_OPTION = "generate.classpath.index";
String COMPILE_PARALLEL_OPTION = "compile.parallel";
String COMPILE_PARALLEL_MAX_THREADS_OPTION = "compile.parallel.max.threads";
diff --git a/jps/jps-builders/src/org/jetbrains/jps/cmdline/BuildMain.java b/jps/jps-builders/src/org/jetbrains/jps/cmdline/BuildMain.java
index 8634769222a0..befddeff6157 100644
--- a/jps/jps-builders/src/org/jetbrains/jps/cmdline/BuildMain.java
+++ b/jps/jps-builders/src/org/jetbrains/jps/cmdline/BuildMain.java
@@ -41,6 +41,7 @@ import org.jetbrains.jps.service.SharedThreadPool;
import java.io.*;
import java.net.InetSocketAddress;
import java.util.UUID;
+import java.util.concurrent.TimeUnit;
/**
* @author Eugene Zhuravlev
@@ -214,7 +215,7 @@ public class BuildMain {
public void run() {
//noinspection finally
try {
- ourEventLoopGroup.shutdownGracefully();
+ ourEventLoopGroup.shutdownGracefully(0, 15, TimeUnit.SECONDS);
}
finally {
System.exit(0);
diff --git a/jps/jps-builders/src/org/jetbrains/jps/cmdline/ClasspathBootstrap.java b/jps/jps-builders/src/org/jetbrains/jps/cmdline/ClasspathBootstrap.java
index 3e5d2514c5a2..030f083652d9 100644
--- a/jps/jps-builders/src/org/jetbrains/jps/cmdline/ClasspathBootstrap.java
+++ b/jps/jps-builders/src/org/jetbrains/jps/cmdline/ClasspathBootstrap.java
@@ -32,7 +32,7 @@ import net.n3.nanoxml.IXMLBuilder;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.builders.java.JavaCompilingTool;
import org.jetbrains.jps.builders.java.JavaSourceTransformer;
-import org.jetbrains.jps.javac.JavacServer;
+import org.jetbrains.jps.javac.ExternalJavacProcess;
import org.jetbrains.jps.model.JpsModel;
import org.jetbrains.jps.model.impl.JpsModelImpl;
import org.jetbrains.jps.model.serialization.JpsProjectLoader;
@@ -145,6 +145,8 @@ public class ClasspathBootstrap {
cp.add(getResourcePath(NotNullVerifyingInstrumenter.class)); // not-null
cp.add(getResourcePath(IXMLBuilder.class)); // nano-xml
cp.add(getResourcePath(SequenceLock.class)); // jsr166
+ cp.add(getJpsPluginSystemClassesPath().getAbsolutePath().replace('\\', '/'));
+
//don't forget to update layoutCommunityJps() in layouts.gant accordingly
if (!isLauncherUsed) {
@@ -176,9 +178,9 @@ public class ClasspathBootstrap {
}
}
- public static List<File> getJavacServerClasspath(String sdkHome, JavaCompilingTool compilingTool) {
+ public static List<File> getExternalJavacProcessClasspath(String sdkHome, JavaCompilingTool compilingTool) {
final Set<File> cp = new LinkedHashSet<File>();
- cp.add(getResourceFile(JavacServer.class)); // self
+ cp.add(getResourceFile(ExternalJavacProcess.class)); // self
// util
for (String path : PathManager.getUtilClassPath()) {
cp.add(new File(path));
@@ -187,7 +189,8 @@ public class ClasspathBootstrap {
cp.add(getResourceFile(JpsModelImpl.class)); // jps-model-impl
cp.add(getResourceFile(Message.class)); // protobuf
cp.add(getResourceFile(NetUtil.class)); // netty
-
+ cp.add(getJpsPluginSystemClassesPath());
+
final Class<StandardJavaFileManager> optimizedFileManagerClass = getOptimizedFileManagerClass();
if (optimizedFileManagerClass != null) {
cp.add(getResourceFile(optimizedFileManagerClass)); // optimizedFileManager, if applicable
@@ -201,38 +204,33 @@ public class ClasspathBootstrap {
LOG.info(th);
}
- final JavaCompiler systemCompiler = ToolProvider.getSystemJavaCompiler();
- if (systemCompiler != null) {
- try {
- final String localJarPath = FileUtil.toSystemIndependentName(getResourceFile(systemCompiler.getClass()).getPath());
- final String localJavaHome = FileUtil.toSystemIndependentName(SystemProperties.getJavaHome());
- if (FileUtil.pathsEqual(localJavaHome, FileUtil.toSystemIndependentName(sdkHome))) {
- cp.add(new File(localJarPath));
- }
- else {
- // sdkHome is not the same as the sdk used to run this process
- final File candidate = new File(sdkHome, "lib/tools.jar");
- if (candidate.exists()) {
- cp.add(candidate);
- }
- else {
- // last resort
- String relPath = FileUtil.getRelativePath(localJavaHome, localJarPath, '/');
+ try {
+ final String localJavaHome = FileUtil.toSystemIndependentName(SystemProperties.getJavaHome());
+ // sdkHome is not the same as the sdk used to run this process
+ final File candidate = new File(sdkHome, "lib/tools.jar");
+ if (candidate.exists()) {
+ cp.add(candidate);
+ }
+ else {
+ // last resort
+ final JavaCompiler systemCompiler = ToolProvider.getSystemJavaCompiler();
+ if (systemCompiler != null) {
+ final String localJarPath = FileUtil.toSystemIndependentName(getResourceFile(systemCompiler.getClass()).getPath());
+ String relPath = FileUtil.getRelativePath(localJavaHome, localJarPath, '/');
+ if (relPath != null) {
+ if (relPath.contains("..")) {
+ relPath = FileUtil.getRelativePath(FileUtil.toSystemIndependentName(new File(localJavaHome).getParent()), localJarPath, '/');
+ }
if (relPath != null) {
- if (relPath.contains("..")) {
- relPath = FileUtil.getRelativePath(FileUtil.toSystemIndependentName(new File(localJavaHome).getParent()), localJarPath, '/');
- }
- if (relPath != null) {
- final File targetFile = new File(sdkHome, relPath);
- cp.add(targetFile); // tools.jar
- }
+ final File targetFile = new File(sdkHome, relPath);
+ cp.add(targetFile); // tools.jar
}
}
}
}
- catch (Throwable th) {
- LOG.info(th);
- }
+ }
+ catch (Throwable th) {
+ LOG.info(th);
}
cp.addAll(compilingTool.getAdditionalClasspath());
@@ -286,4 +284,16 @@ public class ClasspathBootstrap {
public static File getResourceFile(Class aClass) {
return new File(getResourcePath(aClass));
}
+
+ private static File getJpsPluginSystemClassesPath() {
+ File classesRoot = new File(getResourcePath(ClasspathBootstrap.class));
+ if (classesRoot.isDirectory()) {
+ //running from sources: load classes from .../out/production/jps-plugin-system
+ return new File(classesRoot.getParentFile(), "jps-plugin-system");
+ }
+ else {
+ return new File(classesRoot.getParentFile(), "rt/jps-plugin-system.jar");
+ }
+ }
+
}
diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java
index 88fdef9eaad2..f13664ec3c8a 100644
--- a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java
+++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java
@@ -36,7 +36,6 @@ import org.jetbrains.jps.ModuleChunk;
import org.jetbrains.jps.TimingLog;
import org.jetbrains.jps.api.CanceledStatus;
import org.jetbrains.jps.api.GlobalOptions;
-import org.jetbrains.jps.api.RequestFuture;
import org.jetbrains.jps.builders.*;
import org.jetbrains.jps.builders.impl.BuildOutputConsumerImpl;
import org.jetbrains.jps.builders.impl.BuildTargetChunk;
@@ -50,12 +49,12 @@ import org.jetbrains.jps.builders.storage.SourceToOutputMapping;
import org.jetbrains.jps.cmdline.BuildRunner;
import org.jetbrains.jps.cmdline.ProjectDescriptor;
import org.jetbrains.jps.incremental.fs.BuildFSState;
-import org.jetbrains.jps.incremental.java.ExternalJavacDescriptor;
import org.jetbrains.jps.incremental.messages.*;
import org.jetbrains.jps.incremental.storage.BuildTargetConfiguration;
import org.jetbrains.jps.incremental.storage.OneToManyPathsMapping;
import org.jetbrains.jps.incremental.storage.OutputToTargetRegistry;
import org.jetbrains.jps.indices.ModuleExcludeIndex;
+import org.jetbrains.jps.javac.ExternalJavacServer;
import org.jetbrains.jps.javac.JavacMain;
import org.jetbrains.jps.model.java.JpsJavaExtensionService;
import org.jetbrains.jps.model.java.compiler.JpsJavaCompilerConfiguration;
@@ -313,17 +312,10 @@ public class IncProjectBuilder {
pd.timestamps.getStorage().force();
pd.dataManager.flush(false);
}
- final ExternalJavacDescriptor descriptor = ExternalJavacDescriptor.KEY.get(context);
- if (descriptor != null) {
- try {
- final RequestFuture future = descriptor.client.sendShutdownRequest();
- future.waitFor(500L, TimeUnit.MILLISECONDS);
- }
- finally {
- // ensure process is not running
- descriptor.process.destroyProcess();
- }
- ExternalJavacDescriptor.KEY.set(context, null);
+ final ExternalJavacServer server = ExternalJavacServer.KEY.get(context);
+ if (server != null) {
+ server.stop();
+ ExternalJavacServer.KEY.set(context, null);
}
}
diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/impl/JarsBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/impl/JarsBuilder.java
index ba43cc7ea05e..c5ce16567be4 100644
--- a/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/impl/JarsBuilder.java
+++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/impl/JarsBuilder.java
@@ -181,7 +181,7 @@ public class JarsBuilder {
packedFilePaths, -1);
}
else {
- LOG.debug("nested jar file " + relativePath + " for " + jar.getPresentableDestination() + " not found");
+ LOG.debug("nested JAR file " + relativePath + " for " + jar.getPresentableDestination() + " not found");
}
}
}
diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/ExternalJavacDescriptor.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/ExternalJavacDescriptor.java
deleted file mode 100644
index b8882decdf4d..000000000000
--- a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/ExternalJavacDescriptor.java
+++ /dev/null
@@ -1,36 +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 org.jetbrains.jps.incremental.java;
-
-import com.intellij.execution.process.BaseOSProcessHandler;
-import org.jetbrains.jps.incremental.GlobalContextKey;
-import org.jetbrains.jps.javac.JavacServerClient;
-
-/**
- * @author Eugene Zhuravlev
- * Date: 1/24/12
- */
-public class ExternalJavacDescriptor {
- public static final GlobalContextKey<ExternalJavacDescriptor> KEY = GlobalContextKey.create("_external_javac_descriptor_");
-
- public final BaseOSProcessHandler process;
- public final JavacServerClient client;
-
- public ExternalJavacDescriptor(BaseOSProcessHandler process, JavacServerClient client) {
- this.process = process;
- this.client = client;
- }
-}
diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java
index 77538c6b6881..94b00d9838a1 100644
--- a/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java
+++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/java/JavaBuilder.java
@@ -15,7 +15,6 @@
*/
package org.jetbrains.jps.incremental.java;
-import com.intellij.execution.process.BaseOSProcessHandler;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Key;
@@ -32,8 +31,6 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.ModuleChunk;
import org.jetbrains.jps.ProjectPaths;
-import org.jetbrains.jps.api.GlobalOptions;
-import org.jetbrains.jps.api.RequestFuture;
import org.jetbrains.jps.builders.BuildRootIndex;
import org.jetbrains.jps.builders.DirtyFilesHolder;
import org.jetbrains.jps.builders.FileProcessor;
@@ -63,13 +60,11 @@ import org.jetbrains.jps.model.module.JpsModule;
import org.jetbrains.jps.model.module.JpsModuleType;
import org.jetbrains.jps.service.JpsServiceManager;
-import javax.tools.Diagnostic;
-import javax.tools.JavaFileObject;
+import javax.tools.*;
import java.io.*;
import java.net.ServerSocket;
import java.util.*;
import java.util.concurrent.Executor;
-import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
/**
@@ -81,7 +76,6 @@ public class JavaBuilder extends ModuleLevelBuilder {
public static final String BUILDER_NAME = "java";
private static final String JAVA_EXTENSION = "java";
private static final String DOT_JAVA_EXTENSION = "." + JAVA_EXTENSION;
- public static final boolean USE_EMBEDDED_JAVAC = System.getProperty(GlobalOptions.USE_EXTERNAL_JAVAC_OPTION) == null;
private static final Key<Integer> JAVA_COMPILER_VERSION_KEY = Key.create("_java_compiler_version_");
public static final Key<Boolean> IS_ENABLED = Key.create("_java_compiler_enabled_");
private static final Key<JavaCompilingTool> COMPILING_TOOL = Key.create("_java_compiling_tool_");
@@ -396,7 +390,7 @@ public class JavaBuilder extends ModuleLevelBuilder {
}
try {
final boolean rc;
- if (USE_EMBEDDED_JAVAC) {
+ if (!shouldForkCompilerProcess(context, chunk, compilingTool)) {
final Collection<File> _platformCp = calcEffectivePlatformCp(platformCp, options, compilingTool);
if (_platformCp == null) {
diagnosticSink.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR,
@@ -409,16 +403,18 @@ public class JavaBuilder extends ModuleLevelBuilder {
);
}
else {
- final JavacServerClient client = ensureJavacServerLaunched(context, compilingTool);
- final RequestFuture<JavacServerResponseHandler> future = client.sendCompileRequest(
- options, files, classpath, platformCp, sourcePath, outs, diagnosticSink, classesConsumer
- );
- while (!future.waitFor(100L, TimeUnit.MILLISECONDS)) {
- if (context.getCancelStatus().isCanceled()) {
- future.cancel(false);
- }
+ // fork external javac
+ final String sdkHome = getChunkSdkHome(chunk);
+ if (sdkHome == null) {
+ diagnosticSink.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, "Cannot start javac process for " + chunk.getName() + ": unknown JDK home path.\nPlease check project configuration."));
+ return true;
}
- rc = future.getMessageHandler().isTerminatedSuccessfully();
+
+ final List<String> vmOptions = getCompilationVMOptions(context, compilingTool);
+ final ExternalJavacServer server = ensureJavacServerStarted(context);
+ rc = server.forkJavac(
+ context, options, vmOptions, files, classpath, platformCp, sourcePath, outs, diagnosticSink, classesConsumer, sdkHome, compilingTool
+ );
}
return rc;
}
@@ -426,6 +422,20 @@ public class JavaBuilder extends ModuleLevelBuilder {
counter.await();
}
}
+
+ private static boolean shouldForkCompilerProcess(CompileContext context, ModuleChunk chunk, JavaCompilingTool tool) {
+ final int compilerSdkVersion = getCompilerSdkVersion(context);
+ if (compilerSdkVersion < 9) {
+ // javac up to version 9 supports all previous releases
+ return false;
+ }
+ final int chunkSdkVersion = getChunkSdkVersion(chunk);
+ if (chunkSdkVersion < 0) {
+ return false; // was not able to determine jdk version, assuming in-process compiler
+ }
+ // according to JEP 182: Retiring javac "one plus three back" policy
+ return Math.abs(compilerSdkVersion - chunkSdkVersion) > 3;
+ }
// If platformCp of the build process is the same as the target plafform, do not specify platformCp explicitly
// this will allow javac to resolve against ct.sym file, which is required for the "compilation profiles" feature
@@ -482,31 +492,16 @@ public class JavaBuilder extends ModuleLevelBuilder {
});
}
- private static synchronized JavacServerClient ensureJavacServerLaunched(@NotNull CompileContext context, @NotNull JavaCompilingTool compilingTool) throws Exception {
- final ExternalJavacDescriptor descriptor = ExternalJavacDescriptor.KEY.get(context);
- if (descriptor != null) {
- return descriptor.client;
+ private static synchronized ExternalJavacServer ensureJavacServerStarted(@NotNull CompileContext context) throws Exception {
+ ExternalJavacServer server = ExternalJavacServer.KEY.get(context);
+ if (server != null) {
+ return server;
}
- // start server here
- final int port = findFreePort();
- final int heapSize = getJavacServerHeapSize(context);
-
- // use the same jdk that used to run the build process
- final String javaHome = SystemProperties.getJavaHome();
-
- final BaseOSProcessHandler processHandler = JavacServerBootstrap.launchJavacServer(
- javaHome, heapSize, port, Utils.getSystemRoot(), getCompilationVMOptions(context, compilingTool), compilingTool
- );
- final JavacServerClient client = new JavacServerClient();
- try {
- client.connect("127.0.0.1", port);
- }
- catch (Throwable ex) {
- processHandler.destroyProcess();
- throw new Exception("Failed to connect to external javac process: ", ex);
- }
- ExternalJavacDescriptor.KEY.set(context, new ExternalJavacDescriptor(processHandler, client));
- return client;
+ final int listenPort = findFreePort();
+ server = new ExternalJavacServer();
+ server.start(listenPort);
+ ExternalJavacServer.KEY.set(context, server);
+ return server;
}
private static int convertToNumber(String ver) {
@@ -564,17 +559,10 @@ public class JavaBuilder extends ModuleLevelBuilder {
}
catch (IOException e) {
e.printStackTrace(System.err);
- return JavacServer.DEFAULT_SERVER_PORT;
+ return ExternalJavacServer.DEFAULT_SERVER_PORT;
}
}
- private static int getJavacServerHeapSize(CompileContext context) {
- final JpsProject project = context.getProjectDescriptor().getProject();
- final JpsJavaCompilerConfiguration config = JpsJavaExtensionService.getInstance().getOrCreateCompilerConfiguration(project);
- final JpsJavaCompilerOptions options = config.getCurrentCompilerOptions();
- return options.MAXIMUM_HEAP_SIZE;
- }
-
private static final Key<List<String>> JAVAC_OPTIONS = Key.create("_javac_options_");
private static final Key<List<String>> JAVAC_VM_OPTIONS = Key.create("_javac_vm_options_");
private static final Key<String> USER_DEFINED_BYTECODE_TARGET = Key.create("_user_defined_bytecode_target_");
@@ -628,19 +616,12 @@ public class JavaBuilder extends ModuleLevelBuilder {
options.add(langLevel);
}
- JpsJavaCompilerConfiguration compilerConfiguration = JpsJavaExtensionService.getInstance().getOrCreateCompilerConfiguration(
- context.getProjectDescriptor().getProject());
+ final JpsJavaCompilerConfiguration compilerConfiguration = JpsJavaExtensionService.getInstance().getOrCreateCompilerConfiguration(
+ context.getProjectDescriptor().getProject()
+ );
+
String bytecodeTarget = null;
- int chunkSdkVersion = -1;
for (JpsModule module : chunk.getModules()) {
- final JpsSdk<JpsDummyElement> sdk = module.getSdk(JpsJavaSdkType.INSTANCE);
- if (sdk != null) {
- final int moduleSdkVersion = convertToNumber(sdk.getVersionString());
- if (moduleSdkVersion != 0 /*could determine the version*/&& (chunkSdkVersion < 0 || chunkSdkVersion > moduleSdkVersion)) {
- chunkSdkVersion = moduleSdkVersion;
- }
- }
-
final String moduleTarget = compilerConfiguration.getByteCodeTargetLevel(module.getName());
if (moduleTarget == null) {
continue;
@@ -662,6 +643,7 @@ public class JavaBuilder extends ModuleLevelBuilder {
}
final int compilerSdkVersion = getCompilerSdkVersion(context);
+ final int chunkSdkVersion = getChunkSdkVersion(chunk);
if (bytecodeTarget != null) {
options.add("-target");
@@ -721,17 +703,19 @@ public class JavaBuilder extends ModuleLevelBuilder {
}
private static String getLanguageLevel(JpsModule module) {
- LanguageLevel level = JpsJavaExtensionService.getInstance().getLanguageLevel(module);
- if (level == null) return null;
- switch (level) {
- case JDK_1_3: return "1.3";
- case JDK_1_4: return "1.4";
- case JDK_1_5: return "1.5";
- case JDK_1_6: return "1.6";
- case JDK_1_7: return "1.7";
- case JDK_1_8: return "8";
- default: return null;
+ final LanguageLevel level = JpsJavaExtensionService.getInstance().getLanguageLevel(module);
+ if (level != null) {
+ switch (level) {
+ case JDK_1_3: return "1.3";
+ case JDK_1_4: return "1.4";
+ case JDK_1_5: return "1.5";
+ case JDK_1_6: return "1.6";
+ case JDK_1_7: return "1.7";
+ case JDK_1_8: return "8";
+ case JDK_1_9: return "9";
+ }
}
+ return null;
}
private static boolean isEncodingSet(List<String> options) {
@@ -743,7 +727,6 @@ public class JavaBuilder extends ModuleLevelBuilder {
return false;
}
-
private static int getCompilerSdkVersion(CompileContext context) {
final Integer cached = JAVA_COMPILER_VERSION_KEY.get(context);
if (cached != null) {
@@ -754,6 +737,30 @@ public class JavaBuilder extends ModuleLevelBuilder {
return javaVersion;
}
+ private static int getChunkSdkVersion(ModuleChunk chunk) {
+ int chunkSdkVersion = -1;
+ for (JpsModule module : chunk.getModules()) {
+ final JpsSdk<JpsDummyElement> sdk = module.getSdk(JpsJavaSdkType.INSTANCE);
+ if (sdk != null) {
+ final int moduleSdkVersion = convertToNumber(sdk.getVersionString());
+ if (moduleSdkVersion != 0 /*could determine the version*/&& (chunkSdkVersion < 0 || chunkSdkVersion > moduleSdkVersion)) {
+ chunkSdkVersion = moduleSdkVersion;
+ }
+ }
+ }
+ return chunkSdkVersion;
+ }
+
+ private static String getChunkSdkHome(ModuleChunk chunk) {
+ for (JpsModule module : chunk.getModules()) {
+ final JpsSdk<JpsDummyElement> sdk = module.getSdk(JpsJavaSdkType.INSTANCE);
+ if (sdk != null) {
+ return sdk.getHomePath();
+ }
+ }
+ return null;
+ }
+
private static void loadCommonJavacOptions(@NotNull CompileContext context, @NotNull JavaCompilingTool compilingTool) {
final List<String> options = new ArrayList<String>();
final List<String> vmOptions = new ArrayList<String>();
diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/ExternalJavacMessageHandler.java b/jps/jps-builders/src/org/jetbrains/jps/javac/ExternalJavacMessageHandler.java
new file mode 100644
index 000000000000..fd5bc65d1e5b
--- /dev/null
+++ b/jps/jps-builders/src/org/jetbrains/jps/javac/ExternalJavacMessageHandler.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.jps.javac;
+
+import com.google.protobuf.ByteString;
+import com.google.protobuf.MessageLite;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.jps.incremental.BinaryContent;
+
+import javax.tools.*;
+import java.io.File;
+import java.net.URI;
+import java.util.Collection;
+import java.util.Locale;
+
+/**
+ * @author Eugene Zhuravlev
+ * Date: 1/22/12
+ */
+public class ExternalJavacMessageHandler {
+ private final DiagnosticOutputConsumer myDiagnosticSink;
+ private final OutputFileConsumer myOutputSink;
+ @Nullable
+ private final String myEncodingName;
+ private volatile boolean myTerminatedSuccessfully;
+
+ public ExternalJavacMessageHandler(DiagnosticOutputConsumer diagnosticSink,
+ OutputFileConsumer outputSink,
+ @Nullable final String encodingName) {
+ myDiagnosticSink = diagnosticSink;
+ myOutputSink = outputSink;
+ myEncodingName = encodingName;
+ }
+
+ public boolean handleMessage(MessageLite message) {
+ try {
+ final JavacRemoteProto.Message msg = (JavacRemoteProto.Message)message;
+ final JavacRemoteProto.Message.Type messageType = msg.getMessageType();
+
+ if (messageType == JavacRemoteProto.Message.Type.RESPONSE) {
+ final JavacRemoteProto.Message.Response response = msg.getResponse();
+ final JavacRemoteProto.Message.Response.Type responseType = response.getResponseType();
+
+ if (responseType == JavacRemoteProto.Message.Response.Type.BUILD_MESSAGE) {
+ final JavacRemoteProto.Message.Response.CompileMessage compileMessage = response.getCompileMessage();
+ final JavacRemoteProto.Message.Response.CompileMessage.Kind messageKind = compileMessage.getKind();
+
+ if (messageKind == JavacRemoteProto.Message.Response.CompileMessage.Kind.STD_OUT) {
+ if (compileMessage.hasText()) {
+ myDiagnosticSink.outputLineAvailable(compileMessage.getText());
+ }
+ }
+ else {
+ final String sourceUri = compileMessage.hasSourceUri()? compileMessage.getSourceUri() : null;
+ final JavaFileObject srcFileObject = sourceUri != null? new DummyJavaFileObject(URI.create(sourceUri)) : null;
+ myDiagnosticSink.report(new DummyDiagnostic(convertKind(messageKind), srcFileObject, compileMessage));
+ }
+
+ return false;
+ }
+
+ if (responseType == JavacRemoteProto.Message.Response.Type.OUTPUT_OBJECT) {
+ final JavacRemoteProto.Message.Response.OutputObject outputObject = response.getOutputObject();
+ final JavacRemoteProto.Message.Response.OutputObject.Kind kind = outputObject.getKind();
+
+ final String outputRoot = outputObject.hasOutputRoot()? outputObject.getOutputRoot() : null;
+ final File outputRootFile = outputRoot != null? new File(outputRoot) : null;
+
+ final BinaryContent fileObjectContent;
+ final ByteString content = outputObject.hasContent()? outputObject.getContent() : null;
+ if (content != null) {
+ final byte[] bytes = content.toByteArray();
+ fileObjectContent = new BinaryContent(bytes, 0, bytes.length);
+ }
+ else {
+ fileObjectContent = null;
+ }
+
+ final String sourceUri = outputObject.hasSourceUri()? outputObject.getSourceUri() : null;
+ final URI srcUri = sourceUri != null? URI.create(sourceUri) : null;
+ final OutputFileObject fileObject = new OutputFileObject(
+ null,
+ outputRootFile,
+ outputObject.hasRelativePath()? outputObject.getRelativePath() : null,
+ new File(outputObject.getFilePath()),
+ convertKind(kind),
+ outputObject.hasClassName()? outputObject.getClassName() : null,
+ srcUri,
+ myEncodingName, fileObjectContent
+ );
+
+ myOutputSink.save(fileObject);
+ return false;
+ }
+
+ if (responseType == JavacRemoteProto.Message.Response.Type.SRC_FILE_LOADED) {
+ final JavacRemoteProto.Message.Response.OutputObject outputObject = response.getOutputObject();
+ final File file = new File(outputObject.getFilePath());
+ myDiagnosticSink.javaFileLoaded(file);
+ return false;
+ }
+
+ if (responseType == JavacRemoteProto.Message.Response.Type.CLASS_DATA) {
+ final JavacRemoteProto.Message.Response.ClassData data = response.getClassData();
+ final String className = data.getClassName();
+ final Collection<String> imports = data.getImportStatementList();
+ final Collection<String> staticImports = data.getStaticImportList();
+ myDiagnosticSink.registerImports(className, imports, staticImports);
+ return false;
+ }
+
+ if (responseType == JavacRemoteProto.Message.Response.Type.BUILD_COMPLETED) {
+ if (response.hasCompletionStatus()) {
+ myTerminatedSuccessfully = response.getCompletionStatus();
+ }
+ return true;
+ }
+
+ throw new Exception("Unsupported response type: " + responseType.name());
+ }
+
+ if (messageType == JavacRemoteProto.Message.Type.FAILURE) {
+ final JavacRemoteProto.Message.Failure failure = msg.getFailure();
+ final StringBuilder buf = new StringBuilder();
+ if (failure.hasDescription()) {
+ buf.append(failure.getDescription());
+ }
+ if (failure.hasStacktrace()) {
+ if (buf.length() > 0) {
+ buf.append("\n");
+ }
+ buf.append(failure.getStacktrace());
+ }
+ myDiagnosticSink.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, buf.toString()));
+ return true;
+ }
+
+ throw new Exception("Unsupported message type: " + messageType.name());
+ }
+ catch (Throwable e) {
+ myDiagnosticSink.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, e.getMessage()));
+ return true;
+ }
+ }
+
+ public boolean isTerminatedSuccessfully() {
+ return myTerminatedSuccessfully;
+ }
+
+ private static Diagnostic.Kind convertKind(JavacRemoteProto.Message.Response.CompileMessage.Kind kind) {
+ switch (kind) {
+ case ERROR: return Diagnostic.Kind.ERROR;
+ case WARNING: return Diagnostic.Kind.WARNING;
+ case MANDATORY_WARNING: return Diagnostic.Kind.MANDATORY_WARNING;
+ case NOTE: return Diagnostic.Kind.NOTE;
+ default : return Diagnostic.Kind.OTHER;
+ }
+ }
+
+ private static OutputFileObject.Kind convertKind(JavacRemoteProto.Message.Response.OutputObject.Kind kind) {
+ switch (kind) {
+ case CLASS: return JavaFileObject.Kind.CLASS;
+ case HTML: return JavaFileObject.Kind.HTML;
+ case SOURCE: return JavaFileObject.Kind.SOURCE;
+ default : return JavaFileObject.Kind.OTHER;
+ }
+ }
+
+ private static class DummyDiagnostic implements Diagnostic<JavaFileObject> {
+
+ private final Kind myMessageKind;
+ private final JavaFileObject mySrcFileObject;
+ private final JavacRemoteProto.Message.Response.CompileMessage myCompileMessage;
+
+ public DummyDiagnostic(final Kind messageKind, JavaFileObject srcFileObject, JavacRemoteProto.Message.Response.CompileMessage compileMessage) {
+ myMessageKind = messageKind;
+ mySrcFileObject = srcFileObject;
+ myCompileMessage = compileMessage;
+ }
+
+ public Kind getKind() {
+ return myMessageKind;
+ }
+
+ public JavaFileObject getSource() {
+ return mySrcFileObject;
+ }
+
+ public long getPosition() {
+ return myCompileMessage.hasProblemLocationOffset()? myCompileMessage.getProblemLocationOffset() : -1;
+ }
+
+ public long getStartPosition() {
+ return myCompileMessage.hasProblemBeginOffset()? myCompileMessage.getProblemBeginOffset() : -1;
+ }
+
+ public long getEndPosition() {
+ return myCompileMessage.hasProblemEndOffset()? myCompileMessage.getProblemEndOffset() : -1;
+ }
+
+ public long getLineNumber() {
+ return myCompileMessage.hasLine()? myCompileMessage.getLine() : -1;
+ }
+
+ public long getColumnNumber() {
+ return myCompileMessage.hasColumn()? myCompileMessage.getColumn() : -1;
+ }
+
+ public String getCode() {
+ return null;
+ }
+
+ public String getMessage(Locale locale) {
+ return myCompileMessage.hasText()? myCompileMessage.getText() : null;
+ }
+ }
+}
diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServer.java b/jps/jps-builders/src/org/jetbrains/jps/javac/ExternalJavacProcess.java
index 0ecfe7617160..d01ae7af6b4d 100644
--- a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServer.java
+++ b/jps/jps-builders/src/org/jetbrains/jps/javac/ExternalJavacProcess.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,18 +15,19 @@
*/
package org.jetbrains.jps.javac;
-import io.netty.bootstrap.ServerBootstrap;
+import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
-import io.netty.channel.group.ChannelGroup;
-import io.netty.channel.group.ChannelGroupFuture;
-import io.netty.channel.group.DefaultChannelGroup;
import io.netty.channel.nio.NioEventLoopGroup;
-import io.netty.channel.socket.nio.NioServerSocketChannel;
+import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.protobuf.ProtobufDecoder;
import io.netty.handler.codec.protobuf.ProtobufEncoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;
-import io.netty.util.concurrent.ImmediateEventExecutor;
+import io.netty.util.internal.logging.InternalLoggerFactory;
+import io.netty.util.internal.logging.Log4JLoggerFactory;
+import org.apache.log4j.ConsoleAppender;
+import org.apache.log4j.Level;
+import org.apache.log4j.PatternLayout;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.api.CanceledStatus;
import org.jetbrains.jps.builders.impl.java.JavacCompilerTool;
@@ -37,85 +38,109 @@ import org.jetbrains.jps.service.SharedThreadPool;
import javax.tools.*;
import java.io.File;
import java.util.*;
+import java.util.concurrent.TimeUnit;
/**
* @author Eugene Zhuravlev
* Date: 1/22/12
*/
-@SuppressWarnings("UseOfSystemOutOrSystemErr")
-public class JavacServer {
- public static final int DEFAULT_SERVER_PORT = 7878;
- public static final String SERVER_SUCCESS_START_MESSAGE = "Javac server started successfully. Listening on port: ";
- public static final String SERVER_ERROR_START_MESSAGE = "Error starting Javac Server: ";
+public class ExternalJavacProcess {
public static final String JPS_JAVA_COMPILING_TOOL_PROPERTY = "jps.java.compiling.tool";
-
- private ChannelRegistrar myChannelRegistrar;
-
- public void start(int listenPort) {
- final ServerBootstrap bootstrap = new ServerBootstrap().group(new NioEventLoopGroup(1, SharedThreadPool.getInstance())).channel(NioServerSocketChannel.class);
- bootstrap.childOption(ChannelOption.TCP_NODELAY, true).childOption(ChannelOption.SO_KEEPALIVE, true);
- myChannelRegistrar = new ChannelRegistrar();
- final ChannelHandler compilationRequestsHandler = new CompilationRequestsHandler();
- bootstrap.childHandler(new ChannelInitializer() {
+ private final ChannelInitializer myChannelInitializer;
+ private final EventLoopGroup myEventLoopGroup;
+ private volatile ChannelFuture myConnectFuture;
+ private volatile CancelHandler myCancelHandler;
+
+ static {
+ org.apache.log4j.Logger root = org.apache.log4j.Logger.getRootLogger();
+ if (!root.getAllAppenders().hasMoreElements()) {
+ root.setLevel(Level.INFO);
+ root.addAppender(new ConsoleAppender(new PatternLayout(PatternLayout.DEFAULT_CONVERSION_PATTERN)));
+ }
+ InternalLoggerFactory.setDefaultFactory(new Log4JLoggerFactory());
+ }
+
+ public ExternalJavacProcess() {
+ final JavacRemoteProto.Message msgDefaultInstance = JavacRemoteProto.Message.getDefaultInstance();
+
+ myEventLoopGroup = new NioEventLoopGroup(1, SharedThreadPool.getInstance());
+ myChannelInitializer = new ChannelInitializer() {
@Override
protected void initChannel(Channel channel) throws Exception {
- channel.pipeline().addLast(myChannelRegistrar,
- new ProtobufVarint32FrameDecoder(),
- new ProtobufDecoder(JavacRemoteProto.Message.getDefaultInstance()),
+ channel.pipeline().addLast(new ProtobufVarint32FrameDecoder(),
+ new ProtobufDecoder(msgDefaultInstance),
new ProtobufVarint32LengthFieldPrepender(),
new ProtobufEncoder(),
- compilationRequestsHandler);
+ new CompilationRequestsHandler()
+ );
}
- });
- myChannelRegistrar.add(bootstrap.bind(listenPort).syncUninterruptibly().channel());
- }
-
- public void stop() {
- myChannelRegistrar.close().awaitUninterruptibly();
+ };
}
-
+
+ //static volatile long myGlobalStart;
+
public static void main(String[] args) {
- JavacServer server = null;
- try {
- int port = DEFAULT_SERVER_PORT;
- if (args.length > 0) {
- try {
- port = Integer.parseInt(args[0]);
- }
- catch (NumberFormatException e) {
- System.err.println("Error parsing port: " + e.getMessage());
- System.exit(-1);
- }
+ //myGlobalStart = System.currentTimeMillis();
+ UUID uuid = null;
+ String host = null;
+ int port = -1;
+ if (args.length > 0) {
+ try {
+ uuid = UUID.fromString(args[0]);
}
-
- server = new JavacServer();
- server.start(port);
- final JavacServer finalServer = server;
- Runtime.getRuntime().addShutdownHook(new Thread("Shutdown hook thread") {
- @Override
- public void run() {
- finalServer.stop();
- }
- });
-
- System.out.println("Server classpath: " + System.getProperty("java.class.path"));
- System.err.println(SERVER_SUCCESS_START_MESSAGE + port);
- }
- catch (Throwable e) {
- System.err.println(SERVER_ERROR_START_MESSAGE + e.getMessage());
- e.printStackTrace(System.err);
+ catch (Exception e) {
+ System.err.println("Error parsing session id: " + e.getMessage());
+ System.exit(-1);
+ }
+
+ host = args[1];
+
try {
- if (server != null) {
- server.stop();
- }
+ port = Integer.parseInt(args[2]);
}
- finally {
+ catch (NumberFormatException e) {
+ System.err.println("Error parsing port: " + e.getMessage());
System.exit(-1);
}
}
+ else {
+ System.err.println("Insufficient parameters");
+ System.exit(-1);
+ }
+
+ final ExternalJavacProcess process = new ExternalJavacProcess();
+ try {
+ //final long connectStart = System.currentTimeMillis();
+ if (process.connect(host, port)) {
+ //final long connectEnd = System.currentTimeMillis();
+ //System.err.println("Connected in " + (connectEnd - connectStart) + " ms; since start: " + (connectEnd - myGlobalStart));
+ process.myConnectFuture.channel().writeAndFlush(
+ JavacProtoUtil.toMessage(uuid, JavacProtoUtil.createRequestAckResponse())
+ );
+ }
+ else {
+ System.err.println("Failed to connect to parent process");
+ System.exit(-1);
+ }
+ }
+ catch (Throwable throwable) {
+ throwable.printStackTrace(System.err);
+ System.exit(-1);
+ }
}
- public static JavacRemoteProto.Message compile(final ChannelHandlerContext context,
+ private boolean connect(final String host, final int port) throws Throwable {
+ final Bootstrap bootstrap = new Bootstrap().group(myEventLoopGroup).channel(NioSocketChannel.class).handler(myChannelInitializer);
+ bootstrap.option(ChannelOption.TCP_NODELAY, true).option(ChannelOption.SO_KEEPALIVE, true);
+ final ChannelFuture future = bootstrap.connect(host, port).syncUninterruptibly();
+ if (future.isSuccess()) {
+ myConnectFuture = future;
+ return true;
+ }
+ return false;
+ }
+
+ private static JavacRemoteProto.Message compile(final ChannelHandlerContext context,
final UUID sessionId,
List<String> options,
Collection<File> files,
@@ -124,6 +149,8 @@ public class JavacServer {
Collection<File> sourcePath,
Map<File, Set<File>> outs,
final CanceledStatus canceledStatus) {
+ //final long compileStart = System.currentTimeMillis();
+ //System.err.println("Compile start; since global start: " + (compileStart - myGlobalStart));
final DiagnosticOutputConsumer diagnostic = new DiagnosticOutputConsumer() {
@Override
public void javaFileLoaded(File file) {
@@ -157,7 +184,8 @@ public class JavacServer {
try {
JavaCompilingTool tool = getCompilingTool();
- final boolean rc = JavacMain.compile(options, files, classpath, platformCp, sourcePath, outs, diagnostic, outputSink, canceledStatus, tool);
+ final boolean rc = JavacMain.compile(options, files, classpath, platformCp, sourcePath, outs, diagnostic, outputSink, canceledStatus,
+ tool);
return JavacProtoUtil.toMessage(sessionId, JavacProtoUtil.createBuildCompletedResponse(rc));
}
catch (Throwable e) {
@@ -165,8 +193,12 @@ public class JavacServer {
e.printStackTrace(System.err);
return JavacProtoUtil.toMessage(sessionId, JavacProtoUtil.createFailure(e.getMessage(), e));
}
+ //finally {
+ // final long compileEnd = System.currentTimeMillis();
+ // System.err.println("Compiled in " + (compileEnd - compileStart) + " ms; since global start: " + (compileEnd - myGlobalStart));
+ //}
}
-
+
private static JavaCompilingTool getCompilingTool() {
String property = System.getProperty(JPS_JAVA_COMPILING_TOOL_PROPERTY);
if (property != null) {
@@ -178,24 +210,6 @@ public class JavacServer {
return new JavacCompilerTool();
}
- private final Set<CancelHandler> myCancelHandlers = Collections.synchronizedSet(new HashSet<CancelHandler>());
-
- public void cancelBuilds() {
- synchronized (myCancelHandlers) {
- for (CancelHandler handler : myCancelHandlers) {
- handler.cancel();
- }
- }
- }
-
- private static List<File> toFiles(List<String> paths) {
- final List<File> files = new ArrayList<File>(paths.size());
- for (String path : paths) {
- files.add(new File(path));
- }
- return files;
- }
-
@ChannelHandler.Sharable
private class CompilationRequestsHandler extends SimpleChannelInboundHandler<JavacRemoteProto.Message> {
@Override
@@ -210,52 +224,50 @@ public class JavacServer {
final JavacRemoteProto.Message.Request request = message.getRequest();
final JavacRemoteProto.Message.Request.Type requestType = request.getRequestType();
if (requestType == JavacRemoteProto.Message.Request.Type.COMPILE) {
- final List<String> options = request.getOptionList();
- final List<File> files = toFiles(request.getFileList());
- final List<File> cp = toFiles(request.getClasspathList());
- final List<File> platformCp = toFiles(request.getPlatformClasspathList());
- final List<File> srcPath = toFiles(request.getSourcepathList());
-
- final Map<File, Set<File>> outs = new HashMap<File, Set<File>>();
- for (JavacRemoteProto.Message.Request.OutputGroup outputGroup : request.getOutputList()) {
- final Set<File> srcRoots = new HashSet<File>();
- for (String root : outputGroup.getSourceRootList()) {
- srcRoots.add(new File(root));
+ if (myCancelHandler == null) { // if not running yet
+ final List<String> options = request.getOptionList();
+ final List<File> files = toFiles(request.getFileList());
+ final List<File> cp = toFiles(request.getClasspathList());
+ final List<File> platformCp = toFiles(request.getPlatformClasspathList());
+ final List<File> srcPath = toFiles(request.getSourcepathList());
+
+ final Map<File, Set<File>> outs = new HashMap<File, Set<File>>();
+ for (JavacRemoteProto.Message.Request.OutputGroup outputGroup : request.getOutputList()) {
+ final Set<File> srcRoots = new HashSet<File>();
+ for (String root : outputGroup.getSourceRootList()) {
+ srcRoots.add(new File(root));
+ }
+ outs.put(new File(outputGroup.getOutputRoot()), srcRoots);
}
- outs.put(new File(outputGroup.getOutputRoot()), srcRoots);
- }
- final CancelHandler cancelHandler = new CancelHandler();
- myCancelHandlers.add(cancelHandler);
- SharedThreadPool.getInstance().executeOnPooledThread(new Runnable() {
- @Override
- public void run() {
- try {
- context.channel()
- .writeAndFlush(compile(context, sessionId, options, files, cp, platformCp, srcPath, outs, cancelHandler));
+ final CancelHandler cancelHandler = new CancelHandler();
+ myCancelHandler = cancelHandler;
+ SharedThreadPool.getInstance().executeOnPooledThread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ context.channel().writeAndFlush(
+ compile(context, sessionId, options, files, cp, platformCp, srcPath, outs, cancelHandler)
+ ).awaitUninterruptibly();
+ }
+ finally {
+ myCancelHandler = null;
+ ExternalJavacProcess.this.stop();
+ }
}
- finally {
- myCancelHandlers.remove(cancelHandler);
- }
- }
- });
+ });
+ }
}
else if (requestType == JavacRemoteProto.Message.Request.Type.CANCEL){
- cancelBuilds();
- reply = JavacProtoUtil.toMessage(sessionId, JavacProtoUtil.createRequestAckResponse());
+ cancelBuild();
}
else if (requestType == JavacRemoteProto.Message.Request.Type.SHUTDOWN){
- cancelBuilds();
+ cancelBuild();
new Thread("StopThread") {
@Override
public void run() {
//noinspection finally
- try {
- JavacServer.this.stop();
- }
- finally {
- System.exit(0);
- }
+ ExternalJavacProcess.this.stop();
}
}.start();
}
@@ -274,46 +286,38 @@ public class JavacServer {
}
}
}
-
- @ChannelHandler.Sharable
- private static final class ChannelRegistrar extends ChannelInboundHandlerAdapter {
- private final ChannelGroup openChannels = new DefaultChannelGroup(ImmediateEventExecutor.INSTANCE);
-
- public boolean isEmpty() {
- return openChannels.isEmpty();
+
+ public void stop() {
+ try {
+ //final long stopStart = System.currentTimeMillis();
+ //System.err.println("Exiting. Since global start " + (stopStart - myGlobalStart));
+ final ChannelFuture future = myConnectFuture;
+ if (future != null) {
+ future.channel().close().await();
+ }
+ myEventLoopGroup.shutdownGracefully(0, 15, TimeUnit.SECONDS).await();
+ //final long stopEnd = System.currentTimeMillis();
+ //System.err.println("Stop completed in " + (stopEnd - stopStart) + "ms; since global start: " + ((stopEnd - myGlobalStart)));
+ System.exit(0);
}
-
- public void add(@NotNull Channel serverChannel) {
- assert serverChannel instanceof ServerChannel;
- openChannels.add(serverChannel);
+ catch (Throwable e) {
+ e.printStackTrace(System.err);
+ System.exit(-1);
}
+ }
- @Override
- public void channelActive(ChannelHandlerContext context) throws Exception {
- // we don't need to remove channel on close - ChannelGroup do it
- openChannels.add(context.channel());
-
- super.channelActive(context);
+ private static List<File> toFiles(List<String> paths) {
+ final List<File> files = new ArrayList<File>(paths.size());
+ for (String path : paths) {
+ files.add(new File(path));
}
-
- public ChannelGroupFuture close() {
- EventLoopGroup eventLoopGroup = null;
- for (Channel channel : openChannels) {
- if (channel instanceof ServerChannel) {
- eventLoopGroup = channel.eventLoop().parent();
- break;
- }
- }
-
- ChannelGroupFuture future;
- try {
- future = openChannels.close();
- }
- finally {
- assert eventLoopGroup != null;
- eventLoopGroup.shutdownGracefully();
- }
- return future;
+ return files;
+ }
+
+ public void cancelBuild() {
+ final CancelHandler cancelHandler = myCancelHandler;
+ if (cancelHandler != null) {
+ cancelHandler.cancel();
}
}
@@ -332,4 +336,4 @@ public class JavacServer {
return myIsCanceled;
}
}
-} \ No newline at end of file
+}
diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/ExternalJavacServer.java b/jps/jps-builders/src/org/jetbrains/jps/javac/ExternalJavacServer.java
new file mode 100644
index 000000000000..f5ff5b175bd8
--- /dev/null
+++ b/jps/jps-builders/src/org/jetbrains/jps/javac/ExternalJavacServer.java
@@ -0,0 +1,310 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.jps.javac;
+
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.util.concurrency.Semaphore;
+import io.netty.bootstrap.ServerBootstrap;
+import io.netty.channel.*;
+import io.netty.channel.group.ChannelGroup;
+import io.netty.channel.group.ChannelGroupFuture;
+import io.netty.channel.group.DefaultChannelGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.nio.NioServerSocketChannel;
+import io.netty.handler.codec.protobuf.ProtobufDecoder;
+import io.netty.handler.codec.protobuf.ProtobufEncoder;
+import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
+import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;
+import io.netty.util.AttributeKey;
+import io.netty.util.concurrent.ImmediateEventExecutor;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.jps.builders.java.JavaCompilingTool;
+import org.jetbrains.jps.incremental.CompileContext;
+import org.jetbrains.jps.incremental.GlobalContextKey;
+import org.jetbrains.jps.incremental.Utils;
+import org.jetbrains.jps.model.JpsProject;
+import org.jetbrains.jps.model.java.JpsJavaExtensionService;
+import org.jetbrains.jps.model.java.compiler.JpsJavaCompilerConfiguration;
+import org.jetbrains.jps.model.java.compiler.JpsJavaCompilerOptions;
+import org.jetbrains.jps.service.SharedThreadPool;
+
+import javax.tools.*;
+import java.io.File;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author Eugene Zhuravlev
+ * Date: 1/22/12
+ */
+@SuppressWarnings("UseOfSystemOutOrSystemErr")
+public class ExternalJavacServer {
+ private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.javac.ExternalJavacServer");
+ public static final GlobalContextKey<ExternalJavacServer> KEY = GlobalContextKey.create("_external_javac_server_");
+
+ public static final int DEFAULT_SERVER_PORT = 7878;
+ private static final AttributeKey<JavacProcessDescriptor> SESSION_DESCRIPTOR = AttributeKey.valueOf("ExternalJavacServer.JavacProcessDescriptor");
+
+ private ChannelRegistrar myChannelRegistrar;
+ private final Map<UUID, JavacProcessDescriptor> myMessageHandlers = new HashMap<UUID, JavacProcessDescriptor>();
+ private int myListenPort = DEFAULT_SERVER_PORT;
+
+ public void start(int listenPort) {
+ final ServerBootstrap bootstrap = new ServerBootstrap().group(new NioEventLoopGroup(1, SharedThreadPool.getInstance())).channel(NioServerSocketChannel.class);
+ bootstrap.childOption(ChannelOption.TCP_NODELAY, true).childOption(ChannelOption.SO_KEEPALIVE, true);
+ myChannelRegistrar = new ChannelRegistrar();
+ final ChannelHandler compilationRequestsHandler = new CompilationRequestsHandler();
+ bootstrap.childHandler(new ChannelInitializer() {
+ @Override
+ protected void initChannel(Channel channel) throws Exception {
+ channel.pipeline().addLast(myChannelRegistrar,
+ new ProtobufVarint32FrameDecoder(),
+ new ProtobufDecoder(JavacRemoteProto.Message.getDefaultInstance()),
+ new ProtobufVarint32LengthFieldPrepender(),
+ new ProtobufEncoder(),
+ compilationRequestsHandler);
+ }
+ });
+ myChannelRegistrar.add(bootstrap.bind(listenPort).syncUninterruptibly().channel());
+ myListenPort = listenPort;
+ }
+
+ private static int getExternalJavacHeapSize(CompileContext context) {
+ final JpsProject project = context.getProjectDescriptor().getProject();
+ final JpsJavaCompilerConfiguration config = JpsJavaExtensionService.getInstance().getOrCreateCompilerConfiguration(project);
+ final JpsJavaCompilerOptions options = config.getCurrentCompilerOptions();
+ return options.MAXIMUM_HEAP_SIZE;
+ }
+
+
+ public boolean forkJavac(CompileContext context, List<String> options,
+ List<String> vmOptions, Collection<File> files,
+ Collection<File> classpath,
+ Collection<File> platformCp,
+ Collection<File> sourcePath,
+ Map<File, Set<File>> outs,
+ DiagnosticOutputConsumer diagnosticSink,
+ OutputFileConsumer outputSink,
+ final String javaHome, final JavaCompilingTool compilingTool) {
+ final ExternalJavacMessageHandler rh = new ExternalJavacMessageHandler(diagnosticSink, outputSink, getEncodingName(options));
+ final JavacRemoteProto.Message.Request request = JavacProtoUtil.createCompilationRequest(options, files, classpath, platformCp, sourcePath, outs);
+ final UUID uuid = UUID.randomUUID();
+ final JavacProcessDescriptor processDescriptor = new JavacProcessDescriptor(uuid, rh, request);
+ synchronized (myMessageHandlers) {
+ myMessageHandlers.put(uuid, processDescriptor);
+ }
+ try {
+ final JavacServerBootstrap.ExternalJavacProcessHandler processHandler = JavacServerBootstrap.launchExternalJavacProcess(
+ uuid, javaHome, getExternalJavacHeapSize(context), myListenPort, Utils.getSystemRoot(), vmOptions, compilingTool
+ );
+
+ while (!processDescriptor.waitFor(300L)) {
+ if (processHandler.isProcessTerminated() && processDescriptor.channel == null && processHandler.getExitCode() != 0) {
+ // process terminated abnormally and no communication took place
+ processDescriptor.setDone();
+ break;
+ }
+ if (context.getCancelStatus().isCanceled()) {
+ processDescriptor.cancelBuild();
+ }
+ }
+
+ return rh.isTerminatedSuccessfully();
+ }
+ catch (Throwable e) {
+ LOG.info(e);
+ diagnosticSink.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, e.getMessage()));
+ }
+ finally {
+ unregisterMessageHandler(uuid);
+ }
+ return false;
+ }
+
+ private void unregisterMessageHandler(UUID uuid) {
+ final JavacProcessDescriptor descriptor;
+ synchronized (myMessageHandlers) {
+ descriptor = myMessageHandlers.remove(uuid);
+ }
+ if (descriptor != null) {
+ descriptor.setDone();
+ }
+ }
+
+ @Nullable
+ private static String getEncodingName(List<String> options) {
+ boolean found = false;
+ for (String option : options) {
+ if (found) {
+ return option;
+ }
+ if ("-encoding".equalsIgnoreCase(option)) {
+ found = true;
+ }
+ }
+ return null;
+ }
+
+ public void stop() {
+ myChannelRegistrar.close().awaitUninterruptibly();
+ }
+
+ @ChannelHandler.Sharable
+ private class CompilationRequestsHandler extends SimpleChannelInboundHandler<JavacRemoteProto.Message> {
+ @Override
+ public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
+ JavacProcessDescriptor descriptor = ctx.attr(SESSION_DESCRIPTOR).get();
+ if (descriptor != null) {
+ descriptor.setDone();
+ }
+ super.channelUnregistered(ctx);
+ }
+
+ @Override
+ public void channelRead0(final ChannelHandlerContext context, JavacRemoteProto.Message message) throws Exception {
+ JavacProcessDescriptor descriptor = context.attr(SESSION_DESCRIPTOR).get();
+
+ UUID sessionId;
+ if (descriptor == null) {
+ // this is the first message for this session, so fill session data with missing info
+ sessionId = JavacProtoUtil.fromProtoUUID(message.getSessionId());
+
+ descriptor = myMessageHandlers.get(sessionId);
+ if (descriptor != null) {
+ descriptor.channel = context.channel();
+ context.attr(SESSION_DESCRIPTOR).set(descriptor);
+ }
+ }
+ else {
+ sessionId = descriptor.sessionId;
+ }
+
+ final ExternalJavacMessageHandler handler = descriptor != null? descriptor.handler : null;
+
+ final JavacRemoteProto.Message.Type messageType = message.getMessageType();
+
+ JavacRemoteProto.Message reply = null;
+ try {
+ if (messageType == JavacRemoteProto.Message.Type.RESPONSE) {
+ final JavacRemoteProto.Message.Response response = message.getResponse();
+ final JavacRemoteProto.Message.Response.Type responseType = response.getResponseType();
+ if (handler != null) {
+ if (responseType == JavacRemoteProto.Message.Response.Type.REQUEST_ACK) {
+ final JavacRemoteProto.Message.Request request = descriptor.request;
+ if (request != null) {
+ reply = JavacProtoUtil.toMessage(sessionId, request);
+ descriptor.request = null;
+ }
+ }
+ else {
+ final boolean terminateOk = handler.handleMessage(message);
+ if (terminateOk) {
+ descriptor.setDone();
+ }
+ }
+ }
+ else {
+ reply = JavacProtoUtil.toMessage(sessionId, JavacProtoUtil.createCancelRequest());
+ }
+ }
+ else {
+ reply = JavacProtoUtil.toMessage(sessionId, JavacProtoUtil.createFailure("Unsupported message: " + messageType.name(), null));
+ }
+ }
+ finally {
+ if (reply != null) {
+ context.channel().writeAndFlush(reply);
+ }
+ }
+ }
+ }
+
+ @ChannelHandler.Sharable
+ private static final class ChannelRegistrar extends ChannelInboundHandlerAdapter {
+ private final ChannelGroup openChannels = new DefaultChannelGroup(ImmediateEventExecutor.INSTANCE);
+
+ public boolean isEmpty() {
+ return openChannels.isEmpty();
+ }
+
+ public void add(@NotNull Channel serverChannel) {
+ assert serverChannel instanceof ServerChannel;
+ openChannels.add(serverChannel);
+ }
+
+ @Override
+ public void channelActive(ChannelHandlerContext context) throws Exception {
+ // we don't need to remove channel on close - ChannelGroup do it
+ openChannels.add(context.channel());
+ super.channelActive(context);
+ }
+
+ public ChannelGroupFuture close() {
+ EventLoopGroup eventLoopGroup = null;
+ for (Channel channel : openChannels) {
+ if (channel instanceof ServerChannel) {
+ eventLoopGroup = channel.eventLoop().parent();
+ break;
+ }
+ }
+
+ ChannelGroupFuture future;
+ try {
+ future = openChannels.close();
+ }
+ finally {
+ assert eventLoopGroup != null;
+ eventLoopGroup.shutdownGracefully(0, 15, TimeUnit.SECONDS);
+ }
+ return future;
+ }
+ }
+
+ private static class JavacProcessDescriptor {
+ @NotNull
+ final UUID sessionId;
+ @NotNull
+ final ExternalJavacMessageHandler handler;
+ volatile JavacRemoteProto.Message.Request request;
+ volatile Channel channel;
+ private final Semaphore myDone = new Semaphore();
+
+ public JavacProcessDescriptor(@NotNull UUID sessionId, @NotNull ExternalJavacMessageHandler handler, @NotNull JavacRemoteProto.Message.Request request) {
+ this.sessionId = sessionId;
+ this.handler = handler;
+ this.request = request;
+ myDone.down();
+ }
+
+ public void cancelBuild() {
+ if (channel != null) {
+ channel.writeAndFlush(JavacProtoUtil.toMessage(sessionId, JavacProtoUtil.createCancelRequest()));
+ }
+ }
+
+ public void setDone() {
+ myDone.up();
+ }
+
+
+ public boolean waitFor(long timeout) {
+ return myDone.waitFor(timeout);
+ }
+
+ }
+
+} \ No newline at end of file
diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServerBootstrap.java b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServerBootstrap.java
index bb66e9c6b09f..ecf53395eb53 100644
--- a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServerBootstrap.java
+++ b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServerBootstrap.java
@@ -20,11 +20,9 @@ import com.intellij.execution.process.ProcessAdapter;
import com.intellij.execution.process.ProcessEvent;
import com.intellij.execution.process.ProcessOutputTypes;
import com.intellij.openapi.util.Key;
-import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.util.concurrency.Semaphore;
import org.jetbrains.jps.builders.java.JavaCompilingTool;
import org.jetbrains.jps.cmdline.ClasspathBootstrap;
import org.jetbrains.jps.service.SharedThreadPool;
@@ -32,6 +30,7 @@ import org.jetbrains.jps.service.SharedThreadPool;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
+import java.util.UUID;
import java.util.concurrent.Future;
/**
@@ -40,15 +39,15 @@ import java.util.concurrent.Future;
*/
public class JavacServerBootstrap {
- public static BaseOSProcessHandler launchJavacServer(String sdkHomePath,
- int heapSize,
- int port,
- File workingDir,
- List<String> vmOptions,
- JavaCompilingTool compilingTool) throws Exception {
+ public static ExternalJavacProcessHandler launchExternalJavacProcess(UUID uuid, String sdkHomePath,
+ int heapSize,
+ int port,
+ File workingDir,
+ List<String> vmOptions,
+ JavaCompilingTool compilingTool) throws Exception {
final List<String> cmdLine = new ArrayList<String>();
appendParam(cmdLine, getVMExecutablePath(sdkHomePath));
- appendParam(cmdLine, "-XX:MaxPermSize=150m");
+ //appendParam(cmdLine, "-XX:MaxPermSize=150m");
//appendParam(cmdLine, "-XX:ReservedCodeCacheSize=64m");
appendParam(cmdLine, "-Djava.awt.headless=true");
final int xms = heapSize / 2;
@@ -59,7 +58,7 @@ public class JavacServerBootstrap {
// debugging
//appendParam(cmdLine, "-XX:+HeapDumpOnOutOfMemoryError");
- //appendParam(cmdLine, "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5009");
+ //appendParam(cmdLine, "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5009");
// javac's VM should use the same default locale that IDEA uses in order for javac to print messages in 'correct' language
final String encoding = System.getProperty("file.encoding");
@@ -83,18 +82,20 @@ public class JavacServerBootstrap {
appendParam(cmdLine, "-Duser.region=" + region);
}
- appendParam(cmdLine, "-D" + JavacServer.JPS_JAVA_COMPILING_TOOL_PROPERTY + "=" + compilingTool.getId());
+ appendParam(cmdLine, "-D" + ExternalJavacProcess.JPS_JAVA_COMPILING_TOOL_PROPERTY + "=" + compilingTool.getId());
// this will disable standard extensions to ensure javac is loaded from the right tools.jar
appendParam(cmdLine, "-Djava.ext.dirs=");
-
+
+ appendParam(cmdLine, "-Dlog4j.defaultInitOverride=true");
+
for (String option : vmOptions) {
appendParam(cmdLine, option);
}
appendParam(cmdLine, "-classpath");
- final List<File> cp = ClasspathBootstrap.getJavacServerClasspath(sdkHomePath, compilingTool);
+ final List<File> cp = ClasspathBootstrap.getExternalJavacProcessClasspath(sdkHomePath, compilingTool);
final StringBuilder classpath = new StringBuilder();
for (File file : cp) {
if (classpath.length() > 0) {
@@ -104,7 +105,9 @@ public class JavacServerBootstrap {
}
appendParam(cmdLine, classpath.toString());
- appendParam(cmdLine, org.jetbrains.jps.javac.JavacServer.class.getName());
+ appendParam(cmdLine, org.jetbrains.jps.javac.ExternalJavacProcess.class.getName());
+ appendParam(cmdLine, uuid.toString());
+ appendParam(cmdLine, "127.0.0.1");
appendParam(cmdLine, Integer.toString(port));
workingDir.mkdirs();
@@ -115,68 +118,31 @@ public class JavacServerBootstrap {
builder.directory(workingDir);
final Process process = builder.start();
- final BaseOSProcessHandler processHandler = new BaseOSProcessHandler(process, null, null) {
+ final ExternalJavacProcessHandler processHandler = new ExternalJavacProcessHandler(process);
+ processHandler.addProcessListener(new ProcessAdapter() {
@Override
- protected Future<?> executeOnPooledThread(Runnable task) {
- return SharedThreadPool.getInstance().executeOnPooledThread(task);
+ public void processTerminated(ProcessEvent event) {
+ processHandler.setExitCode(event.getExitCode());
}
- };
- configureProcessHandler(processHandler);
-
- return processHandler;
- }
- private static void configureProcessHandler(final BaseOSProcessHandler processHandler) throws Exception {
- processHandler.addProcessListener(new ProcessAdapter() {
public void onTextAvailable(ProcessEvent event, Key outputType) {
final String text = event.getText();
if (!StringUtil.isEmptyOrSpaces(text)) {
if (outputType == ProcessOutputTypes.STDOUT) {
- System.out.print("JAVAC_SERVER: " + text);
- }
- else if (outputType == ProcessOutputTypes.STDERR){
- System.err.print("JAVAC_SERVER: " + text);
+ System.out.print("JAVAC_PROCESS: " + text);
}
- }
- }
- });
- final Semaphore semaphore = new Semaphore();
- semaphore.down();
- final Ref<String> serverStartMessage = new Ref<String>(null);
- processHandler.addProcessListener(new ProcessAdapter() {
- public void processTerminated(ProcessEvent event) {
- try {
- processHandler.removeProcessListener(this);
- }
- finally {
- semaphore.up();
- }
- }
-
- public void onTextAvailable(ProcessEvent event, Key outputType) {
- if (outputType == ProcessOutputTypes.STDERR) {
- final String text = event.getText();
- if (text != null && (text.contains(JavacServer.SERVER_SUCCESS_START_MESSAGE) || text.contains(JavacServer.SERVER_ERROR_START_MESSAGE))) {
- try {
- processHandler.removeProcessListener(this);
- serverStartMessage.set(text);
- }
- finally {
- semaphore.up();
- }
+ else if (outputType == ProcessOutputTypes.STDERR) {
+ System.err.print("JAVAC_PROCESS: " + text);
}
}
}
});
processHandler.startNotify();
- semaphore.waitFor();
-
- final String startupMsg = serverStartMessage.get();
- if (startupMsg == null || !startupMsg.contains(JavacServer.SERVER_SUCCESS_START_MESSAGE)) {
- throw new Exception("Server startup failed: " + startupMsg);
- }
+ return processHandler;
}
+
+
private static void appendParam(List<String> cmdLine, String param) {
if (SystemInfo.isWindows) {
if (param.contains("\"")) {
@@ -192,4 +158,25 @@ public class JavacServerBootstrap {
public static String getVMExecutablePath(String sdkHome) {
return sdkHome + "/bin/java";
}
+
+ public static class ExternalJavacProcessHandler extends BaseOSProcessHandler {
+ private volatile int myExitCode;
+
+ ExternalJavacProcessHandler(Process process) {
+ super(process, null, null);
+ }
+
+ @Override
+ protected Future<?> executeOnPooledThread(Runnable task) {
+ return SharedThreadPool.getInstance().executeOnPooledThread(task);
+ }
+
+ void setExitCode(int exitCode) {
+ myExitCode = exitCode;
+ }
+
+ public int getExitCode() {
+ return myExitCode;
+ }
+ }
}
diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServerClient.java b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServerClient.java
deleted file mode 100644
index 8085068b56e6..000000000000
--- a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServerClient.java
+++ /dev/null
@@ -1,78 +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 org.jetbrains.jps.javac;
-
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-import org.jetbrains.jps.api.RequestFuture;
-import org.jetbrains.jps.client.SimpleProtobufClient;
-import org.jetbrains.jps.client.UUIDGetter;
-import org.jetbrains.jps.service.SharedThreadPool;
-
-import java.io.File;
-import java.util.*;
-
-/**
- * @author Eugene Zhuravlev
- * Date: 1/22/12
- */
-public class JavacServerClient extends SimpleProtobufClient<JavacServerResponseHandler>{
-
- public JavacServerClient() {
- super(JavacRemoteProto.Message.getDefaultInstance(), SharedThreadPool.getInstance(), new UUIDGetter() {
- @Override
- @NotNull
- public UUID getSessionUUID(@NotNull JavacRemoteProto.Message message) {
- final JavacRemoteProto.Message.UUID uuid = message.getSessionId();
- return new UUID(uuid.getMostSigBits(), uuid.getLeastSigBits());
- }
- });
- }
-
- public RequestFuture<JavacServerResponseHandler> sendCompileRequest(List<String> options, Collection<File> files, Collection<File> classpath, Collection<File> platformCp, Collection<File> sourcePath, Map<File, Set<File>> outs, DiagnosticOutputConsumer diagnosticSink, OutputFileConsumer outputSink) {
- final JavacServerResponseHandler rh = new JavacServerResponseHandler(diagnosticSink, outputSink, getEncodingName(options));
- final JavacRemoteProto.Message.Request request = JavacProtoUtil.createCompilationRequest(options, files, classpath, platformCp, sourcePath, outs);
- return sendRequest(request, rh, new RequestFuture.CancelAction<JavacServerResponseHandler>() {
- @Override
- public void cancel(RequestFuture<JavacServerResponseHandler> javacServerResponseHandlerRequestFuture) throws Exception {
- sendRequest(JavacProtoUtil.createCancelRequest(), null, null);
- }
- });
- }
-
- public RequestFuture sendShutdownRequest() {
- return sendRequest(JavacProtoUtil.createShutdownRequest(), null, null);
- }
-
- private RequestFuture<JavacServerResponseHandler> sendRequest(final JavacRemoteProto.Message.Request request, final JavacServerResponseHandler responseHandler, final RequestFuture.CancelAction<JavacServerResponseHandler> cancelAction) {
- final UUID requestId = UUID.randomUUID();
- return sendMessage(requestId, JavacProtoUtil.toMessage(requestId, request), responseHandler, cancelAction);
- }
-
- @Nullable
- private static String getEncodingName(List<String> options) {
- boolean found = false;
- for (String option : options) {
- if (found) {
- return option;
- }
- if ("-encoding".equalsIgnoreCase(option)) {
- found = true;
- }
- }
- return null;
- }
-}
diff --git a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServerResponseHandler.java b/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServerResponseHandler.java
deleted file mode 100644
index 688bf0596ac4..000000000000
--- a/jps/jps-builders/src/org/jetbrains/jps/javac/JavacServerResponseHandler.java
+++ /dev/null
@@ -1,231 +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 org.jetbrains.jps.javac;
-
-import com.google.protobuf.ByteString;
-import com.google.protobuf.MessageLite;
-import org.jetbrains.annotations.Nullable;
-import org.jetbrains.jps.client.ProtobufResponseHandler;
-import org.jetbrains.jps.incremental.BinaryContent;
-
-import javax.tools.Diagnostic;
-import javax.tools.JavaFileObject;
-import java.io.File;
-import java.net.URI;
-import java.util.Collection;
-import java.util.Locale;
-
-/**
- * @author Eugene Zhuravlev
- * Date: 1/22/12
- */
-public class JavacServerResponseHandler implements ProtobufResponseHandler{
- private final DiagnosticOutputConsumer myDiagnosticSink;
- private final OutputFileConsumer myOutputSink;
- @Nullable
- private final String myEncodingName;
- private volatile boolean myTerminatedSuccessfully;
-
- public JavacServerResponseHandler(DiagnosticOutputConsumer diagnosticSink, OutputFileConsumer outputSink, @Nullable final String encodingName) {
- myDiagnosticSink = diagnosticSink;
- myOutputSink = outputSink;
- myEncodingName = encodingName;
- }
-
- public boolean handleMessage(MessageLite message) throws Exception {
- final JavacRemoteProto.Message msg = (JavacRemoteProto.Message)message;
- final JavacRemoteProto.Message.Type messageType = msg.getMessageType();
-
- if (messageType == JavacRemoteProto.Message.Type.RESPONSE) {
- final JavacRemoteProto.Message.Response response = msg.getResponse();
- final JavacRemoteProto.Message.Response.Type responseType = response.getResponseType();
-
- if (responseType == JavacRemoteProto.Message.Response.Type.BUILD_MESSAGE) {
- final JavacRemoteProto.Message.Response.CompileMessage compileMessage = response.getCompileMessage();
- final JavacRemoteProto.Message.Response.CompileMessage.Kind messageKind = compileMessage.getKind();
-
- if (messageKind == JavacRemoteProto.Message.Response.CompileMessage.Kind.STD_OUT) {
- if (compileMessage.hasText()) {
- myDiagnosticSink.outputLineAvailable(compileMessage.getText());
- }
- }
- else {
- final String sourceUri = compileMessage.hasSourceUri()? compileMessage.getSourceUri() : null;
- final JavaFileObject srcFileObject = sourceUri != null? new DummyJavaFileObject(URI.create(sourceUri)) : null;
- myDiagnosticSink.report(new DummyDiagnostic(convertKind(messageKind), srcFileObject, compileMessage));
- }
-
- return false;
- }
-
- if (responseType == JavacRemoteProto.Message.Response.Type.OUTPUT_OBJECT) {
- final JavacRemoteProto.Message.Response.OutputObject outputObject = response.getOutputObject();
- final JavacRemoteProto.Message.Response.OutputObject.Kind kind = outputObject.getKind();
-
- final String outputRoot = outputObject.hasOutputRoot()? outputObject.getOutputRoot() : null;
- final File outputRootFile = outputRoot != null? new File(outputRoot) : null;
-
- final BinaryContent fileObjectContent;
- final ByteString content = outputObject.hasContent()? outputObject.getContent() : null;
- if (content != null) {
- final byte[] bytes = content.toByteArray();
- fileObjectContent = new BinaryContent(bytes, 0, bytes.length);
- }
- else {
- fileObjectContent = null;
- }
-
- final String sourceUri = outputObject.hasSourceUri()? outputObject.getSourceUri() : null;
- final URI srcUri = sourceUri != null? URI.create(sourceUri) : null;
- final OutputFileObject fileObject = new OutputFileObject(
- null,
- outputRootFile,
- outputObject.hasRelativePath()? outputObject.getRelativePath() : null,
- new File(outputObject.getFilePath()),
- convertKind(kind),
- outputObject.hasClassName()? outputObject.getClassName() : null,
- srcUri,
- myEncodingName, fileObjectContent
- );
-
- myOutputSink.save(fileObject);
- return false;
- }
-
- if (responseType == JavacRemoteProto.Message.Response.Type.SRC_FILE_LOADED) {
- final JavacRemoteProto.Message.Response.OutputObject outputObject = response.getOutputObject();
- final File file = new File(outputObject.getFilePath());
- myDiagnosticSink.javaFileLoaded(file);
- return false;
- }
-
- if (responseType == JavacRemoteProto.Message.Response.Type.CLASS_DATA) {
- final JavacRemoteProto.Message.Response.ClassData data = response.getClassData();
- final String className = data.getClassName();
- final Collection<String> imports = data.getImportStatementList();
- final Collection<String> staticImports = data.getStaticImportList();
- myDiagnosticSink.registerImports(className, imports, staticImports);
- return false;
- }
-
- if (responseType == JavacRemoteProto.Message.Response.Type.BUILD_COMPLETED) {
- if (response.hasCompletionStatus()) {
- myTerminatedSuccessfully = response.getCompletionStatus();
- }
- return true;
- }
-
- if (responseType == JavacRemoteProto.Message.Response.Type.REQUEST_ACK) {
- return true;
- }
-
- throw new Exception("Unsupported response type: " + responseType.name());
- }
-
- if (messageType == JavacRemoteProto.Message.Type.FAILURE) {
- final JavacRemoteProto.Message.Failure failure = msg.getFailure();
- final StringBuilder buf = new StringBuilder();
- if (failure.hasDescription()) {
- buf.append(failure.getDescription());
- }
- if (failure.hasStacktrace()) {
- if (buf.length() > 0) {
- buf.append("\n");
- }
- buf.append(failure.getStacktrace());
- }
- myDiagnosticSink.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, buf.toString()));
- return true;
- }
-
- throw new Exception("Unsupported message type: " + messageType.name());
- }
-
- public boolean isTerminatedSuccessfully() {
- return myTerminatedSuccessfully;
- }
-
- private static Diagnostic.Kind convertKind(JavacRemoteProto.Message.Response.CompileMessage.Kind kind) {
- switch (kind) {
- case ERROR: return Diagnostic.Kind.ERROR;
- case WARNING: return Diagnostic.Kind.WARNING;
- case MANDATORY_WARNING: return Diagnostic.Kind.MANDATORY_WARNING;
- case NOTE: return Diagnostic.Kind.NOTE;
- default : return Diagnostic.Kind.OTHER;
- }
- }
-
- private static OutputFileObject.Kind convertKind(JavacRemoteProto.Message.Response.OutputObject.Kind kind) {
- switch (kind) {
- case CLASS: return JavaFileObject.Kind.CLASS;
- case HTML: return JavaFileObject.Kind.HTML;
- case SOURCE: return JavaFileObject.Kind.SOURCE;
- default : return JavaFileObject.Kind.OTHER;
- }
- }
-
- public void sessionTerminated() {
- }
-
- private static class DummyDiagnostic implements Diagnostic<JavaFileObject> {
-
- private final Kind myMessageKind;
- private final JavaFileObject mySrcFileObject;
- private final JavacRemoteProto.Message.Response.CompileMessage myCompileMessage;
-
- public DummyDiagnostic(final Kind messageKind, JavaFileObject srcFileObject, JavacRemoteProto.Message.Response.CompileMessage compileMessage) {
- myMessageKind = messageKind;
- mySrcFileObject = srcFileObject;
- myCompileMessage = compileMessage;
- }
-
- public Kind getKind() {
- return myMessageKind;
- }
-
- public JavaFileObject getSource() {
- return mySrcFileObject;
- }
-
- public long getPosition() {
- return myCompileMessage.hasProblemLocationOffset()? myCompileMessage.getProblemLocationOffset() : -1;
- }
-
- public long getStartPosition() {
- return myCompileMessage.hasProblemBeginOffset()? myCompileMessage.getProblemBeginOffset() : -1;
- }
-
- public long getEndPosition() {
- return myCompileMessage.hasProblemEndOffset()? myCompileMessage.getProblemEndOffset() : -1;
- }
-
- public long getLineNumber() {
- return myCompileMessage.hasLine()? myCompileMessage.getLine() : -1;
- }
-
- public long getColumnNumber() {
- return myCompileMessage.hasColumn()? myCompileMessage.getColumn() : -1;
- }
-
- public String getCode() {
- return null;
- }
-
- public String getMessage(Locale locale) {
- return myCompileMessage.hasText()? myCompileMessage.getText() : null;
- }
- }
-}
diff --git a/jps/model-api/src/org/jetbrains/jps/model/java/LanguageLevel.java b/jps/model-api/src/org/jetbrains/jps/model/java/LanguageLevel.java
index 689776eafda0..3d9b302d38cf 100644
--- a/jps/model-api/src/org/jetbrains/jps/model/java/LanguageLevel.java
+++ b/jps/model-api/src/org/jetbrains/jps/model/java/LanguageLevel.java
@@ -19,5 +19,5 @@ package org.jetbrains.jps.model.java;
* @author nik
*/
public enum LanguageLevel {
- JDK_1_3, JDK_1_4, JDK_1_5, JDK_1_6, JDK_1_7, JDK_1_8
+ JDK_1_3, JDK_1_4, JDK_1_5, JDK_1_6, JDK_1_7, JDK_1_8, JDK_1_9
}
diff --git a/lib/jsch-0.1.50.jar b/lib/jsch-0.1.50.jar
deleted file mode 100644
index de6cd0cda26b..000000000000
--- a/lib/jsch-0.1.50.jar
+++ /dev/null
Binary files differ
diff --git a/lib/jsch-0.1.51.jar b/lib/jsch-0.1.51.jar
new file mode 100644
index 000000000000..70d13988ccec
--- /dev/null
+++ b/lib/jsch-0.1.51.jar
Binary files differ
diff --git a/lib/required_for_dist.txt b/lib/required_for_dist.txt
index 094e94784836..997eb52a6fc6 100644
--- a/lib/required_for_dist.txt
+++ b/lib/required_for_dist.txt
@@ -30,7 +30,7 @@ jgoodies-looks-2.4.2.jar
jh.jar
jna-utils.jar
jna.jar
-jsch-0.1.50.jar
+jsch-0.1.51.jar
jsch.agentproxy.connector-factory.jar
jsch.agentproxy.core.jar
jsch.agentproxy.pageant.jar
@@ -63,7 +63,7 @@ snappy-in-java-0.3.jar
swingx-core-1.6.2.jar
trove4j.jar
velocity.jar
-winp-1.17-patched.jar
+winp-1.21-patched.jar
xbean.jar
xerces.jar
xmlrpc-2.0.jar
diff --git a/lib/src/ecjsrc-4.3.2.jar b/lib/src/ecjsrc-4.3.2.jar
deleted file mode 100644
index 5d54db8bb843..000000000000
--- a/lib/src/ecjsrc-4.3.2.jar
+++ /dev/null
Binary files differ
diff --git a/lib/src/jsch-0.1.50.zip b/lib/src/jsch-0.1.50.zip
deleted file mode 100644
index a90c40d2f272..000000000000
--- a/lib/src/jsch-0.1.50.zip
+++ /dev/null
Binary files differ
diff --git a/lib/src/jsch-0.1.51.zip b/lib/src/jsch-0.1.51.zip
new file mode 100644
index 000000000000..f4652c479d8c
--- /dev/null
+++ b/lib/src/jsch-0.1.51.zip
Binary files differ
diff --git a/lib/src/winp-1.17-patched-src.zip b/lib/src/winp-1.17-patched-src.zip
deleted file mode 100644
index 02f7972bc776..000000000000
--- a/lib/src/winp-1.17-patched-src.zip
+++ /dev/null
Binary files differ
diff --git a/lib/src/winp-1.21-patched.zip b/lib/src/winp-1.21-patched.zip
new file mode 100644
index 000000000000..24a308323632
--- /dev/null
+++ b/lib/src/winp-1.21-patched.zip
Binary files differ
diff --git a/lib/src/winp.patch b/lib/src/winp.patch
new file mode 100644
index 000000000000..c3828306e8ee
--- /dev/null
+++ b/lib/src/winp.patch
@@ -0,0 +1,26 @@
+diff -ur winp-winp-1.17/src/main/java/org/jvnet/winp/Native.java winp-1.17-patched/src/main/java/org/jvnet/winp/Native.java
+--- winp-winp-1.17/src/main/java/org/jvnet/winp/Native.java 2013-01-03 09:26:13.000000000 +0400
++++ winp-1.17-patched/src/main/java/org/jvnet/winp/Native.java 2013-02-25 16:23:24.000000000 +0400
+@@ -47,6 +47,7 @@
+ private static final Logger LOGGER = Logger.getLogger(Native.class.getName());
+ // system property holding the preferred folder for copying the dll file to.
+ private static final String DLL_TARGET = "winp.folder.preferred";
++ private static final String UNPACK_DLL_TO_PARENT_DIR = "winp.unpack.dll.to.parent.dir";
+
+ static {
+ load();
+@@ -61,7 +62,12 @@
+ final URL res = Native.class.getClassLoader().getResource(dllName+".dll");
+ if(res!=null) {
+ String url = res.toExternalForm();
+- if(url.startsWith("jar:") || url.startsWith("wsjar:")) {
++
++ //patched by JetBrains: do not try to unpack the dll file to the directory containing the jar file by default.
++ // It can fail because the process has no rights to write to that directory and also pollutes the project directories if the jar is used in development mode.
++ boolean unpackToParentDir = Boolean.parseBoolean(System.getProperty(UNPACK_DLL_TO_PARENT_DIR));
++
++ if(unpackToParentDir && (url.startsWith("jar:") || url.startsWith("wsjar:"))) {
+ int idx = url.lastIndexOf('!');
+ String filePortion = url.substring(url.indexOf(':')+1,idx);
+ while(filePortion.startsWith("/"))
+
diff --git a/lib/winp-1.17-patched.jar b/lib/winp-1.17-patched.jar
deleted file mode 100644
index 21a670e11aba..000000000000
--- a/lib/winp-1.17-patched.jar
+++ /dev/null
Binary files differ
diff --git a/lib/winp-1.21-patched.jar b/lib/winp-1.21-patched.jar
new file mode 100644
index 000000000000..76141dcd8911
--- /dev/null
+++ b/lib/winp-1.21-patched.jar
Binary files differ
diff --git a/native/MacLauncher/Launcher.m b/native/MacLauncher/Launcher.m
index 630cf741fdab..7e899f9da040 100644
--- a/native/MacLauncher/Launcher.m
+++ b/native/MacLauncher/Launcher.m
@@ -326,8 +326,8 @@ NSDictionary *parseProperties() {
NSLog(@"Cannot chdir to working directory at %@", cwd);
}
} else {
- NSLog(@"Info.plist is corrupted, Absent WorkingDirectory key.");
- exit(-1);
+ NSString *dir = [[NSFileManager defaultManager] currentDirectoryPath];
+ NSLog(@"WorkingDirectory is absent in Info.plist. Current Directory: %@", dir);
}
}
diff --git a/native/WinLauncher/WinLauncher/WinLauncher.cpp b/native/WinLauncher/WinLauncher/WinLauncher.cpp
index 3249a9a1f0de..681cb46ae6aa 100644
--- a/native/WinLauncher/WinLauncher/WinLauncher.cpp
+++ b/native/WinLauncher/WinLauncher/WinLauncher.cpp
@@ -194,11 +194,16 @@ bool LocateJVM()
return result;
}
- std::string jreDir = GetAdjacentDir(need64BitJRE ? "jre64":"jre");
- if (FindValidJVM(jreDir.c_str()) && Is64BitJRE(jvmPath) == need64BitJRE)
- {
- return true;
- }
+
+ std::vector<std::string> jrePaths;
+ if(need64BitJRE) jrePaths.push_back(GetAdjacentDir("jre64"));
+ jrePaths.push_back(GetAdjacentDir("jre"));
+ for(std::vector<std::string>::iterator it = jrePaths.begin(); it != jrePaths.end(); ++it) {
+ if (FindValidJVM((*it).c_str()) && Is64BitJRE(jvmPath) == need64BitJRE)
+ {
+ return true;
+ }
+ }
if (FindJVMInRegistry())
{
diff --git a/platform/analysis-api/src/com/intellij/psi/search/scope/packageSet/FilePatternPackageSet.java b/platform/analysis-api/src/com/intellij/psi/search/scope/packageSet/FilePatternPackageSet.java
index 4fed9ea06538..db0c71b9f99a 100644
--- a/platform/analysis-api/src/com/intellij/psi/search/scope/packageSet/FilePatternPackageSet.java
+++ b/platform/analysis-api/src/com/intellij/psi/search/scope/packageSet/FilePatternPackageSet.java
@@ -56,12 +56,12 @@ public class FilePatternPackageSet extends PatternBasedPackageSet {
if (modulePattern.startsWith("group:")) {
int idx = modulePattern.indexOf(':', 6);
if (idx == -1) idx = modulePattern.length();
- myModuleGroupPattern = Pattern.compile(StringUtil.replace(modulePattern.substring(6, idx), "*", ".*"));
+ myModuleGroupPattern = Pattern.compile(StringUtil.escapeToRegexp(modulePattern.substring(6, idx)));
if (idx < modulePattern.length() - 1) {
- myModulePattern = Pattern.compile(StringUtil.replace(modulePattern.substring(idx + 1), "*", ".*"));
+ myModulePattern = Pattern.compile(StringUtil.escapeToRegexp(modulePattern.substring(idx + 1)));
}
} else {
- myModulePattern = Pattern.compile(StringUtil.replace(modulePattern, "*", ".*"));
+ myModulePattern = Pattern.compile(StringUtil.escapeToRegexp(modulePattern));
}
}
myFilePattern = filePattern != null ? Pattern.compile(convertToRegexp(filePattern, '/')) : null;
diff --git a/platform/analysis-impl/src/com/intellij/codeHighlighting/TextEditorHighlightingPass.java b/platform/analysis-impl/src/com/intellij/codeHighlighting/TextEditorHighlightingPass.java
index 6e30e2d4ac4d..a4a2d3fda58d 100644
--- a/platform/analysis-impl/src/com/intellij/codeHighlighting/TextEditorHighlightingPass.java
+++ b/platform/analysis-impl/src/com/intellij/codeHighlighting/TextEditorHighlightingPass.java
@@ -141,6 +141,7 @@ public abstract class TextEditorHighlightingPass implements HighlightingPass {
myStartingPredecessorIds = startingPredecessorIds;
}
+ @Override
@NonNls
public String toString() {
return getClass() + "; id=" + getId();
diff --git a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/UpdateHighlightersUtil.java b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/UpdateHighlightersUtil.java
index bd63e19c8657..123263a566c8 100644
--- a/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/UpdateHighlightersUtil.java
+++ b/platform/analysis-impl/src/com/intellij/codeInsight/daemon/impl/UpdateHighlightersUtil.java
@@ -49,7 +49,7 @@ import java.util.List;
public class UpdateHighlightersUtil {
private static final Comparator<HighlightInfo> BY_START_OFFSET_NODUPS = new Comparator<HighlightInfo>() {
@Override
- public int compare(HighlightInfo o1, HighlightInfo o2) {
+ public int compare(@NotNull HighlightInfo o1, @NotNull HighlightInfo o2) {
int d = o1.getActualStartOffset() - o2.getActualStartOffset();
if (d != 0) return d;
d = o1.getActualEndOffset() - o2.getActualEndOffset();
@@ -212,7 +212,7 @@ public class UpdateHighlightersUtil {
if (!atStart) return true;
if (!info.isFromInjection() && info.getEndOffset() < document.getTextLength() && (info.getEndOffset() <= startOffset || info.getStartOffset()>=endOffset)) return true; // injections are oblivious to restricting range
- if (info.isFileLevelAnnotation() && psiFile.getViewProvider().isPhysical()) {
+ if (info.isFileLevelAnnotation()) {
codeAnalyzer.addFileLevelHighlight(project, group, info, psiFile);
changed[0] = true;
return true;
diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/InspectionEngine.java b/platform/analysis-impl/src/com/intellij/codeInspection/InspectionEngine.java
index 713b545c6247..d8f019a7327e 100644
--- a/platform/analysis-impl/src/com/intellij/codeInspection/InspectionEngine.java
+++ b/platform/analysis-impl/src/com/intellij/codeInspection/InspectionEngine.java
@@ -33,6 +33,7 @@ import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.util.Condition;
+import com.intellij.openapi.util.Conditions;
import com.intellij.openapi.util.ProperTextRange;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
@@ -113,7 +114,7 @@ public class InspectionEngine {
TextRange range = file.getTextRange();
final LocalInspectionToolSession session = new LocalInspectionToolSession(file, range.getStartOffset(), range.getEndOffset());
Divider.divideInsideAndOutside(file, range.getStartOffset(), range.getEndOffset(), range, elements, new ArrayList<ProperTextRange>(),
- Collections.<PsiElement>emptyList(), Collections.<ProperTextRange>emptyList(), true, Condition.TRUE);
+ Collections.<PsiElement>emptyList(), Collections.<ProperTextRange>emptyList(), true, Conditions.<PsiFile>alwaysTrue());
MultiMap<LocalInspectionToolWrapper, String> toolToLanguages = getToolsForElements(toolWrappers, DumbService.isDumb(file.getProject()), elements, Collections.<PsiElement>emptyList());
List<Map.Entry<LocalInspectionToolWrapper, Collection<String>>> entries = new ArrayList<Map.Entry<LocalInspectionToolWrapper, Collection<String>>>(toolToLanguages.entrySet());
diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/ex/InspectionProfileImpl.java b/platform/analysis-impl/src/com/intellij/codeInspection/ex/InspectionProfileImpl.java
index 0a1861e8000e..346a4446090a 100644
--- a/platform/analysis-impl/src/com/intellij/codeInspection/ex/InspectionProfileImpl.java
+++ b/platform/analysis-impl/src/com/intellij/codeInspection/ex/InspectionProfileImpl.java
@@ -772,18 +772,17 @@ public class InspectionProfileImpl extends ProfileEx implements ModifiableModel,
return InspectionProfileImplHolder.DEFAULT_PROFILE;
}
- public Document saveToDocument() throws WriteExternalException {
+ public Element saveToDocument() throws WriteExternalException {
if (isLocal()) {
Element root = new Element(ROOT_ELEMENT_TAG);
root.setAttribute(PROFILE_NAME_TAG, myName);
writeExternal(root);
//myVisibleTreeState.writeExternal(root);
- return new Document(root);
+ return root;
}
else {
return null;
}
-
}
@Override
@@ -886,13 +885,13 @@ public class InspectionProfileImpl extends ProfileEx implements ModifiableModel,
getTools(toolId, project).removeScope(scopeIdx);
}
- public void removeScope(@NotNull String toolId, @NotNull NamedScope scope, Project project) {
- getTools(toolId, project).removeScope(scope);
+ public void removeScope(@NotNull String toolId, @NotNull String scopeName, Project project) {
+ getTools(toolId, project).removeScope(scopeName);
}
- public void removeScopes(@NotNull List<String> toolIds, @NotNull NamedScope scope, Project project) {
+ public void removeScopes(@NotNull List<String> toolIds, @NotNull String scopeName, Project project) {
for (final String toolId : toolIds) {
- removeScope(toolId, scope, project);
+ removeScope(toolId, scopeName, project);
}
}
diff --git a/platform/analysis-impl/src/com/intellij/codeInspection/ex/ToolsImpl.java b/platform/analysis-impl/src/com/intellij/codeInspection/ex/ToolsImpl.java
index 267c0ee67fc3..caeb02a2316f 100644
--- a/platform/analysis-impl/src/com/intellij/codeInspection/ex/ToolsImpl.java
+++ b/platform/analysis-impl/src/com/intellij/codeInspection/ex/ToolsImpl.java
@@ -267,25 +267,26 @@ public class ToolsImpl implements Tools {
public void removeScope(int scopeIdx) {
if (myTools != null && scopeIdx >= 0 && myTools.size() > scopeIdx) {
myTools.remove(scopeIdx);
- if (myTools.isEmpty()) {
- myTools = null;
- setEnabled(myDefaultState.isEnabled());
- }
+ checkToolsIsEmpty();
}
}
- public void removeScope(final NamedScope scope) {
+ public void removeScope(final @NotNull String scopeName) {
if (myTools != null) {
- for (final ScopeToolState tool : myTools) {
- if (Comparing.equal(tool.getScopeName(), scope.getName())) {
+ for (ScopeToolState tool : myTools) {
+ if (scopeName.equals(tool.getScopeName())) {
myTools.remove(tool);
break;
}
}
- if (myTools.isEmpty()) {
- myTools = null;
- setEnabled(myDefaultState.isEnabled());
- }
+ checkToolsIsEmpty();
+ }
+ }
+
+ private void checkToolsIsEmpty() {
+ if (myTools.isEmpty()) {
+ myTools = null;
+ setEnabled(myDefaultState.isEnabled());
}
}
diff --git a/platform/core-api/src/com/intellij/concurrency/AsyncUtil.java b/platform/core-api/src/com/intellij/concurrency/AsyncUtil.java
index 93c7573c0381..72c0a85aac72 100644
--- a/platform/core-api/src/com/intellij/concurrency/AsyncUtil.java
+++ b/platform/core-api/src/com/intellij/concurrency/AsyncUtil.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,12 +18,17 @@ package com.intellij.concurrency;
import org.jetbrains.annotations.NotNull;
import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
/**
* Author: dmitrylomov
*/
public class AsyncUtil {
+ private static final AsyncFuture<Boolean> TRUE = createConst(true);
+ private static final AsyncFuture<Boolean> FALSE = createConst(false);
+
public static <V> V get(@NotNull Future<V> result) {
try {
return result.get();
@@ -41,4 +46,43 @@ public class AsyncUtil {
}
}
}
+
+ private static AsyncFuture<Boolean> createConst(final boolean result) {
+ return new AsyncFuture<Boolean>() {
+ @Override
+ public void addConsumer(@NotNull Executor executor, @NotNull ResultConsumer<Boolean> consumer) {
+ consumer.onSuccess(result);
+ }
+
+ @Override
+ public boolean cancel(boolean mayInterruptIfRunning) {
+ return false;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return false;
+ }
+
+ @Override
+ public boolean isDone() {
+ return true;
+ }
+
+ @Override
+ public Boolean get() {
+ return result;
+ }
+
+ @Override
+ public Boolean get(long timeout, @NotNull TimeUnit unit) {
+ return result;
+ }
+ };
+ }
+
+ @NotNull
+ public static AsyncFuture<Boolean> wrapBoolean(boolean result) {
+ return result ? TRUE : FALSE;
+ }
}
diff --git a/platform/core-api/src/com/intellij/concurrency/DefaultResultConsumer.java b/platform/core-api/src/com/intellij/concurrency/DefaultResultConsumer.java
index 7230cd469e13..0e54993fe84b 100644
--- a/platform/core-api/src/com/intellij/concurrency/DefaultResultConsumer.java
+++ b/platform/core-api/src/com/intellij/concurrency/DefaultResultConsumer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,13 +15,15 @@
*/
package com.intellij.concurrency;
+import org.jetbrains.annotations.NotNull;
+
/**
* Author: dmitrylomov
*/
public class DefaultResultConsumer<V> implements ResultConsumer<V> {
private final AsyncFutureResult<V> myResult;
- public DefaultResultConsumer(AsyncFutureResult<V> result) {
+ public DefaultResultConsumer(@NotNull AsyncFutureResult<V> result) {
myResult = result;
}
@@ -31,7 +33,7 @@ public class DefaultResultConsumer<V> implements ResultConsumer<V> {
}
@Override
- public void onFailure(Throwable t) {
+ public void onFailure(@NotNull Throwable t) {
myResult.setException(t);
}
}
diff --git a/platform/core-api/src/com/intellij/concurrency/DoWhile.java b/platform/core-api/src/com/intellij/concurrency/DoWhile.java
deleted file mode 100644
index b77e3258c984..000000000000
--- a/platform/core-api/src/com/intellij/concurrency/DoWhile.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2000-2013 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.intellij.concurrency;
-
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Author: dmitrylomov
- */
-public abstract class DoWhile {
- private final AsyncFutureResult<Boolean> myResult = AsyncFutureFactory.getInstance().createAsyncFutureResult();
- private final SameThreadExecutorWithTrampoline myExecutor = new SameThreadExecutorWithTrampoline();
-
- @NotNull
- public AsyncFutureResult<Boolean> getResult() {
- body().addConsumer(myExecutor, new MyConsumer());
- return myResult;
- }
-
- @NotNull
- protected abstract AsyncFuture<Boolean> body();
- protected abstract boolean condition();
-
- private class MyConsumer extends DefaultResultConsumer<Boolean> {
- public MyConsumer() {
- super(DoWhile.this.myResult);
- }
-
- @Override
- public void onSuccess(Boolean value) {
- if (!value.booleanValue()) {
- myResult.set(false);
- }
- else {
- if(!condition()) {
- myResult.set(true);
- }
- else {
- body().addConsumer(myExecutor, this);
- }
- }
- }
- }
-
-
-}
diff --git a/platform/core-api/src/com/intellij/concurrency/Iterate.java b/platform/core-api/src/com/intellij/concurrency/Iterate.java
deleted file mode 100644
index e158999f4da5..000000000000
--- a/platform/core-api/src/com/intellij/concurrency/Iterate.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package com.intellij.concurrency;
-
-import org.jetbrains.annotations.NotNull;
-
-import java.util.Iterator;
-
-/**
- * Author: dmitrylomov
- */
-public abstract class Iterate<T> extends DoWhile {
- private final Iterator<T> myIterator;
- private boolean myIsDone;
-
- public Iterate(@NotNull Iterable<T> iterable) {
- myIterator = iterable.iterator();
- myIsDone = false;
- }
-
- @NotNull
- @Override
- protected final AsyncFuture<Boolean> body() {
- if (!myIterator.hasNext()) {
- myIsDone = true;
- return AsyncFutureFactory.wrap(true);
- }
- return process(myIterator.next());
- }
-
- @NotNull
- protected abstract AsyncFuture<Boolean> process(T t);
-
- @Override
- protected boolean condition() {
- return !myIsDone;
- }
-}
diff --git a/platform/core-api/src/com/intellij/concurrency/ResultConsumer.java b/platform/core-api/src/com/intellij/concurrency/ResultConsumer.java
index 80618f0b9c79..409d5a9439a4 100644
--- a/platform/core-api/src/com/intellij/concurrency/ResultConsumer.java
+++ b/platform/core-api/src/com/intellij/concurrency/ResultConsumer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,10 +15,12 @@
*/
package com.intellij.concurrency;
+import org.jetbrains.annotations.NotNull;
+
/**
* Author: dmitrylomov
*/
public interface ResultConsumer<V> {
void onSuccess(V value);
- void onFailure(Throwable t);
+ void onFailure(@NotNull Throwable t);
}
diff --git a/platform/core-api/src/com/intellij/lang/folding/CustomFoldingBuilder.java b/platform/core-api/src/com/intellij/lang/folding/CustomFoldingBuilder.java
index f43c1c9b55ae..ab03627d7d6a 100644
--- a/platform/core-api/src/com/intellij/lang/folding/CustomFoldingBuilder.java
+++ b/platform/core-api/src/com/intellij/lang/folding/CustomFoldingBuilder.java
@@ -45,7 +45,9 @@ public abstract class CustomFoldingBuilder extends FoldingBuilderEx implements P
if (CustomFoldingProvider.getAllProviders().length > 0) {
myDefaultProvider = null;
ASTNode rootNode = root.getNode();
- addCustomFoldingRegionsRecursively(new FoldingStack(rootNode), rootNode, descriptors, 0);
+ if (rootNode != null) {
+ addCustomFoldingRegionsRecursively(new FoldingStack(rootNode), rootNode, descriptors, 0);
+ }
}
buildLanguageFoldRegions(descriptors, root, document, quick);
return descriptors.toArray(new FoldingDescriptor[descriptors.size()]);
diff --git a/platform/core-api/src/com/intellij/openapi/components/RoamingType.java b/platform/core-api/src/com/intellij/openapi/components/RoamingType.java
index 0cbf78053953..ba4b6d8b36e6 100644
--- a/platform/core-api/src/com/intellij/openapi/components/RoamingType.java
+++ b/platform/core-api/src/com/intellij/openapi/components/RoamingType.java
@@ -16,5 +16,12 @@
package com.intellij.openapi.components;
public enum RoamingType {
- DISABLED, PER_PLATFORM, GLOBAL, PER_USER
+ DISABLED,
+ PER_PLATFORM,
+ @Deprecated
+ /**
+ * Use {@link #PER_USER} instead
+ */
+ GLOBAL,
+ PER_USER
}
diff --git a/platform/core-api/src/com/intellij/openapi/options/SchemeProcessor.java b/platform/core-api/src/com/intellij/openapi/options/SchemeProcessor.java
index 94ec194b9f89..5acdbe7cacf6 100644
--- a/platform/core-api/src/com/intellij/openapi/options/SchemeProcessor.java
+++ b/platform/core-api/src/com/intellij/openapi/options/SchemeProcessor.java
@@ -19,18 +19,22 @@ import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.WriteExternalException;
import org.jdom.Document;
import org.jdom.JDOMException;
+import org.jdom.Parent;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
public interface SchemeProcessor<T extends ExternalizableScheme> {
T readScheme(@NotNull Document schemeContent) throws InvalidDataException, IOException, JDOMException;
- Document writeScheme(@NotNull T scheme) throws WriteExternalException;
+
+ Parent writeScheme(@NotNull T scheme) throws WriteExternalException;
boolean shouldBeSaved(@NotNull T scheme);
+
void initScheme(@NotNull T scheme);
void onSchemeAdded(@NotNull T scheme);
+
void onSchemeDeleted(@NotNull T scheme);
void onCurrentSchemeChanged(final Scheme oldCurrentScheme);
diff --git a/platform/core-api/src/com/intellij/openapi/options/SchemesManagerFactory.java b/platform/core-api/src/com/intellij/openapi/options/SchemesManagerFactory.java
index a0c0ee7dad62..abd37269985f 100644
--- a/platform/core-api/src/com/intellij/openapi/options/SchemesManagerFactory.java
+++ b/platform/core-api/src/com/intellij/openapi/options/SchemesManagerFactory.java
@@ -25,9 +25,8 @@ public abstract class SchemesManagerFactory {
public static final ExtensionPointName<ServiceBean> SCHEME_OWNER = ExtensionPointName.create("com.intellij.schemeOwner");
public abstract <T extends Scheme, E extends ExternalizableScheme> SchemesManager<T, E> createSchemesManager(@NotNull String fileSpec,
- @NotNull SchemeProcessor<E> processor,
- @NotNull RoamingType roamingType);
-
+ @NotNull SchemeProcessor<E> processor, @NotNull RoamingType roamingType);
+ @NotNull
public static SchemesManagerFactory getInstance() {
return ServiceManager.getService(SchemesManagerFactory.class);
}
diff --git a/platform/core-api/src/com/intellij/openapi/progress/ProgressManager.java b/platform/core-api/src/com/intellij/openapi/progress/ProgressManager.java
index 3f0601ba951b..377bcc520e27 100644
--- a/platform/core-api/src/com/intellij/openapi/progress/ProgressManager.java
+++ b/platform/core-api/src/com/intellij/openapi/progress/ProgressManager.java
@@ -34,6 +34,7 @@ public abstract class ProgressManager extends ProgressIndicatorProvider {
private static final ProgressManager ourInstance = ServiceManager.getService(ProgressManager.class);
}
+ @NotNull
public static ProgressManager getInstance() {
return ProgressManagerHolder.ourInstance;
}
diff --git a/platform/core-api/src/com/intellij/openapi/vfs/ex/http/HttpFileSystem.java b/platform/core-api/src/com/intellij/openapi/vfs/ex/http/HttpFileSystem.java
index a42441fe49de..af6c670ab22a 100644
--- a/platform/core-api/src/com/intellij/openapi/vfs/ex/http/HttpFileSystem.java
+++ b/platform/core-api/src/com/intellij/openapi/vfs/ex/http/HttpFileSystem.java
@@ -23,13 +23,6 @@ import com.intellij.util.io.URLUtil;
import org.jetbrains.annotations.NotNull;
public abstract class HttpFileSystem extends DeprecatedVirtualFileSystem {
- @Deprecated
- @SuppressWarnings("UnusedDeclaration")
- /**
- * @deprecated use {@link com.intellij.util.io.URLUtil#HTTP_PROTOCOL}
- */
- public static final String PROTOCOL = URLUtil.HTTP_PROTOCOL;
-
public static HttpFileSystem getInstance() {
return (HttpFileSystem)VirtualFileManager.getInstance().getFileSystem(URLUtil.HTTP_PROTOCOL);
}
@@ -43,4 +36,4 @@ public abstract class HttpFileSystem extends DeprecatedVirtualFileSystem {
public abstract void removeFileListener(@NotNull HttpVirtualFileListener listener);
public abstract VirtualFile createChild(@NotNull VirtualFile parent, @NotNull String name, boolean isDirectory);
-} \ No newline at end of file
+}
diff --git a/platform/core-api/src/com/intellij/psi/util/CachedValuesManager.java b/platform/core-api/src/com/intellij/psi/util/CachedValuesManager.java
index a8a82bed411a..4c7c12d79906 100644
--- a/platform/core-api/src/com/intellij/psi/util/CachedValuesManager.java
+++ b/platform/core-api/src/com/intellij/psi/util/CachedValuesManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -42,9 +42,12 @@ public abstract class CachedValuesManager {
* @param trackValue if value tracking required. T should be trackable in this case.
* @return new CachedValue instance.
*/
+ @NotNull
public abstract <T> CachedValue<T> createCachedValue(@NotNull CachedValueProvider<T> provider, boolean trackValue);
+ @NotNull
public abstract <T,P> ParameterizedCachedValue<T,P> createParameterizedCachedValue(@NotNull ParameterizedCachedValueProvider<T,P> provider, boolean trackValue);
+ @NotNull
public <T> CachedValue<T> createCachedValue(@NotNull CachedValueProvider<T> provider) {
return createCachedValue(provider, true);
}
@@ -54,7 +57,6 @@ public abstract class CachedValuesManager {
@NotNull ParameterizedCachedValueProvider<T, P> provider,
boolean trackValue,
P parameter) {
-
ParameterizedCachedValue<T,P> value;
if (dataHolder instanceof UserDataHolderEx) {
@@ -100,6 +102,7 @@ public abstract class CachedValuesManager {
}
private final ConcurrentMap<String, Key<CachedValue>> keyForProvider = new ConcurrentHashMap<String, Key<CachedValue>>();
+ @NotNull
public <T> Key<CachedValue<T>> getKeyForClass(@NotNull Class<?> providerClass) {
String name = providerClass.getName();
assert name != null : providerClass + " doesn't have a name; can't be used for cache value provider";
diff --git a/platform/core-api/src/com/intellij/util/AbstractQuery.java b/platform/core-api/src/com/intellij/util/AbstractQuery.java
index 1c29ef6437ac..219aae614140 100644
--- a/platform/core-api/src/com/intellij/util/AbstractQuery.java
+++ b/platform/core-api/src/com/intellij/util/AbstractQuery.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,9 +16,7 @@
package com.intellij.util;
import com.intellij.concurrency.AsyncFuture;
-import com.intellij.concurrency.AsyncFutureFactory;
-import com.intellij.concurrency.AsyncFutureResult;
-import com.intellij.concurrency.FinallyFuture;
+import com.intellij.concurrency.AsyncUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -84,26 +82,13 @@ public abstract class AbstractQuery<Result> implements Query<Result> {
@NotNull
@Override
public AsyncFuture<Boolean> forEachAsync(@NotNull Processor<Result> consumer) {
- assertNotProcessing();
- myIsProcessing = true;
- return new FinallyFuture<Boolean>(processResultsAsync(consumer), new Runnable() {
- @Override
- public void run() {
- myIsProcessing = false;
- }
- });
+ return AsyncUtil.wrapBoolean(forEach(consumer));
}
protected abstract boolean processResults(@NotNull Processor<Result> consumer);
@NotNull
protected AsyncFuture<Boolean> processResultsAsync(@NotNull Processor<Result> consumer) {
- final AsyncFutureResult<Boolean> result = AsyncFutureFactory.getInstance().createAsyncFutureResult();
- try {
- result.set(processResults(consumer));
- } catch (Throwable t) {
- result.setException(t);
- }
- return result;
+ return AsyncUtil.wrapBoolean(processResults(consumer));
}
}
diff --git a/platform/core-api/src/com/intellij/util/ArrayQuery.java b/platform/core-api/src/com/intellij/util/ArrayQuery.java
index abe2f1001fe0..1b7760146de6 100644
--- a/platform/core-api/src/com/intellij/util/ArrayQuery.java
+++ b/platform/core-api/src/com/intellij/util/ArrayQuery.java
@@ -17,8 +17,7 @@
package com.intellij.util;
import com.intellij.concurrency.AsyncFuture;
-import com.intellij.concurrency.AsyncFutureFactory;
-import com.intellij.concurrency.AsyncFutureResult;
+import com.intellij.concurrency.AsyncUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
@@ -55,13 +54,7 @@ public class ArrayQuery<T> implements Query<T> {
@NotNull
@Override
public AsyncFuture<Boolean> forEachAsync(@NotNull final Processor<T> consumer) {
- final AsyncFutureResult<Boolean> result = AsyncFutureFactory.getInstance().createAsyncFutureResult();
- try {
- result.set(forEach(consumer));
- } catch (Throwable t){
- result.setException(t);
- }
- return result;
+ return AsyncUtil.wrapBoolean(forEach(consumer));
}
diff --git a/platform/core-api/src/com/intellij/util/CollectionQuery.java b/platform/core-api/src/com/intellij/util/CollectionQuery.java
index cd90ab55edd9..253182cef0c1 100644
--- a/platform/core-api/src/com/intellij/util/CollectionQuery.java
+++ b/platform/core-api/src/com/intellij/util/CollectionQuery.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,8 +17,7 @@
package com.intellij.util;
import com.intellij.concurrency.AsyncFuture;
-import com.intellij.concurrency.AsyncFutureFactory;
-import com.intellij.concurrency.AsyncFutureResult;
+import com.intellij.concurrency.AsyncUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
@@ -55,13 +54,7 @@ public class CollectionQuery<T> implements Query<T> {
@NotNull
@Override
public AsyncFuture<Boolean> forEachAsync(@NotNull Processor<T> consumer) {
- AsyncFutureResult<Boolean> result = AsyncFutureFactory.getInstance().createAsyncFutureResult();
- try {
- result.set(forEach(consumer));
- } catch (Throwable t) {
- result.setException(t);
- }
- return result;
+ return AsyncUtil.wrapBoolean(forEach(consumer));
}
@NotNull
diff --git a/platform/core-api/src/com/intellij/util/EmptyQuery.java b/platform/core-api/src/com/intellij/util/EmptyQuery.java
index 465100505450..18a32a5a94b4 100644
--- a/platform/core-api/src/com/intellij/util/EmptyQuery.java
+++ b/platform/core-api/src/com/intellij/util/EmptyQuery.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@
package com.intellij.util;
import com.intellij.concurrency.AsyncFuture;
-import com.intellij.concurrency.AsyncFutureFactory;
+import com.intellij.concurrency.AsyncUtil;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
@@ -48,7 +48,7 @@ public class EmptyQuery<R> implements Query<R> {
@NotNull
@Override
public AsyncFuture<Boolean> forEachAsync(@NotNull Processor<R> consumer) {
- return AsyncFutureFactory.wrap(true);
+ return AsyncUtil.wrapBoolean(true);
}
@NotNull
diff --git a/platform/core-api/src/com/intellij/util/MergeQuery.java b/platform/core-api/src/com/intellij/util/MergeQuery.java
index 699659b93055..35d122639cd3 100644
--- a/platform/core-api/src/com/intellij/util/MergeQuery.java
+++ b/platform/core-api/src/com/intellij/util/MergeQuery.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -66,13 +66,13 @@ public class MergeQuery<T> implements Query<T>{
fq.addConsumer(SameThreadExecutor.INSTANCE, new DefaultResultConsumer<Boolean>(result) {
@Override
public void onSuccess(Boolean value) {
- if (!value.booleanValue()) {
- result.set(false);
- }
- else {
+ if (value.booleanValue()) {
final AsyncFuture<Boolean> fq2 = processSubQueryAsync(consumer, myQuery2);
fq2.addConsumer(SameThreadExecutor.INSTANCE, new DefaultResultConsumer<Boolean>(result));
}
+ else {
+ result.set(false);
+ }
}
});
return result;
@@ -85,12 +85,7 @@ public class MergeQuery<T> implements Query<T>{
}
private <V extends T> AsyncFuture<Boolean> processSubQueryAsync(@NotNull final Processor<T> consumer, @NotNull Query<V> query1) {
- return query1.forEachAsync(new Processor<V>() {
- @Override
- public boolean process(final V t) {
- return consumer.process(t);
- }
- });
+ return query1.forEachAsync((Processor<V>)consumer);
}
@NotNull
diff --git a/platform/core-impl/src/com/intellij/core/CoreApplicationEnvironment.java b/platform/core-impl/src/com/intellij/core/CoreApplicationEnvironment.java
index f82e7a80d5fb..cbb35b4f9812 100644
--- a/platform/core-impl/src/com/intellij/core/CoreApplicationEnvironment.java
+++ b/platform/core-impl/src/com/intellij/core/CoreApplicationEnvironment.java
@@ -36,10 +36,7 @@ import com.intellij.openapi.extensions.ExtensionsArea;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileTypes.*;
import com.intellij.openapi.progress.*;
-import com.intellij.openapi.util.ClassExtension;
-import com.intellij.openapi.util.Disposer;
-import com.intellij.openapi.util.KeyedExtensionCollector;
-import com.intellij.openapi.util.StaticGetter;
+import com.intellij.openapi.util.*;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.openapi.vfs.VirtualFileSystem;
import com.intellij.openapi.vfs.encoding.EncodingRegistry;
@@ -175,15 +172,7 @@ public class CoreApplicationEnvironment {
ProgressIndicator progress,
boolean failFastOnAcquireReadAction,
@NotNull Processor<T> thingProcessor) {
- final AsyncFutureResult<Boolean> asyncFutureResult = AsyncFutureFactory.getInstance().createAsyncFutureResult();
- try {
- final boolean result = invokeConcurrentlyUnderProgress(things, progress, failFastOnAcquireReadAction, thingProcessor);
- asyncFutureResult.set(result);
- }
- catch (Throwable t) {
- asyncFutureResult.setException(t);
- }
- return asyncFutureResult;
+ return AsyncUtil.wrapBoolean(invokeConcurrentlyUnderProgress(things, progress, failFastOnAcquireReadAction, thingProcessor));
}
@NotNull
diff --git a/platform/core-impl/src/com/intellij/ide/plugins/IdeaPluginDescriptorImpl.java b/platform/core-impl/src/com/intellij/ide/plugins/IdeaPluginDescriptorImpl.java
index 72d290e61e25..939ab753574b 100644
--- a/platform/core-impl/src/com/intellij/ide/plugins/IdeaPluginDescriptorImpl.java
+++ b/platform/core-impl/src/com/intellij/ide/plugins/IdeaPluginDescriptorImpl.java
@@ -53,17 +53,17 @@ import java.util.*;
* @author mike
*/
public class IdeaPluginDescriptorImpl implements IdeaPluginDescriptor {
- private static final Logger LOG = Logger.getInstance("#com.intellij.ide.plugins.PluginDescriptor");
-
public static final IdeaPluginDescriptorImpl[] EMPTY_ARRAY = new IdeaPluginDescriptorImpl[0];
- private String myName;
- private PluginId myId;
+ private static final Logger LOG = Logger.getInstance("#com.intellij.ide.plugins.PluginDescriptor");
+ private static final StringInterner ourInterner = new WeakStringInterner();
private final NullableLazyValue<String> myDescription = new NullableLazyValue<String>() {
@Override
protected String compute() {
return computeDescription();
}
};
+ private String myName;
+ private PluginId myId;
private String myResourceBundleBaseName;
private String myChangeNotes;
private String myVersion;
@@ -93,39 +93,62 @@ public class IdeaPluginDescriptorImpl implements IdeaPluginDescriptor {
private boolean myUseIdeaClassLoader;
private boolean myUseCoreClassLoader;
private boolean myEnabled = true;
-
private String mySinceBuild;
private String myUntilBuild;
-
private Boolean mySkipped;
-
private List<String> myModules = null;
public IdeaPluginDescriptorImpl(@NotNull File pluginPath) {
myPath = pluginPath;
}
- IdeaPluginDescriptorImpl() {
+ @NotNull
+ public static String intern(@NotNull String s) {
+ return ourInterner.intern(s);
}
- public void setPath(@NotNull File path) {
- myPath = path;
+ public static void internJDOMElement(@NotNull Element rootElement) {
+ JDOMUtil.internElement(rootElement, ourInterner);
}
- @Override
- public File getPath() {
- return myPath;
+ @Nullable
+ private static List<Element> copyElements(final Element[] elements) {
+ if (elements != null) {
+ List<Element> result = new ArrayList<Element>();
+ for (Element extensionsRoot : elements) {
+ for (final Object o : extensionsRoot.getChildren()) {
+ Element element = (Element)o;
+ internJDOMElement(element);
+ result.add(element);
+ }
+ }
+ return result;
+ }
+ return null;
}
- private static final StringInterner ourInterner = new WeakStringInterner();
+ @SuppressWarnings({"HardCodedStringLiteral"})
+ private static String createDescriptionKey(final PluginId id) {
+ return "plugin." + id + ".description";
+ }
- @NotNull
- public static String intern(@NotNull String s) {
- return ourInterner.intern(s);
+ private static ComponentConfig[] mergeComponents(ComponentConfig[] first, ComponentConfig[] second) {
+ if (first == null) {
+ return second;
+ }
+ if (second == null) {
+ return first;
+ }
+ return ArrayUtil.mergeArrays(first, second);
}
- public static void internJDOMElement(@NotNull Element rootElement) {
- JDOMUtil.internElement(rootElement, ourInterner);
+ @Override
+ public File getPath() {
+ return myPath;
+ }
+
+ public void setPath(@NotNull File path) {
+ myPath = path;
}
public void readExternal(@NotNull Document document, @NotNull URL url) throws InvalidDataException, FileNotFoundException {
@@ -243,7 +266,7 @@ public class IdeaPluginDescriptorImpl implements IdeaPluginDescriptor {
myExtensions.putValue(ExtensionsAreaImpl.extractEPName(extension), extension);
}
}
-
+
List<Element> extensionPoints = copyElements(pluginBean.extensionPoints);
if (extensionPoints != null) {
myExtensionsPoints = new MultiMap<String, Element>();
@@ -251,7 +274,7 @@ public class IdeaPluginDescriptorImpl implements IdeaPluginDescriptor {
myExtensionsPoints.putValue(extensionPoint.getAttributeValue(ExtensionsAreaImpl.ATTRIBUTE_AREA), extensionPoint);
}
}
-
+
myActionsElements = copyElements(pluginBean.actions);
if (pluginBean.modules != null && !pluginBean.modules.isEmpty()) {
@@ -259,27 +282,6 @@ public class IdeaPluginDescriptorImpl implements IdeaPluginDescriptor {
}
}
- @Nullable
- private static List<Element> copyElements(final Element[] elements) {
- if (elements != null) {
- List<Element> result = new ArrayList<Element>();
- for (Element extensionsRoot : elements) {
- for (final Object o : extensionsRoot.getChildren()) {
- Element element = (Element)o;
- internJDOMElement(element);
- result.add(element);
- }
- }
- return result;
- }
- return null;
- }
-
- @SuppressWarnings({"HardCodedStringLiteral"})
- private static String createDescriptionKey(final PluginId id) {
- return "plugin." + id + ".description";
- }
-
void registerExtensionPoints(ExtensionsArea area) {
if (myExtensionsPoints != null) {
for (Element element : myExtensionsPoints.get(area.getAreaClass())) {
@@ -317,7 +319,6 @@ public class IdeaPluginDescriptorImpl implements IdeaPluginDescriptor {
return myDependencies;
}
-
@Override
@NotNull
public PluginId[] getOptionalDependentPluginIds() {
@@ -329,6 +330,11 @@ public class IdeaPluginDescriptorImpl implements IdeaPluginDescriptor {
return myVendor;
}
+ public void setVendor( final String val )
+ {
+ myVendor = val;
+ }
+
@Override
public String getVersion() {
return myVersion;
@@ -344,6 +350,17 @@ public class IdeaPluginDescriptorImpl implements IdeaPluginDescriptor {
return myCategory;
}
+ /*
+ This setter was explicitly defined to be able to set a category for a
+ descriptor outside its loading from the xml file.
+ Problem was that most commonly plugin authors do not publish the plugin's
+ category in its .xml file so to be consistent in plugins representation
+ (e.g. in the Plugins form) we have to set this value outside.
+ */
+ public void setCategory( String category ){
+ myCategory = category;
+ }
+
@SuppressWarnings("UnusedDeclaration") // Used in Upsource
@Nullable
public MultiMap<String, Element> getExtensionsPoints() {
@@ -418,16 +435,31 @@ public class IdeaPluginDescriptorImpl implements IdeaPluginDescriptor {
return myVendorEmail;
}
+ public void setVendorEmail( final String val )
+ {
+ myVendorEmail = val;
+ }
+
@Override
public String getVendorUrl() {
return myVendorUrl;
}
+ public void setVendorUrl( final String val )
+ {
+ myVendorUrl = val;
+ }
+
@Override
public String getUrl() {
return url;
}
+ public void setUrl( final String val )
+ {
+ url = val;
+ }
+
@NonNls
public String toString() {
return "PluginDescriptor[name='" + myName + "', classpath='" + myPath + "']";
@@ -470,17 +502,6 @@ public class IdeaPluginDescriptorImpl implements IdeaPluginDescriptor {
}
/*
- This setter was explicitly defined to be able to set a category for a
- descriptor outside its loading from the xml file.
- Problem was that most commonly plugin authors do not publish the plugin's
- category in its .xml file so to be consistent in plugins representation
- (e.g. in the Plugins form) we have to set this value outside.
- */
- public void setCategory( String category ){
- myCategory = category;
- }
-
- /*
This setter was explicitly defined to be able to set downloads count for a
descriptor outside its loading from the xml file since this information
is available only from the site.
@@ -494,6 +515,10 @@ public class IdeaPluginDescriptorImpl implements IdeaPluginDescriptor {
return myDownloadCounter;
}
+ public long getDate(){
+ return myDate;
+ }
+
/*
This setter was explicitly defined to be able to set date for a
descriptor outside its loading from the xml file since this information
@@ -503,27 +528,6 @@ public class IdeaPluginDescriptorImpl implements IdeaPluginDescriptor {
myDate = date;
}
- public long getDate(){
- return myDate;
- }
-
- public void setVendor( final String val )
- {
- myVendor = val;
- }
- public void setVendorEmail( final String val )
- {
- myVendorEmail = val;
- }
- public void setVendorUrl( final String val )
- {
- myVendorUrl = val;
- }
- public void setUrl( final String val )
- {
- url = val;
- }
-
@Override
public ClassLoader getPluginClassLoader() {
return myLoader != null ? myLoader : getClass().getClassLoader();
@@ -534,6 +538,10 @@ public class IdeaPluginDescriptorImpl implements IdeaPluginDescriptor {
return myVendorLogoPath;
}
+ public void setVendorLogoPath(final String vendorLogoPath) {
+ myVendorLogoPath = vendorLogoPath;
+ }
+
@Override
public boolean getUseIdeaClassLoader() {
return myUseIdeaClassLoader;
@@ -547,10 +555,6 @@ public class IdeaPluginDescriptorImpl implements IdeaPluginDescriptor {
myUseCoreClassLoader = useCoreClassLoader;
}
- public void setVendorLogoPath(final String vendorLogoPath) {
- myVendorLogoPath = vendorLogoPath;
- }
-
private String computeDescription() {
ResourceBundle bundle = null;
if (myResourceBundleBaseName != null) {
@@ -635,16 +639,6 @@ public class IdeaPluginDescriptorImpl implements IdeaPluginDescriptor {
myModuleComponents = mergeComponents(myModuleComponents, descriptor.myModuleComponents);
}
- private static ComponentConfig[] mergeComponents(ComponentConfig[] first, ComponentConfig[] second) {
- if (first == null) {
- return second;
- }
- if (second == null) {
- return first;
- }
- return ArrayUtil.mergeArrays(first, second);
- }
-
public Boolean getSkipped() {
return mySkipped;
}
diff --git a/platform/core-impl/src/com/intellij/mock/MockComponentManager.java b/platform/core-impl/src/com/intellij/mock/MockComponentManager.java
index c026211c232a..8e047fe60b4d 100644
--- a/platform/core-impl/src/com/intellij/mock/MockComponentManager.java
+++ b/platform/core-impl/src/com/intellij/mock/MockComponentManager.java
@@ -20,6 +20,7 @@ import com.intellij.openapi.components.BaseComponent;
import com.intellij.openapi.components.ComponentManager;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.util.Condition;
+import com.intellij.openapi.util.Conditions;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.UserDataHolderBase;
import com.intellij.util.containers.ConcurrentHashSet;
@@ -137,6 +138,6 @@ public class MockComponentManager extends UserDataHolderBase implements Componen
@NotNull
@Override
public Condition getDisposed() {
- return Condition.FALSE;
+ return Conditions.alwaysFalse();
}
}
diff --git a/platform/core-impl/src/com/intellij/openapi/util/JDOMExternalizableAdapter.java b/platform/core-impl/src/com/intellij/openapi/util/JDOMExternalizableAdapter.java
index 5248f4a0e535..8ba56e77f160 100644
--- a/platform/core-impl/src/com/intellij/openapi/util/JDOMExternalizableAdapter.java
+++ b/platform/core-impl/src/com/intellij/openapi/util/JDOMExternalizableAdapter.java
@@ -20,8 +20,10 @@ import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.diagnostic.Logger;
import org.jdom.Element;
+@Deprecated
/**
* @author Dmitry Avdeev
+ * @deprecated to remove in IDEA 14
*/
public class JDOMExternalizableAdapter implements PersistentStateComponent<Element> {
diff --git a/platform/core-impl/src/com/intellij/openapi/vfs/impl/http/HttpVirtualFile.java b/platform/core-impl/src/com/intellij/openapi/vfs/impl/http/HttpVirtualFile.java
index 990418dc9c51..1e0f0bcd68b5 100644
--- a/platform/core-impl/src/com/intellij/openapi/vfs/impl/http/HttpVirtualFile.java
+++ b/platform/core-impl/src/com/intellij/openapi/vfs/impl/http/HttpVirtualFile.java
@@ -16,10 +16,12 @@
package com.intellij.openapi.vfs.impl.http;
import com.intellij.openapi.vfs.VirtualFile;
+import org.jetbrains.annotations.Nullable;
/**
* @author nik
*/
public abstract class HttpVirtualFile extends VirtualFile {
+ @Nullable
public abstract RemoteFileInfo getFileInfo();
}
diff --git a/platform/core-impl/src/com/intellij/psi/MultiplePsiFilesPerDocumentFileViewProvider.java b/platform/core-impl/src/com/intellij/psi/MultiplePsiFilesPerDocumentFileViewProvider.java
index c6554f83fb7a..d8291fbd7f8d 100644
--- a/platform/core-impl/src/com/intellij/psi/MultiplePsiFilesPerDocumentFileViewProvider.java
+++ b/platform/core-impl/src/com/intellij/psi/MultiplePsiFilesPerDocumentFileViewProvider.java
@@ -97,10 +97,11 @@ public abstract class MultiplePsiFilesPerDocumentFileViewProvider extends Single
@Override
- public PsiFile getCachedPsi(Language target) {
+ public PsiFile getCachedPsi(@NotNull Language target) {
return myRoots.get(target);
}
+ @NotNull
@Override
public FileElement[] getKnownTreeRoots() {
List<FileElement> files = new ArrayList<FileElement>(myRoots.size());
diff --git a/platform/core-impl/src/com/intellij/psi/SingleRootFileViewProvider.java b/platform/core-impl/src/com/intellij/psi/SingleRootFileViewProvider.java
index bed56c25292d..63a7f205c11c 100644
--- a/platform/core-impl/src/com/intellij/psi/SingleRootFileViewProvider.java
+++ b/platform/core-impl/src/com/intellij/psi/SingleRootFileViewProvider.java
@@ -53,6 +53,7 @@ import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.util.Collections;
import java.util.List;
@@ -68,7 +69,7 @@ public class SingleRootFileViewProvider extends UserDataHolderBase implements Fi
private final boolean myPhysical;
private final AtomicReference<PsiFile> myPsiFile = new AtomicReference<PsiFile>();
private volatile Content myContent;
- private volatile SoftReference<Document> myDocument;
+ private volatile Reference<Document> myDocument;
@NotNull private final Language myBaseLanguage;
public SingleRootFileViewProvider(@NotNull PsiManager manager, @NotNull VirtualFile file) {
@@ -213,10 +214,11 @@ public class SingleRootFileViewProvider extends UserDataHolderBase implements Fi
}
- public PsiFile getCachedPsi(Language target) {
+ public PsiFile getCachedPsi(@NotNull Language target) {
return myPsiFile.get();
}
+ @NotNull
public FileElement[] getKnownTreeRoots() {
PsiFile psiFile = myPsiFile.get();
if (psiFile == null || !(psiFile instanceof PsiFileImpl)) return new FileElement[0];
@@ -257,8 +259,7 @@ public class SingleRootFileViewProvider extends UserDataHolderBase implements Fi
protected boolean isIgnored() {
final VirtualFile file = getVirtualFile();
- if (file instanceof LightVirtualFile) return false;
- return FileTypeRegistry.getInstance().isFileIgnored(file);
+ return !(file instanceof LightVirtualFile) && FileTypeRegistry.getInstance().isFileIgnored(file);
}
@Nullable
@@ -357,7 +358,7 @@ public class SingleRootFileViewProvider extends UserDataHolderBase implements Fi
Document document = com.intellij.reference.SoftReference.dereference(myDocument);
if (document == null/* TODO[ik] make this change && isEventSystemEnabled()*/) {
document = FileDocumentManager.getInstance().getDocument(getVirtualFile());
- myDocument = new SoftReference<Document>(document);
+ myDocument = document == null ? null : new SoftReference<Document>(document);
}
if (document != null && getContent() instanceof VirtualFileContent) {
setContent(new DocumentContent());
@@ -446,16 +447,17 @@ public class SingleRootFileViewProvider extends UserDataHolderBase implements Fi
return null;
}
- public void forceCachedPsi(final PsiFile psiFile) {
+ public void forceCachedPsi(@NotNull PsiFile psiFile) {
myPsiFile.set(psiFile);
((PsiManagerEx)myManager).getFileManager().setViewProvider(getVirtualFile(), this);
}
+ @NotNull
private Content getContent() {
return myContent;
}
- private void setContent(final Content content) {
+ private void setContent(@NotNull Content content) {
// temporarily commented
//if (myPhysical) {
// final Content oldContent = myContent;
diff --git a/platform/core-impl/src/com/intellij/psi/impl/file/impl/FileManagerImpl.java b/platform/core-impl/src/com/intellij/psi/impl/file/impl/FileManagerImpl.java
index 6b2877d83351..e54b200507ca 100644
--- a/platform/core-impl/src/com/intellij/psi/impl/file/impl/FileManagerImpl.java
+++ b/platform/core-impl/src/com/intellij/psi/impl/file/impl/FileManagerImpl.java
@@ -527,6 +527,7 @@ public class FileManagerImpl implements FileManager {
}
void reloadFromDisk(@NotNull PsiFile file, boolean ignoreDocument) {
+ ApplicationManager.getApplication().assertWriteAccessAllowed();
VirtualFile vFile = file.getVirtualFile();
assert vFile != null;
diff --git a/platform/core-impl/src/com/intellij/psi/impl/source/tree/CompositeElement.java b/platform/core-impl/src/com/intellij/psi/impl/source/tree/CompositeElement.java
index c73d0bd485ce..f8bfc611ce55 100644
--- a/platform/core-impl/src/com/intellij/psi/impl/source/tree/CompositeElement.java
+++ b/platform/core-impl/src/com/intellij/psi/impl/source/tree/CompositeElement.java
@@ -54,10 +54,10 @@ public class CompositeElement extends TreeElement {
private TreeElement firstChild = null;
private TreeElement lastChild = null;
- private volatile int myModificationsCount = 0;
+ private volatile int myModificationsCount;
private volatile int myCachedLength = -1;
private volatile int myHC = -1;
- private volatile PsiElement myWrapper = null;
+ private volatile PsiElement myWrapper;
private static final boolean ASSERT_THREADING = true;//DebugUtil.CHECK || ApplicationManagerEx.getApplicationEx().isInternal() || ApplicationManagerEx.getApplicationEx().isUnitTestMode();
public CompositeElement(@NotNull IElementType type) {
diff --git a/platform/core-impl/src/com/intellij/psi/impl/source/tree/FileElement.java b/platform/core-impl/src/com/intellij/psi/impl/source/tree/FileElement.java
index 76d5c421094d..d3071ddbca7d 100644
--- a/platform/core-impl/src/com/intellij/psi/impl/source/tree/FileElement.java
+++ b/platform/core-impl/src/com/intellij/psi/impl/source/tree/FileElement.java
@@ -70,7 +70,7 @@ public class FileElement extends LazyParseableElement implements FileASTNode, Ge
return psiElementCopy.getTreeElement();
}
- public void setCharTable(CharTable table) {
+ public void setCharTable(@NotNull CharTable table) {
myCharTable = table;
}
diff --git a/platform/core-impl/src/com/intellij/refactoring/rename/FragmentaryPsiReference.java b/platform/core-impl/src/com/intellij/refactoring/rename/FragmentaryPsiReference.java
new file mode 100644
index 000000000000..49a3c5a0cc3c
--- /dev/null
+++ b/platform/core-impl/src/com/intellij/refactoring/rename/FragmentaryPsiReference.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.refactoring.rename;
+
+public interface FragmentaryPsiReference extends BindablePsiReference {
+ boolean isReadOnlyFragment();
+ boolean isFragmentOnlyRename();
+}
diff --git a/platform/core-impl/src/com/intellij/util/CachedValuesManagerImpl.java b/platform/core-impl/src/com/intellij/util/CachedValuesManagerImpl.java
index 9c05387f2137..e63589b40cb5 100644
--- a/platform/core-impl/src/com/intellij/util/CachedValuesManagerImpl.java
+++ b/platform/core-impl/src/com/intellij/util/CachedValuesManagerImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -36,11 +36,13 @@ public class CachedValuesManagerImpl extends CachedValuesManager {
myFactory = factory == null ? new DefaultCachedValuesFactory(project) : factory;
}
+ @NotNull
@Override
public <T> CachedValue<T> createCachedValue(@NotNull CachedValueProvider<T> provider, boolean trackValue) {
return myFactory.createCachedValue(provider, trackValue);
}
+ @NotNull
@Override
public <T,P> ParameterizedCachedValue<T,P> createParameterizedCachedValue(@NotNull ParameterizedCachedValueProvider<T,P> provider, boolean trackValue) {
return myFactory.createParameterizedCachedValue(provider, trackValue);
diff --git a/platform/dvcs-api/src/com/intellij/dvcs/push/PushSupport.java b/platform/dvcs-api/src/com/intellij/dvcs/push/PushSupport.java
index fbf6f148c3b1..a1ffabfab844 100644
--- a/platform/dvcs-api/src/com/intellij/dvcs/push/PushSupport.java
+++ b/platform/dvcs-api/src/com/intellij/dvcs/push/PushSupport.java
@@ -19,12 +19,9 @@ import com.intellij.dvcs.repo.Repository;
import com.intellij.dvcs.repo.RepositoryManager;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.vcs.AbstractVcs;
-import com.intellij.ui.SimpleColoredText;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import java.util.List;
-
/**
* Base class to provide vcs-specific info
*/
@@ -50,27 +47,12 @@ public abstract class PushSupport<Repo extends Repository, Source extends PushSo
public abstract Target getDefaultTarget(@NotNull Repo repository);
/**
- * @return All remote destinations which will be proposed to user in the target field completion.
- * They will be shown in the same order as they appear in the returned list.
- */
- @NotNull
- public abstract List<String> getTargetNames(@NotNull Repo repository);
-
- /**
* @return current source(branch) for repository
*/
@NotNull
public abstract Source getSource(@NotNull Repo repository);
/**
- * Parse user input string, and create the VALID target for push
- *
- * @see #validateSpec(Repository, PushSpec)
- */
- @NotNull
- public abstract Target createTarget(@NotNull Repo repository, @NotNull String targetName);
-
- /**
* @return RepositoryManager for vcs
*/
@NotNull
@@ -81,11 +63,7 @@ public abstract class PushSupport<Repo extends Repository, Source extends PushSo
return null;
}
- /**
- * @return null if target is valid for selected repository
- */
- @Nullable
- public abstract VcsError validate(@NotNull Repo repository, @Nullable String targetToValidate);
+ @NotNull
+ public abstract PushTargetPanel<Target> createTargetPanel(@NotNull Repo repository, @Nullable Target defaultTarget);
- public abstract SimpleColoredText renderTarget(@Nullable Target target);
}
diff --git a/platform/dvcs-api/src/com/intellij/dvcs/push/PushTarget.java b/platform/dvcs-api/src/com/intellij/dvcs/push/PushTarget.java
index d7ed69d0875c..df6bfaefa79b 100644
--- a/platform/dvcs-api/src/com/intellij/dvcs/push/PushTarget.java
+++ b/platform/dvcs-api/src/com/intellij/dvcs/push/PushTarget.java
@@ -15,15 +15,9 @@
*/
package com.intellij.dvcs.push;
-import org.jetbrains.annotations.NotNull;
-
-
/**
* Destination for push action. (Remote for git or push-path for mercurial).
*/
public interface PushTarget {
- @NotNull
- //todo rename - > getName or smth
- String getPresentation();
}
diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyNewProject.java b/platform/dvcs-api/src/com/intellij/dvcs/push/PushTargetPanel.java
index 0b75c4bc01c4..ede2f17410ee 100644
--- a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyNewProject.java
+++ b/platform/dvcs-api/src/com/intellij/dvcs/push/PushTargetPanel.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,22 +13,26 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.jetbrains.python.edu.actions;
+package com.intellij.dvcs.push;
-import com.jetbrains.python.edu.StudyDirectoryProjectGenerator;
-import com.jetbrains.python.newProject.actions.GenerateProjectCallback;
-import com.jetbrains.python.newProject.actions.ProjectSpecificAction;
+import com.intellij.openapi.ui.ValidationInfo;
+import com.intellij.ui.ColoredTreeCellRenderer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-public class StudyNewProject extends ProjectSpecificAction {
+import javax.swing.*;
- public StudyNewProject(@NotNull final String name, @Nullable final Runnable runnable) {
- super(new GenerateProjectCallback(runnable), new StudyDirectoryProjectGenerator(), name, true);
- }
+public abstract class PushTargetPanel<T extends PushTarget> extends JPanel {
- public StudyNewProject() {
- this("Learn Python", null);
- }
+ abstract public void render(@NotNull ColoredTreeCellRenderer renderer);
+ @NotNull
+ abstract public T getValue();
+
+ public abstract void fireOnCancel();
+
+ public abstract void fireOnChange();
+
+ @Nullable
+ public abstract ValidationInfo verify();
}
diff --git a/platform/dvcs-api/src/com/intellij/dvcs/push/VcsError.java b/platform/dvcs-api/src/com/intellij/dvcs/push/VcsError.java
index b76095629ccd..e6c0e210429a 100644
--- a/platform/dvcs-api/src/com/intellij/dvcs/push/VcsError.java
+++ b/platform/dvcs-api/src/com/intellij/dvcs/push/VcsError.java
@@ -42,6 +42,6 @@ public class VcsError {
}
public static VcsError createEmptyTargetError(@NotNull String name) {
- return new VcsError("Please, specify remote push path for repository " + name + ".");
+ return new VcsError("Please, specify not empty remote push path for repository " + name + ".");
}
}
diff --git a/platform/dvcs-api/src/com/intellij/dvcs/repo/Repository.java b/platform/dvcs-api/src/com/intellij/dvcs/repo/Repository.java
index 47cc17866c08..a71df5c39307 100644
--- a/platform/dvcs-api/src/com/intellij/dvcs/repo/Repository.java
+++ b/platform/dvcs-api/src/com/intellij/dvcs/repo/Repository.java
@@ -48,12 +48,9 @@ import org.jetbrains.annotations.Nullable;
* If one needs a really 100 % up-to-date value, one should call {@link #update()} and then get...().
* update() is a synchronous read from repository file (.git or .hg), so it is guaranteed to query the real value.
* </p>
- *
- * @author Nadya Zabrodina
*/
public interface Repository extends Disposable {
-
/**
* Current state of the repository.
*/
@@ -62,24 +59,29 @@ public interface Repository extends Disposable {
* HEAD is on branch, no merge process is in progress (and no rebase as well).
*/
NORMAL,
+
/**
* During merge (for instance, merge failed with conflicts that weren't immediately resolved).
*/
MERGING {
+ @NotNull
@Override
public String toString() {
return "Merging";
}
},
+
/**
* During rebase.
*/
REBASING {
+ @NotNull
@Override
public String toString() {
return "Rebasing";
}
},
+
/**
* Detached HEAD state, but not during rebase (for example, manual checkout of a commit hash).
*/
@@ -99,6 +101,9 @@ public interface Repository extends Disposable {
State getState();
@Nullable
+ String getCurrentBranchName();
+
+ @Nullable
AbstractVcs getVcs();
/**
diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/DvcsCommitAdditionalComponent.java b/platform/dvcs-impl/src/com/intellij/dvcs/DvcsCommitAdditionalComponent.java
index 26c87c7de627..76d58125b719 100644
--- a/platform/dvcs-impl/src/com/intellij/dvcs/DvcsCommitAdditionalComponent.java
+++ b/platform/dvcs-impl/src/com/intellij/dvcs/DvcsCommitAdditionalComponent.java
@@ -43,9 +43,6 @@ import java.io.File;
import java.util.*;
import java.util.List;
-/**
- * @author Nadya Zabrodina
- */
public abstract class DvcsCommitAdditionalComponent implements RefreshableOnComponent {
private static final Logger log = Logger.getInstance(DvcsCommitAdditionalComponent.class);
@@ -179,4 +176,8 @@ public abstract class DvcsCommitAdditionalComponent implements RefreshableOnComp
@Nullable
protected abstract String getLastCommitMessage(@NotNull VirtualFile repo) throws VcsException;
+
+ public boolean isAmend() {
+ return myAmend.isSelected();
+ }
}
diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/branch/DvcsBranchPopup.java b/platform/dvcs-impl/src/com/intellij/dvcs/branch/DvcsBranchPopup.java
new file mode 100644
index 000000000000..a98cf27ab5d6
--- /dev/null
+++ b/platform/dvcs-impl/src/com/intellij/dvcs/branch/DvcsBranchPopup.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.dvcs.branch;
+
+import com.intellij.dvcs.DvcsUtil;
+import com.intellij.dvcs.repo.AbstractRepositoryManager;
+import com.intellij.dvcs.repo.Repository;
+import com.intellij.dvcs.ui.BranchActionGroupPopup;
+import com.intellij.notification.Notification;
+import com.intellij.notification.NotificationListener;
+import com.intellij.openapi.actionSystem.ActionGroup;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.DefaultActionGroup;
+import com.intellij.openapi.options.ShowSettingsUtil;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.popup.ListPopup;
+import com.intellij.openapi.util.Condition;
+import com.intellij.openapi.vcs.AbstractVcs;
+import com.intellij.openapi.vcs.VcsNotifier;
+import com.intellij.ui.popup.list.ListPopupImpl;
+import com.intellij.util.containers.ContainerUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import javax.swing.event.HyperlinkEvent;
+import java.util.List;
+
+public abstract class DvcsBranchPopup<Repo extends Repository> {
+ @NotNull protected final Project myProject;
+ @NotNull protected final AbstractRepositoryManager<Repo> myRepositoryManager;
+ @NotNull protected final DvcsSyncBranchSettings myVcsSettings;
+ @NotNull protected final AbstractVcs myVcs;
+ @NotNull protected final DvcsMultiRootBranchConfig<Repo> myMultiRootBranchConfig;
+
+ @NotNull protected final Repo myCurrentRepository;
+ @NotNull protected final ListPopupImpl myPopup;
+
+ protected DvcsBranchPopup(@NotNull Repo currentRepository,
+ @NotNull AbstractRepositoryManager<Repo> repositoryManager,
+ @NotNull DvcsMultiRootBranchConfig<Repo> multiRootBranchConfig,
+ @NotNull DvcsSyncBranchSettings vcsSettings,
+ @NotNull Condition<AnAction> preselectActionCondition) {
+ myProject = currentRepository.getProject();
+ myCurrentRepository = currentRepository;
+ myRepositoryManager = repositoryManager;
+ myVcs = currentRepository.getVcs();
+ myVcsSettings = vcsSettings;
+ myMultiRootBranchConfig = multiRootBranchConfig;
+ String title = createPopupTitle(currentRepository);
+ myPopup = new BranchActionGroupPopup(title, myProject, preselectActionCondition, createActions());
+
+ initBranchSyncPolicyIfNotInitialized();
+ setCurrentBranchInfo();
+ warnThatBranchesDivergedIfNeeded();
+ }
+
+ public ListPopup asListPopup() {
+ return myPopup;
+ }
+
+ private void initBranchSyncPolicyIfNotInitialized() {
+ if (myRepositoryManager.moreThanOneRoot() && myVcsSettings.getSyncSetting() == DvcsBranchSync.NOT_DECIDED) {
+ if (!myMultiRootBranchConfig.diverged()) {
+ notifyAboutSyncedBranches();
+ myVcsSettings.setSyncSetting(DvcsBranchSync.SYNC);
+ }
+ else {
+ myVcsSettings.setSyncSetting(DvcsBranchSync.DONT);
+ }
+ }
+ }
+
+ @NotNull
+ private String createPopupTitle(@NotNull Repo currentRepository) {
+ String title = myVcs.getDisplayName() + " Branches";
+ if (myRepositoryManager.moreThanOneRoot() &&
+ (myMultiRootBranchConfig.diverged() || myVcsSettings.getSyncSetting() == DvcsBranchSync.DONT)) {
+ title += " in " + DvcsUtil.getShortRepositoryName(currentRepository);
+ }
+ return title;
+ }
+
+ protected void setCurrentBranchInfo() {
+ String branchText = "Current branch : ";
+ myPopup.setAdText(branchText + myCurrentRepository.getCurrentBranchName(), SwingConstants.CENTER);
+ }
+
+ private void notifyAboutSyncedBranches() {
+ String description =
+ "You have several " + myVcs.getDisplayName() + "roots in the project and they all are checked out at the same branch. " +
+ "We've enabled synchronous branch control for the project. <br/>" +
+ "If you wish to control branches in different roots separately, " +
+ "you may <a href='settings'>disable</a> the setting.";
+ NotificationListener listener = new NotificationListener() {
+ @Override
+ public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) {
+ if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
+ ShowSettingsUtil.getInstance().showSettingsDialog(myProject, myVcs.getConfigurable().getDisplayName());
+ if (myVcsSettings.getSyncSetting() == DvcsBranchSync.DONT) {
+ notification.expire();
+ }
+ }
+ }
+ };
+ VcsNotifier.getInstance(myProject).notifyImportantInfo("Synchronous branch control enabled", description, listener);
+ }
+
+ @NotNull
+ private ActionGroup createActions() {
+ DefaultActionGroup popupGroup = new DefaultActionGroup(null, false);
+ AbstractRepositoryManager<Repo> repositoryManager = myRepositoryManager;
+ if (repositoryManager.moreThanOneRoot()) {
+ if (userWantsSyncControl()) {
+ fillWithCommonRepositoryActions(popupGroup, repositoryManager);
+ }
+ else {
+ fillPopupWithCurrentRepositoryActions(popupGroup, createRepositoriesActions());
+ }
+ }
+ else {
+ fillPopupWithCurrentRepositoryActions(popupGroup, null);
+ }
+ popupGroup.addSeparator();
+ return popupGroup;
+ }
+
+ private boolean userWantsSyncControl() {
+ return (myVcsSettings.getSyncSetting() != DvcsBranchSync.DONT);
+ }
+
+ protected abstract void fillWithCommonRepositoryActions(@NotNull DefaultActionGroup popupGroup,
+ @NotNull AbstractRepositoryManager<Repo> repositoryManager);
+
+ @NotNull
+ protected List<Repo> filterRepositoriesNotOnThisBranch(@NotNull final String branch,
+ @NotNull List<Repo> allRepositories) {
+ return ContainerUtil.filter(allRepositories, new Condition<Repo>() {
+ @Override
+ public boolean value(Repo repository) {
+ return !branch.equals(repository.getCurrentBranchName());
+ }
+ });
+ }
+
+ private void warnThatBranchesDivergedIfNeeded() {
+ if (myRepositoryManager.moreThanOneRoot() && myMultiRootBranchConfig.diverged() && userWantsSyncControl()) {
+ myPopup.setWarning("Branches have diverged");
+ }
+ }
+
+ @NotNull
+ protected abstract DefaultActionGroup createRepositoriesActions();
+
+ protected boolean highlightCurrentRepo() {
+ return !userWantsSyncControl() || myMultiRootBranchConfig.diverged();
+ }
+
+ protected abstract void fillPopupWithCurrentRepositoryActions(@NotNull DefaultActionGroup popupGroup,
+ @Nullable DefaultActionGroup actions);
+}
diff --git a/plugins/git4idea/src/git4idea/ui/branch/GitBranchSyncSetting.java b/platform/dvcs-impl/src/com/intellij/dvcs/branch/DvcsBranchSync.java
index bb9c7592f028..9fab273be2e1 100644
--- a/plugins/git4idea/src/git4idea/ui/branch/GitBranchSyncSetting.java
+++ b/platform/dvcs-impl/src/com/intellij/dvcs/branch/DvcsBranchSync.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,12 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package git4idea.ui.branch;
+package com.intellij.dvcs.branch;
-/**
- * @author Kirill Likhodedov
- */
-public enum GitBranchSyncSetting {
+public enum DvcsBranchSync {
SYNC,
DONT,
NOT_DECIDED
diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/branch/DvcsMultiRootBranchConfig.java b/platform/dvcs-impl/src/com/intellij/dvcs/branch/DvcsMultiRootBranchConfig.java
new file mode 100644
index 000000000000..ee24209167fa
--- /dev/null
+++ b/platform/dvcs-impl/src/com/intellij/dvcs/branch/DvcsMultiRootBranchConfig.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.dvcs.branch;
+
+import com.intellij.dvcs.repo.Repository;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Collection;
+
+public abstract class DvcsMultiRootBranchConfig<Repo extends Repository> {
+ @NotNull protected final Collection<Repo> myRepositories;
+
+ public DvcsMultiRootBranchConfig(@NotNull Collection<Repo> repositories) {
+ myRepositories = repositories;
+ }
+
+ public boolean diverged() {
+ return getCurrentBranch() == null;
+ }
+
+ @Nullable
+ public String getCurrentBranch() {
+ String commonBranch = null;
+ for (Repo repository : myRepositories) {
+ String branchName = repository.getCurrentBranchName();
+ if (branchName == null) {
+ return null;
+ }
+ // NB: if all repositories are in the rebasing state on the same branches, this branch is returned
+ if (commonBranch == null) {
+ commonBranch = branchName;
+ }
+ else if (!commonBranch.equals(branchName)) {
+ return null;
+ }
+ }
+ return commonBranch;
+ }
+
+ @Nullable
+ public Repository.State getState() {
+ Repository.State commonState = null;
+ for (Repo repository : myRepositories) {
+ Repository.State state = repository.getState();
+ if (commonState == null) {
+ commonState = state;
+ }
+ else if (!commonState.equals(state)) {
+ return null;
+ }
+ }
+ return commonState;
+ }
+
+ @NotNull
+ public abstract Collection<String> getLocalBranchNames();
+}
diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/branch/DvcsSyncBranchSettings.java b/platform/dvcs-impl/src/com/intellij/dvcs/branch/DvcsSyncBranchSettings.java
new file mode 100644
index 000000000000..115872a66552
--- /dev/null
+++ b/platform/dvcs-impl/src/com/intellij/dvcs/branch/DvcsSyncBranchSettings.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.dvcs.branch;
+
+import org.jetbrains.annotations.NotNull;
+
+public interface DvcsSyncBranchSettings {
+ @NotNull
+ DvcsBranchSync getSyncSetting();
+
+ void setSyncSetting(@NotNull DvcsBranchSync syncSetting);
+}
diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/PushController.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/PushController.java
index 45f5c68e1d0a..cd0cc7a1ef7a 100644
--- a/platform/dvcs-impl/src/com/intellij/dvcs/push/PushController.java
+++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/PushController.java
@@ -20,31 +20,32 @@ import com.intellij.dvcs.push.ui.*;
import com.intellij.dvcs.repo.Repository;
import com.intellij.dvcs.repo.RepositoryManager;
import com.intellij.openapi.Disposable;
-import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.Task;
-import com.intellij.openapi.progress.impl.ProgressManagerImpl;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.ui.ValidationInfo;
+import com.intellij.openapi.ui.popup.util.PopupUtil;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Disposer;
-import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.AbstractVcs;
import com.intellij.ui.CheckedTreeNode;
-import com.intellij.ui.SimpleColoredText;
-import com.intellij.ui.SimpleTextAttributes;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.hash.HashMap;
+import com.intellij.util.ui.UIUtil;
import com.intellij.vcs.log.VcsFullCommitDetails;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.*;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicReference;
public class PushController implements Disposable {
@@ -56,6 +57,7 @@ public class PushController implements Disposable {
private boolean mySingleRepoProject;
private static final int DEFAULT_CHILDREN_PRESENTATION_NUMBER = 20;
private final Map<PushSupport, MyPushOptionValueModel> myAdditionalValuesMap;
+ private final ExecutorService myExecutorService = Executors.newSingleThreadExecutor();
private final Map<RepositoryNode, MyRepoModel> myView2Model = new TreeMap<RepositoryNode, MyRepoModel>();
//todo need to sort repositories in ui tree using natural order
@@ -162,33 +164,31 @@ public class PushController implements Disposable {
if (target == null) {
model.setError(VcsError.createEmptyTargetError(repoName));
}
- RepositoryWithBranchPanel repoPanel = new RepositoryWithBranchPanel(myProject, repoName,
- support.getSource(repository).getPresentation(),
- target == null ? "" : target.getPresentation(),
- support.getTargetNames(repository));
+ final PushTargetPanel<T> pushTargetPanel = support.createTargetPanel(repository, target);
+ RepositoryWithBranchPanel<T> repoPanel =
+ new RepositoryWithBranchPanel<T>(repoName, support.getSource(repository).getPresentation(), pushTargetPanel);
+ repoPanel.setInputVerifier(new InputVerifier() {
+ @Override
+ public boolean verify(JComponent input) {
+ ValidationInfo error = pushTargetPanel.verify();
+ if (error != null) {
+ //noinspection ConstantConditions
+ PopupUtil.showBalloonForComponent(error.component, error.message, MessageType.WARNING, false, myProject);
+ }
+ return error == null;
+ }
+ });
final RepositoryNode repoNode = isSingleRepositoryProject
- ? new SingleRepositoryNode(repoPanel, support.renderTarget(target))
- : new RepositoryNode(repoPanel, support.renderTarget(target));
+ ? new SingleRepositoryNode(repoPanel)
+ : new RepositoryNode(repoPanel);
myView2Model.put(repoNode, model);
repoNode.setChecked(model.isSelected());
- repoPanel.addRepoNodeListener(new RepositoryNodeListener() {
+ repoPanel.addRepoNodeListener(new RepositoryNodeListener<T>() {
@Override
- public void onTargetChanged(String newValue) {
- VcsError validationError = support.validate(model.getRepository(), newValue);
- if (validationError == null) {
- T newTarget = support.createTarget(repository, newValue);
- repoNode.setTargetPresentation(support.renderTarget(newTarget));
- model.setTarget(newTarget);
- model.clearErrors();
- loadCommits(model, repoNode, false);
- }
- else {
- repoNode.setTargetPresentation(StringUtil.isEmptyOrSpaces(newValue)
- ? support.renderTarget(null)
- : new SimpleColoredText(newValue, SimpleTextAttributes.ERROR_ATTRIBUTES));
- model.setError(validationError); // todo may be should accept and store errors collection, now store one major target error
- model.setTarget(null);
- }
+ public void onTargetChanged(T newTarget) {
+ model.setTarget(newTarget);
+ model.clearErrors();
+ loadCommits(model, repoNode, false);
myDialog.updateButtons();
}
@@ -209,56 +209,49 @@ public class PushController implements Disposable {
final T target = model.getTarget();
if (target == null) return; //todo should be removed when commit loader executor will be modified
myPushLog.startLoading(node);
- final ProgressIndicator indicator = node.startLoading();
final PushSupport<R, S, T> support = model.getSupport();
final AtomicReference<OutgoingResult> result = new AtomicReference<OutgoingResult>();
- Task.Backgroundable task = new Task.Backgroundable(myProject, "Loading Commits", true) {
-
+ Runnable task = new Runnable() {
@Override
- public void onCancel() {
- node.stopLoading();
- }
-
- @Override
- public void onSuccess() {
- OutgoingResult outgoing = result.get();
- List<VcsError> errors = outgoing.getErrors();
- if (!errors.isEmpty()) {
- myPushLog.setChildren(node, ContainerUtil.map(errors, new Function<VcsError, DefaultMutableTreeNode>() {
- @Override
- public DefaultMutableTreeNode fun(final VcsError error) {
- VcsLinkedText errorLinkText = new VcsLinkedText(error.getText(), new VcsLinkListener() {
+ public void run() {
+ OutgoingResult outgoing = support.getOutgoingCommitsProvider()
+ .getOutgoingCommits(model.getRepository(), new PushSpec<S, T>(model.getSource(), model.getTarget()), initial);
+ result.compareAndSet(null, outgoing);
+ UIUtil.invokeAndWaitIfNeeded(new Runnable() {
+ @Override
+ public void run() {
+ OutgoingResult outgoing = result.get();
+ List<VcsError> errors = outgoing.getErrors();
+ if (!errors.isEmpty()) {
+ myPushLog.setChildren(node, ContainerUtil.map(errors, new Function<VcsError, DefaultMutableTreeNode>() {
@Override
- public void hyperlinkActivated(@NotNull DefaultMutableTreeNode sourceNode) {
- error.handleError(new CommitLoader() {
+ public DefaultMutableTreeNode fun(final VcsError error) {
+ VcsLinkedText errorLinkText = new VcsLinkedText(error.getText(), new VcsLinkListener() {
@Override
- public void reloadCommits() {
- loadCommits(model, node, false);
+ public void hyperlinkActivated(@NotNull DefaultMutableTreeNode sourceNode) {
+ error.handleError(new CommitLoader() {
+ @Override
+ public void reloadCommits() {
+ loadCommits(model, node, false);
+ }
+ });
}
});
+ return new TextWithLinkNode(errorLinkText);
}
- });
- return new TextWithLinkNode(errorLinkText);
+ }), model.isSelected());
}
- }), model.isSelected());
- }
- else {
- model.setLoadedCommits(outgoing.getCommits());
- myPushLog.setChildren(node,
- getPresentationForCommits(PushController.this.myProject, model.getLoadedCommits(),
- model.getNumberOfShownCommits()), model.isSelected());
- }
- }
-
- @Override
- public void run(@NotNull ProgressIndicator indicator) {
- OutgoingResult outgoing = support.getOutgoingCommitsProvider()
- .getOutgoingCommits(model.getRepository(), new PushSpec<S, T>(model.getSource(), model.getTarget()), initial);
- result.compareAndSet(null, outgoing);
+ else {
+ model.setLoadedCommits(outgoing.getCommits());
+ myPushLog.setChildren(node,
+ getPresentationForCommits(PushController.this.myProject, model.getLoadedCommits(),
+ model.getNumberOfShownCommits()), model.isSelected());
+ }
+ }
+ });
}
};
-
- ProgressManagerImpl.runProcessWithProgressAsynchronously(task, indicator, null, ModalityState.any());
+ node.startLoading(myExecutorService.submit(task, result));
}
public PushLog getPushPanelLog() {
@@ -315,9 +308,7 @@ public class PushController implements Disposable {
@Override
public void dispose() {
- for (RepositoryNode node : myView2Model.keySet()) {
- node.stopLoading();
- }
+ myExecutorService.shutdownNow();
}
private void addMoreCommits(RepositoryNode repositoryNode) {
diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/RepositoryNodeListener.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/RepositoryNodeListener.java
index 7ca285fc95aa..91bb711cc384 100644
--- a/platform/dvcs-impl/src/com/intellij/dvcs/push/RepositoryNodeListener.java
+++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/RepositoryNodeListener.java
@@ -15,9 +15,9 @@
*/
package com.intellij.dvcs.push;
-public interface RepositoryNodeListener {
+public interface RepositoryNodeListener<T extends PushTarget> {
- void onTargetChanged(String newValue);
+ void onTargetChanged(T newTarget);
void onSelectionChanged(boolean isSelected);
}
diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/EditableTreeNode.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/EditableTreeNode.java
index b5747de91bf7..aab70818082d 100644
--- a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/EditableTreeNode.java
+++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/EditableTreeNode.java
@@ -15,9 +15,12 @@
*/
package com.intellij.dvcs.push.ui;
-import com.intellij.openapi.progress.ProgressIndicator;
+import com.intellij.dvcs.push.OutgoingResult;
import org.jetbrains.annotations.NotNull;
+import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicReference;
+
public interface EditableTreeNode extends CustomRenderedTreeNode {
void fireOnChange();
@@ -28,8 +31,5 @@ public interface EditableTreeNode extends CustomRenderedTreeNode {
void stopLoading();
- @NotNull
- ProgressIndicator startLoading();
-
- String getValue();
+ void startLoading(@NotNull Future<AtomicReference<OutgoingResult>> future);
}
diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java
index 0b4bcb0fbef0..1539b94216c0 100644
--- a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java
+++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/PushLog.java
@@ -15,6 +15,7 @@
*/
package com.intellij.dvcs.push.ui;
+import com.intellij.dvcs.push.PushTargetPanel;
import com.intellij.openapi.actionSystem.CommonShortcuts;
import com.intellij.openapi.actionSystem.DataKey;
import com.intellij.openapi.actionSystem.DataSink;
@@ -25,7 +26,10 @@ import com.intellij.openapi.vcs.VcsDataKeys;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.changes.committed.CommittedChangesTreeBrowser;
import com.intellij.openapi.vcs.changes.ui.ChangesBrowser;
-import com.intellij.ui.*;
+import com.intellij.ui.CheckboxTree;
+import com.intellij.ui.CheckedTreeNode;
+import com.intellij.ui.ColoredTreeCellRenderer;
+import com.intellij.ui.ScrollPaneFactory;
import com.intellij.ui.components.JBTextField;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ui.tree.TreeUtil;
@@ -37,7 +41,10 @@ import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
-import javax.swing.tree.*;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.TreePath;
+import javax.swing.tree.TreeSelectionModel;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
@@ -45,17 +52,14 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.EventObject;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
public class PushLog extends JPanel implements TypeSafeDataProvider {
- private final ReentrantReadWriteLock TREE_CONSTRUCTION_LOCK = new ReentrantReadWriteLock();
-
private static final String START_EDITING = "startEditing";
private final ChangesBrowser myChangesBrowser;
private final CheckboxTree myTree;
private final MyTreeCellRenderer myTreeCellRenderer;
- //private final AtomicBoolean myIgnoreStopEditing = new AtomicBoolean(false);
+ private boolean myEditingSucceeded;
public PushLog(Project project, CheckedTreeNode root) {
DefaultTreeModel treeModel = new DefaultTreeModel(root);
@@ -89,6 +93,23 @@ public class PushLog extends JPanel implements TypeSafeDataProvider {
}
return "";
}
+
+ @Override
+ public boolean stopEditing() {
+ DefaultMutableTreeNode node = (DefaultMutableTreeNode)myTree.getLastSelectedPathComponent();
+ if (node instanceof EditableTreeNode) {
+ JComponent editedComponent = (JComponent)node.getUserObject();
+ InputVerifier verifier = editedComponent.getInputVerifier();
+ if (verifier != null && !verifier.verify(editedComponent)) return false;
+ }
+ myEditingSucceeded = true;
+ try {
+ return super.stopEditing();
+ }
+ finally {
+ myEditingSucceeded = false;
+ }
+ }
};
myTree.setEditable(true);
MyTreeCellEditor treeCellEditor = new MyTreeCellEditor(new JBTextField());
@@ -140,6 +161,9 @@ public class PushLog extends JPanel implements TypeSafeDataProvider {
}
});
myTree.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0), START_EDITING);
+ //override default tree behaviour.
+ myTree.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "");
+
myTree.setRowHeight(0);
ToolTipManager.sharedInstance().registerComponent(myTree);
@@ -197,8 +221,14 @@ public class PushLog extends JPanel implements TypeSafeDataProvider {
@Override
protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) {
- if (e.getKeyCode() == KeyEvent.VK_ENTER && myTree.isEditing()) {
- myTree.stopEditing();
+ if (e.getKeyCode() == KeyEvent.VK_ENTER && pressed) {
+ if (myTree.isEditing()) {
+ myTree.stopEditing();
+ }
+ else {
+ DefaultMutableTreeNode node = (DefaultMutableTreeNode)myTree.getLastSelectedPathComponent();
+ myTree.startEditingAtPath(TreeUtil.getPathFromRoot(node));
+ }
return true;
}
return super.processKeyBinding(ks, e, condition, pressed);
@@ -239,7 +269,7 @@ public class PushLog extends JPanel implements TypeSafeDataProvider {
Object tag = me.getClickCount() >= clickCountToStart
? PushLogTreeUtil.getTagAtForRenderer(myTreeCellRenderer, me)
: null;
- return tag instanceof EditorTextField;
+ return tag instanceof PushTargetPanel;
}
//if keyboard event - then anEvent will be null =( See BasicTreeUi
TreePath treePath = myTree.getAnchorSelectionPath();
@@ -251,7 +281,7 @@ public class PushLog extends JPanel implements TypeSafeDataProvider {
//Implement the one CellEditor method that AbstractCellEditor doesn't.
public Object getCellEditorValue() {
- return ((RepositoryWithBranchPanel)editorComponent).getRemoteTargetName();
+ return myEditingSucceeded ? ((RepositoryWithBranchPanel)editorComponent).getEditableValue() : null;
}
}
@@ -285,34 +315,19 @@ public class PushLog extends JPanel implements TypeSafeDataProvider {
public void setChildren(DefaultMutableTreeNode parentNode,
@NotNull Collection<? extends DefaultMutableTreeNode> childrenNodes,
boolean shouldExpand) {
- try {
- TREE_CONSTRUCTION_LOCK.writeLock().lock();
- parentNode.removeAllChildren();
- for (DefaultMutableTreeNode child : childrenNodes) {
- parentNode.add(child);
- }
- final DefaultTreeModel model = ((DefaultTreeModel)myTree.getModel());
- model.nodeStructureChanged(parentNode);
- TreePath path = TreeUtil.getPathFromRoot(parentNode);
- //myIgnoreStopEditing.set(true);
- if (shouldExpand) {
- myTree.expandPath(path);
- }
- else {
- myTree.collapsePath(path);
- }
+ parentNode.removeAllChildren();
+ for (DefaultMutableTreeNode child : childrenNodes) {
+ parentNode.add(child);
}
- finally {
- TREE_CONSTRUCTION_LOCK.writeLock().unlock();
- //myIgnoreStopEditing.set(false);
+ final DefaultTreeModel model = ((DefaultTreeModel)myTree.getModel());
+ model.nodeStructureChanged(parentNode);
+ TreePath path = TreeUtil.getPathFromRoot(parentNode);
+ if (shouldExpand) {
+ myTree.expandPath(path);
}
- }
-
- public void startEditNode(@NotNull TreeNode node) {
- TreePath path = TreeUtil.getPathFromRoot(node);
- if (!myTree.isEditing()) {
- myTree.setSelectionPath(path);
- myTree.startEditingAtPath(path);
+ else {
+ myTree.collapsePath(path);
}
}
+
}
diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryNode.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryNode.java
index 05e752c4be85..4808064f5c8d 100644
--- a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryNode.java
+++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryNode.java
@@ -15,29 +15,26 @@
*/
package com.intellij.dvcs.push.ui;
-import com.intellij.openapi.progress.EmptyProgressIndicator;
-import com.intellij.openapi.progress.ProgressIndicator;
-import com.intellij.ui.*;
+import com.intellij.dvcs.push.OutgoingResult;
+import com.intellij.dvcs.push.PushTargetPanel;
+import com.intellij.ui.CheckedTreeNode;
+import com.intellij.ui.ColoredTreeCellRenderer;
+import com.intellij.ui.SimpleTextAttributes;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
-import java.util.ArrayList;
+import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicReference;
public class RepositoryNode extends CheckedTreeNode implements EditableTreeNode, Comparable<RepositoryNode> {
@NotNull private final RepositoryWithBranchPanel myRepositoryPanel;
- @NotNull protected SimpleColoredText myTargetPresentation;
- private ProgressIndicator myCurrentIndicator;
+ private Future<AtomicReference<OutgoingResult>> myFuture;
- public RepositoryNode(@NotNull RepositoryWithBranchPanel repositoryPanel, @NotNull SimpleColoredText targetPresentation) {
+ public RepositoryNode(@NotNull RepositoryWithBranchPanel repositoryPanel) {
super(repositoryPanel);
myRepositoryPanel = repositoryPanel;
- myTargetPresentation = targetPresentation;
- }
-
- public void setTargetPresentation(@NotNull SimpleColoredText targetPresentation) {
- myTargetPresentation = targetPresentation;
}
public boolean isCheckboxVisible() {
@@ -51,32 +48,18 @@ public class RepositoryNode extends CheckedTreeNode implements EditableTreeNode,
renderer.appendFixedTextFragmentWidth(120);
renderer.append(myRepositoryPanel.getSourceName(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
renderer.append(myRepositoryPanel.getArrow(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
- EditorTextField textField = myRepositoryPanel.getRemoteTextFiled();
- renderTargetName(renderer, textField);
- Insets insets = BorderFactory.createEmptyBorder().getBorderInsets(textField);
+ PushTargetPanel pushTargetPanel = myRepositoryPanel.getTargetPanel();
+ pushTargetPanel.render(renderer);
+ Insets insets = BorderFactory.createEmptyBorder().getBorderInsets(pushTargetPanel);
renderer.setBorder(new EmptyBorder(insets));
}
- protected void renderTargetName(@NotNull ColoredTreeCellRenderer renderer, @NotNull EditorTextField textField) {
- ArrayList<String> strings = myTargetPresentation.getTexts();
- ArrayList<SimpleTextAttributes> attributes = myTargetPresentation.getAttributes();
- for (int i = 0; i < strings.size(); i++) {
- renderer.append(strings.get(i), attributes.get(i), textField);
- }
- }
-
@Override
public Object getUserObject() {
return myRepositoryPanel;
}
@Override
- @NotNull
- public String getValue() {
- return myRepositoryPanel.getRemoteTargetName();
- }
-
- @Override
public void fireOnChange() {
myRepositoryPanel.fireOnChange();
}
@@ -93,15 +76,14 @@ public class RepositoryNode extends CheckedTreeNode implements EditableTreeNode,
@Override
public void stopLoading() {
- if (myCurrentIndicator != null && myCurrentIndicator.isRunning()) {
- myCurrentIndicator.cancel();
+ if (myFuture != null && !myFuture.isDone()) {
+ myFuture.cancel(true);
}
}
@Override
- @NotNull
- public ProgressIndicator startLoading() {
- return myCurrentIndicator = new EmptyProgressIndicator();
+ public void startLoading(@NotNull Future<AtomicReference<OutgoingResult>> future) {
+ myFuture = future;
}
public int compareTo(@NotNull RepositoryNode repositoryNode) {
diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryWithBranchPanel.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryWithBranchPanel.java
index cd93d0653c36..29a32237ca3a 100644
--- a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryWithBranchPanel.java
+++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/RepositoryWithBranchPanel.java
@@ -15,18 +15,15 @@
*/
package com.intellij.dvcs.push.ui;
+import com.intellij.dvcs.push.PushTarget;
+import com.intellij.dvcs.push.PushTargetPanel;
import com.intellij.dvcs.push.RepositoryNodeListener;
-import com.intellij.openapi.editor.ex.EditorEx;
-import com.intellij.openapi.project.Project;
import com.intellij.ui.ColoredTreeCellRenderer;
import com.intellij.ui.SimpleTextAttributes;
-import com.intellij.ui.TextFieldWithAutoCompletion;
-import com.intellij.ui.TextFieldWithAutoCompletionListProvider;
import com.intellij.ui.components.JBCheckBox;
import com.intellij.ui.components.JBLabel;
import com.intellij.ui.components.panels.NonOpaquePanel;
import com.intellij.util.containers.ContainerUtil;
-import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
@@ -34,23 +31,20 @@ import javax.swing.tree.TreeCellRenderer;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
-import java.awt.event.FocusAdapter;
-import java.awt.event.FocusEvent;
import java.util.List;
-public class RepositoryWithBranchPanel extends NonOpaquePanel implements TreeCellRenderer {
+public class RepositoryWithBranchPanel<T extends PushTarget> extends NonOpaquePanel implements TreeCellRenderer {
private final JBCheckBox myRepositoryCheckbox;
- private final TextFieldWithAutoCompletion myDestBranchTextField;
+ private final PushTargetPanel<T> myDestPushTargetPanelComponent;
private final JBLabel myLocalBranch;
private final JLabel myArrowLabel;
private final JLabel myRepositoryLabel;
private final ColoredTreeCellRenderer myTextRenderer;
- @NotNull private final List<RepositoryNodeListener> myListeners = ContainerUtil.createLockFreeCopyOnWriteList();
- private String myOldDestination;
+ @NotNull private final List<RepositoryNodeListener<T>> myListeners = ContainerUtil.createLockFreeCopyOnWriteList();
- public RepositoryWithBranchPanel(Project project, @NotNull String repoName,
- @NotNull String sourceName, String targetName, @NotNull final List<String> targetVariants) {
+ public RepositoryWithBranchPanel(@NotNull String repoName,
+ @NotNull String sourceName, @NotNull PushTargetPanel<T> destPushTargetPanelComponent) {
super();
setLayout(new BorderLayout());
myRepositoryCheckbox = new JBCheckBox();
@@ -65,37 +59,7 @@ public class RepositoryWithBranchPanel extends NonOpaquePanel implements TreeCel
myRepositoryLabel = new JLabel(repoName);
myLocalBranch = new JBLabel(sourceName);
myArrowLabel = new JLabel(" -> ");
- myOldDestination = targetName;
- TextFieldWithAutoCompletionListProvider<String> provider =
- new TextFieldWithAutoCompletion.StringsCompletionProvider(targetVariants, null) {
- @Override
- public int compare(String item1, String item2) {
- return Integer.valueOf(ContainerUtil.indexOf(targetVariants, item1)).compareTo(ContainerUtil.indexOf(targetVariants, item2));
- }
- };
- myDestBranchTextField = new TextFieldWithAutoCompletion<String>(project, provider, true, targetName) {
-
- @Override
- public boolean shouldHaveBorder() {
- return false;
- }
-
- @Override
- protected void updateBorder(@NotNull final EditorEx editor) {
- }
- };
- myDestBranchTextField.setBorder(UIUtil.getTableFocusCellHighlightBorder());
- myDestBranchTextField.setOneLineMode(true);
- myDestBranchTextField.setOpaque(true);
- FocusAdapter focusListener = new FocusAdapter() {
- @Override
- public void focusGained(FocusEvent e) {
- myDestBranchTextField.selectAll();
- }
- };
- myDestBranchTextField.addFocusListener(focusListener);
- addFocusListener(focusListener);
-
+ myDestPushTargetPanelComponent = destPushTargetPanelComponent;
myTextRenderer = new ColoredTreeCellRenderer() {
public void customizeCellRenderer(@NotNull JTree tree,
Object value,
@@ -115,7 +79,7 @@ public class RepositoryWithBranchPanel extends NonOpaquePanel implements TreeCel
add(myRepositoryCheckbox, BorderLayout.WEST);
JPanel panel = new NonOpaquePanel(new BorderLayout());
panel.add(myTextRenderer, BorderLayout.WEST);
- panel.add(myDestBranchTextField, BorderLayout.CENTER);
+ panel.add(myDestPushTargetPanelComponent, BorderLayout.CENTER);
add(panel, BorderLayout.CENTER);
}
@@ -132,15 +96,6 @@ public class RepositoryWithBranchPanel extends NonOpaquePanel implements TreeCel
return myArrowLabel.getText();
}
- public TextFieldWithAutoCompletion getRemoteTextFiled() {
- return myDestBranchTextField;
- }
-
- @NotNull
- public String getRemoteTargetName() {
- return myDestBranchTextField.getText();
- }
-
@Override
public Component getTreeCellRendererComponent(JTree tree,
Object value,
@@ -168,20 +123,20 @@ public class RepositoryWithBranchPanel extends NonOpaquePanel implements TreeCel
if (bounds != null) {
setPreferredSize(new Dimension(tree.getWidth() - bounds.x, bounds.height));
}
- myDestBranchTextField.grabFocus();
- myDestBranchTextField.requestFocus();
+ myDestPushTargetPanelComponent.grabFocus();
+ myDestPushTargetPanelComponent.requestFocus();
revalidate();
return this;
}
- public void addRepoNodeListener(@NotNull RepositoryNodeListener listener) {
+ public void addRepoNodeListener(@NotNull RepositoryNodeListener<T> listener) {
myListeners.add(listener);
}
public void fireOnChange() {
- myOldDestination = myDestBranchTextField.getText();
- for (RepositoryNodeListener listener : myListeners) {
- listener.onTargetChanged(myOldDestination);
+ myDestPushTargetPanelComponent.fireOnChange();
+ for (RepositoryNodeListener<T> listener : myListeners) {
+ listener.onTargetChanged(myDestPushTargetPanelComponent.getValue());
}
}
@@ -192,7 +147,15 @@ public class RepositoryWithBranchPanel extends NonOpaquePanel implements TreeCel
}
public void fireOnCancel() {
- myDestBranchTextField.setText(myOldDestination);
+ myDestPushTargetPanelComponent.fireOnCancel();
+ }
+
+ public PushTargetPanel getTargetPanel() {
+ return myDestPushTargetPanelComponent;
+ }
+
+ public T getEditableValue() {
+ return myDestPushTargetPanelComponent.getValue();
}
}
diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/SingleRepositoryNode.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/SingleRepositoryNode.java
index 81fb2bd1a9d0..8506e1d50fea 100644
--- a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/SingleRepositoryNode.java
+++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/SingleRepositoryNode.java
@@ -15,9 +15,8 @@
*/
package com.intellij.dvcs.push.ui;
+import com.intellij.dvcs.push.PushTargetPanel;
import com.intellij.ui.ColoredTreeCellRenderer;
-import com.intellij.ui.EditorTextField;
-import com.intellij.ui.SimpleColoredText;
import com.intellij.ui.SimpleTextAttributes;
import org.jetbrains.annotations.NotNull;
@@ -29,8 +28,8 @@ public class SingleRepositoryNode extends RepositoryNode {
@NotNull private final RepositoryWithBranchPanel myRepositoryPanel;
- public SingleRepositoryNode(@NotNull RepositoryWithBranchPanel repositoryPanel, @NotNull SimpleColoredText customTargetPresentation) {
- super(repositoryPanel, customTargetPresentation);
+ public SingleRepositoryNode(@NotNull RepositoryWithBranchPanel repositoryPanel) {
+ super(repositoryPanel);
myRepositoryPanel = repositoryPanel;
}
@@ -43,9 +42,9 @@ public class SingleRepositoryNode extends RepositoryNode {
public void render(@NotNull ColoredTreeCellRenderer renderer) {
renderer.append(myRepositoryPanel.getSourceName(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
renderer.append(myRepositoryPanel.getArrow(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
- EditorTextField textField = myRepositoryPanel.getRemoteTextFiled();
- renderTargetName(renderer, textField);
- Insets insets = BorderFactory.createEmptyBorder().getBorderInsets(textField);
+ PushTargetPanel pushTargetPanel = myRepositoryPanel.getTargetPanel();
+ pushTargetPanel.render(renderer);
+ Insets insets = BorderFactory.createEmptyBorder().getBorderInsets(pushTargetPanel);
renderer.setBorder(new EmptyBorder(insets));
}
}
diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/VcsBranchEditorListener.java b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/VcsBranchEditorListener.java
index d8e35fd25d53..0b3df11db78a 100644
--- a/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/VcsBranchEditorListener.java
+++ b/platform/dvcs-impl/src/com/intellij/dvcs/push/ui/VcsBranchEditorListener.java
@@ -15,9 +15,9 @@
*/
package com.intellij.dvcs.push.ui;
+import com.intellij.dvcs.push.PushTargetPanel;
import com.intellij.openapi.vcs.changes.issueLinks.LinkMouseListenerBase;
import com.intellij.ui.CheckboxTree;
-import com.intellij.ui.EditorTextField;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -35,7 +35,7 @@ public class VcsBranchEditorListener extends LinkMouseListenerBase {
public void mouseMoved(MouseEvent e) {
Component component = (Component)e.getSource();
Object tag = getTagAt(e);
- if (tag != null && tag instanceof EditorTextField) {
+ if (tag != null && tag instanceof PushTargetPanel) {
component.setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
}
else if (tag != null && tag instanceof TextWithLinkNode) {
diff --git a/platform/dvcs-impl/src/com/intellij/dvcs/repo/RepositoryUtil.java b/platform/dvcs-impl/src/com/intellij/dvcs/repo/RepositoryUtil.java
index 5a5a555768ba..35b5bceebff4 100644
--- a/platform/dvcs-impl/src/com/intellij/dvcs/repo/RepositoryUtil.java
+++ b/platform/dvcs-impl/src/com/intellij/dvcs/repo/RepositoryUtil.java
@@ -20,7 +20,7 @@ import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.openapi.vfs.VfsUtil;
+import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Consumer;
import com.intellij.util.Processor;
@@ -101,15 +101,10 @@ public class RepositoryUtil {
}
public static void visitAllChildrenRecursively(@Nullable VirtualFile dir) {
- if (dir == null) {
- return;
+ if (dir != null) {
+ //noinspection unchecked
+ VfsUtilCore.processFilesRecursively(dir, Processor.TRUE);
}
- VfsUtil.processFilesRecursively(dir, new Processor<VirtualFile>() {
- @Override
- public boolean process(VirtualFile virtualFile) {
- return true;
- }
- });
}
public static class Updater implements Consumer<Object> {
diff --git a/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.java b/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.java
index 9f5f5d5720da..c61ce5f8f946 100644
--- a/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.java
+++ b/platform/editor-ui-api/src/com/intellij/ide/ui/UISettings.java
@@ -121,6 +121,7 @@ public class UISettings extends SimpleModificationTracker implements PersistentS
public boolean MARK_MODIFIED_TABS_WITH_ASTERISK = false;
public boolean SHOW_TABS_TOOLTIPS = true;
public boolean SHOW_DIRECTORY_FOR_NON_UNIQUE_FILENAMES = true;
+ public boolean NAVIGATE_TO_PREVIEW = false;
private final EventDispatcher<UISettingsListener> myDispatcher = EventDispatcher.create(UISettingsListener.class);
diff --git a/platform/editor-ui-api/src/com/intellij/openapi/actionSystem/AnAction.java b/platform/editor-ui-api/src/com/intellij/openapi/actionSystem/AnAction.java
index 42da54a61d72..33be4de4b37d 100644
--- a/platform/editor-ui-api/src/com/intellij/openapi/actionSystem/AnAction.java
+++ b/platform/editor-ui-api/src/com/intellij/openapi/actionSystem/AnAction.java
@@ -229,7 +229,7 @@ public abstract class AnAction implements PossiblyDumbAware {
*
* @param e Carries information on the invocation place and data available
*/
- public void update(AnActionEvent e) {
+ public void update(@NotNull AnActionEvent e) {
}
/**
@@ -268,7 +268,7 @@ public abstract class AnAction implements PossiblyDumbAware {
*
* @param e Carries information on the invocation place
*/
- public abstract void actionPerformed(AnActionEvent e);
+ public abstract void actionPerformed(@NotNull AnActionEvent e);
protected void setShortcutSet(ShortcutSet shortcutSet) {
myShortcutSet = shortcutSet;
diff --git a/platform/editor-ui-ex/src/com/intellij/psi/impl/cache/impl/id/PlatformIdTableBuilding.java b/platform/editor-ui-ex/src/com/intellij/psi/impl/cache/impl/id/PlatformIdTableBuilding.java
index 6a3dd82b237e..b1669144551a 100644
--- a/platform/editor-ui-ex/src/com/intellij/psi/impl/cache/impl/id/PlatformIdTableBuilding.java
+++ b/platform/editor-ui-ex/src/com/intellij/psi/impl/cache/impl/id/PlatformIdTableBuilding.java
@@ -23,17 +23,21 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.ex.util.LexerEditorHighlighter;
import com.intellij.openapi.editor.highlighter.EditorHighlighter;
import com.intellij.openapi.editor.highlighter.HighlighterIterator;
-import com.intellij.openapi.fileTypes.*;
+import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.openapi.fileTypes.InternalFileType;
+import com.intellij.openapi.fileTypes.LanguageFileType;
+import com.intellij.openapi.fileTypes.PlainTextFileType;
import com.intellij.openapi.fileTypes.impl.CustomSyntaxTableFileType;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.CustomHighlighterTokenType;
-import com.intellij.psi.impl.cache.impl.BaseFilterLexer;
import com.intellij.psi.impl.cache.CacheUtil;
+import com.intellij.psi.impl.cache.impl.BaseFilterLexer;
import com.intellij.psi.impl.cache.impl.IndexPatternUtil;
import com.intellij.psi.impl.cache.impl.OccurrenceConsumer;
import com.intellij.psi.impl.cache.impl.todo.TodoIndexEntry;
import com.intellij.psi.impl.cache.impl.todo.TodoIndexers;
+import com.intellij.psi.impl.cache.impl.todo.VersionedTodoIndexer;
import com.intellij.psi.search.IndexPattern;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
@@ -116,7 +120,7 @@ public abstract class PlatformIdTableBuilding {
return ourTodoIndexers.containsKey(fileType) || TodoIndexers.INSTANCE.forFileType(fileType) != null || fileType instanceof InternalFileType;
}
- private static class CompositeTodoIndexer implements DataIndexer<TodoIndexEntry, Integer, FileContent> {
+ private static class CompositeTodoIndexer extends VersionedTodoIndexer {
private final DataIndexer<TodoIndexEntry, Integer, FileContent>[] indexers;
public CompositeTodoIndexer(@NotNull DataIndexer<TodoIndexEntry, Integer, FileContent>... indexers) {
@@ -139,9 +143,18 @@ public abstract class PlatformIdTableBuilding {
}
return result;
}
+
+ @Override
+ public int getVersion() {
+ int version = super.getVersion();
+ for(DataIndexer dataIndexer:indexers) {
+ version += dataIndexer instanceof VersionedTodoIndexer ? ((VersionedTodoIndexer)dataIndexer).getVersion() : 0xFF;
+ }
+ return version;
+ }
}
- private static class TokenSetTodoIndexer implements DataIndexer<TodoIndexEntry, Integer, FileContent> {
+ private static class TokenSetTodoIndexer extends VersionedTodoIndexer {
@NotNull private final TokenSet myCommentTokens;
private final VirtualFile myFile;
@@ -201,7 +214,7 @@ public abstract class PlatformIdTableBuilding {
}
}
- public static class PlainTextTodoIndexer implements DataIndexer<TodoIndexEntry, Integer, FileContent> {
+ public static class PlainTextTodoIndexer extends VersionedTodoIndexer {
@Override
@NotNull
public Map<TodoIndexEntry, Integer> map(@NotNull final FileContent inputData) {
diff --git a/platform/editor-ui-ex/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java b/platform/editor-ui-ex/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java
index d955354cca7f..f2101b6e59a4 100644
--- a/platform/editor-ui-ex/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java
+++ b/platform/editor-ui-ex/src/com/intellij/psi/impl/cache/impl/todo/TodoIndex.java
@@ -20,8 +20,10 @@ import com.intellij.lang.Language;
import com.intellij.lang.LanguageParserDefinitions;
import com.intellij.lang.ParserDefinition;
import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.openapi.fileTypes.FileTypeRegistry;
import com.intellij.openapi.fileTypes.LanguageFileType;
import com.intellij.openapi.fileTypes.impl.CustomSyntaxTableFileType;
+import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.impl.cache.impl.id.PlatformIdTableBuilding;
import com.intellij.psi.search.IndexPatternProvider;
@@ -39,7 +41,9 @@ import java.beans.PropertyChangeListener;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
+import java.util.Arrays;
import java.util.Collections;
+import java.util.Comparator;
import java.util.Map;
/**
@@ -49,7 +53,10 @@ import java.util.Map;
public class TodoIndex extends FileBasedIndexExtension<TodoIndexEntry, Integer> {
@NonNls public static final ID<TodoIndexEntry, Integer> NAME = ID.create("TodoIndex");
- public TodoIndex(MessageBus messageBus) {
+ private final FileTypeRegistry myFileTypeManager;
+
+ public TodoIndex(MessageBus messageBus, FileTypeRegistry manager) {
+ myFileTypeManager = manager;
messageBus.connect().subscribe(IndexPatternProvider.INDEX_PATTERNS_CHANGED, new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
@@ -127,7 +134,23 @@ public class TodoIndex extends FileBasedIndexExtension<TodoIndexEntry, Integer>
@Override
public int getVersion() {
- return 8;
+ int version = 8;
+ FileType[] types = myFileTypeManager.getRegisteredFileTypes();
+ Arrays.sort(types, new Comparator<FileType>() {
+ @Override
+ public int compare(FileType o1, FileType o2) {
+ return Comparing.compare(o1.getName(), o2.getName());
+ }
+ });
+
+ for(FileType fileType:types) {
+ DataIndexer<TodoIndexEntry, Integer, FileContent> indexer = TodoIndexers.INSTANCE.forFileType(fileType);
+ if (indexer == null) continue;
+
+ int versionFromIndexer = indexer instanceof VersionedTodoIndexer ? (((VersionedTodoIndexer)indexer).getVersion()) : 0xFF;
+ version = version * 31 + (versionFromIndexer ^ indexer.getClass().getName().hashCode());
+ }
+ return version;
}
@Override
diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/DefaultExternalSourceDirectorySet.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/DefaultExternalSourceDirectorySet.java
index d6a8d7aa6291..8121c0ccaa8a 100644
--- a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/DefaultExternalSourceDirectorySet.java
+++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/DefaultExternalSourceDirectorySet.java
@@ -43,6 +43,8 @@ public class DefaultExternalSourceDirectorySet implements ExternalSourceDirector
@NotNull
private List<ExternalFilter> myFilters;
+ private boolean myInheritedCompilerOutput;
+
public DefaultExternalSourceDirectorySet() {
mySrcDirs = new HashSet<File>();
myExcludes = new HashSet<String>();
@@ -88,6 +90,15 @@ public class DefaultExternalSourceDirectorySet implements ExternalSourceDirector
return myOutputDir;
}
+ @Override
+ public boolean isCompilerOutputPathInherited() {
+ return myInheritedCompilerOutput;
+ }
+
+ public void setInheritedCompilerOutput(boolean inheritedCompilerOutput) {
+ myInheritedCompilerOutput = inheritedCompilerOutput;
+ }
+
@NotNull
@Override
public Set<String> getIncludes() {
diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/ExternalSourceDirectorySet.java b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/ExternalSourceDirectorySet.java
index 70f0bed3d177..530d4d4c0695 100644
--- a/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/ExternalSourceDirectorySet.java
+++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/model/ExternalSourceDirectorySet.java
@@ -36,6 +36,12 @@ public interface ExternalSourceDirectorySet extends Serializable {
@NotNull
File getOutputDir();
+ /**
+ * Returns <code>true</code> if compiler output for this ExternalSourceDirectorySet should is inherited from IDEA project
+ * @return true if compiler output path is inherited, false otherwise
+ */
+ boolean isCompilerOutputPathInherited();
+
@NotNull
Set<String> getExcludes();
@NotNull
diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/LibraryDataService.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/LibraryDataService.java
index d04d728966bb..873a12fe8eb3 100644
--- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/LibraryDataService.java
+++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/project/manage/LibraryDataService.java
@@ -152,7 +152,7 @@ public class LibraryDataService implements ProjectDataService<LibraryData, Libra
VirtualFile jarRoot = JarFileSystem.getInstance().getJarRootForLocalFile(virtualFile);
if (jarRoot == null) {
LOG.warn(String.format(
- "Can't parse contents of the jar file at path '%s' for the library '%s''", file.getAbsolutePath(), libraryName
+ "Can't parse contents of the JAR file at path '%s' for the library '%s''", file.getAbsolutePath(), libraryName
));
continue;
}
diff --git a/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/AbstractExternalSystemTest.groovy b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/AbstractExternalSystemTest.groovy
index 37e35f1b9b76..5f5d122ba318 100644
--- a/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/AbstractExternalSystemTest.groovy
+++ b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/AbstractExternalSystemTest.groovy
@@ -88,26 +88,29 @@ abstract class AbstractExternalSystemTest extends UsefulTestCase {
@Override
protected void tearDown() throws Exception {
- project = null
- UIUtil.invokeAndWaitIfNeeded {
- try {
- externalSystemManagerEP.unregisterExtension(externalSystemManager)
- testFixture.tearDown();
- testFixture = null;
+ try {
+ project = null
+ UIUtil.invokeAndWaitIfNeeded {
+ try {
+ externalSystemManagerEP.unregisterExtension(externalSystemManager)
+ testFixture.tearDown();
+ testFixture = null;
+ }
+ catch (Exception e) {
+ throw new RuntimeException(e);
+ }
}
- catch (Exception e) {
- throw new RuntimeException(e);
+
+ if (!FileUtil.delete(projectDir) && projectDir.exists()) {
+ System.err.println("Cannot delete " + projectDir);
+ //printDirectoryContent(myDir);
+ projectDir.deleteOnExit();
}
}
-
- if (!FileUtil.delete(projectDir) && projectDir.exists()) {
- System.err.println("Cannot delete " + projectDir);
- //printDirectoryContent(myDir);
- projectDir.deleteOnExit();
+ finally {
+ super.tearDown();
+ resetClassFields(getClass());
}
-
- super.tearDown();
- resetClassFields(getClass());
}
private void resetClassFields(@Nullable Class<?> aClass) {
diff --git a/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/ExternalSystemImportingTestCase.java b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/ExternalSystemImportingTestCase.java
index 6107a00b7107..d55ceb0fe97c 100644
--- a/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/ExternalSystemImportingTestCase.java
+++ b/platform/external-system-impl/testSrc/com/intellij/openapi/externalSystem/test/ExternalSystemImportingTestCase.java
@@ -157,6 +157,11 @@ public abstract class ExternalSystemImportingTestCase extends ExternalSystemTest
assertEquals(testOutput, getAbsolutePath(e.getCompilerOutputUrlForTests()));
}
+ protected void assertModuleInheritedOutput(String moduleName) {
+ CompilerModuleExtension e = getCompilerExtension(moduleName);
+ assertTrue(e.isCompilerOutputPathInherited());
+ }
+
private static String getAbsolutePath(String path) {
path = VfsUtil.urlToPath(path);
path = PathUtil.getCanonicalPath(path);
@@ -168,8 +173,7 @@ public abstract class ExternalSystemImportingTestCase extends ExternalSystemTest
}
protected CompilerModuleExtension getCompilerExtension(String module) {
- ModuleRootManager m = getRootManager(module);
- return CompilerModuleExtension.getInstance(m.getModule());
+ return CompilerModuleExtension.getInstance(getModule(module));
}
protected void assertModuleLibDep(String moduleName, String depName) {
diff --git a/platform/icons/src/debugger/commandLine.png b/platform/icons/src/debugger/commandLine.png
new file mode 100644
index 000000000000..3d2333b0e7e8
--- /dev/null
+++ b/platform/icons/src/debugger/commandLine.png
Binary files differ
diff --git a/platform/icons/src/debugger/commandLine@2x.png b/platform/icons/src/debugger/commandLine@2x.png
new file mode 100644
index 000000000000..a70992337f1e
--- /dev/null
+++ b/platform/icons/src/debugger/commandLine@2x.png
Binary files differ
diff --git a/platform/indexing-api/src/com/intellij/lang/cacheBuilder/DefaultWordsScanner.java b/platform/indexing-api/src/com/intellij/lang/cacheBuilder/DefaultWordsScanner.java
index c4a306286708..824202fd0807 100644
--- a/platform/indexing-api/src/com/intellij/lang/cacheBuilder/DefaultWordsScanner.java
+++ b/platform/indexing-api/src/com/intellij/lang/cacheBuilder/DefaultWordsScanner.java
@@ -27,7 +27,7 @@ import org.jetbrains.annotations.NotNull;
* @author max
*/
-public class DefaultWordsScanner implements WordsScanner {
+public class DefaultWordsScanner extends VersionedWordsScanner {
private final Lexer myLexer;
private final TokenSet myIdentifierTokenSet;
private final TokenSet myCommentTokenSet;
diff --git a/platform/indexing-api/src/com/intellij/lang/cacheBuilder/SimpleWordsScanner.java b/platform/indexing-api/src/com/intellij/lang/cacheBuilder/SimpleWordsScanner.java
index 6273654982a9..069c8643ae19 100644
--- a/platform/indexing-api/src/com/intellij/lang/cacheBuilder/SimpleWordsScanner.java
+++ b/platform/indexing-api/src/com/intellij/lang/cacheBuilder/SimpleWordsScanner.java
@@ -25,7 +25,7 @@ import com.intellij.util.text.CharArrayUtil;
*
* @author max
*/
-public class SimpleWordsScanner implements WordsScanner {
+public class SimpleWordsScanner extends VersionedWordsScanner {
public void processWords(CharSequence fileText, Processor<WordOccurrence> processor) {
int index = 0;
WordOccurrence occurrence = null;
diff --git a/platform/indexing-api/src/com/intellij/lang/cacheBuilder/VersionedWordsScanner.java b/platform/indexing-api/src/com/intellij/lang/cacheBuilder/VersionedWordsScanner.java
new file mode 100644
index 000000000000..f8d27825d14e
--- /dev/null
+++ b/platform/indexing-api/src/com/intellij/lang/cacheBuilder/VersionedWordsScanner.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.lang.cacheBuilder;
+
+public abstract class VersionedWordsScanner implements WordsScanner {
+ public int getVersion() {
+ return 1;
+ }
+}
diff --git a/platform/indexing-api/src/com/intellij/psi/search/PsiSearchHelper.java b/platform/indexing-api/src/com/intellij/psi/search/PsiSearchHelper.java
index bef3d0350563..8f2db591888d 100644
--- a/platform/indexing-api/src/com/intellij/psi/search/PsiSearchHelper.java
+++ b/platform/indexing-api/src/com/intellij/psi/search/PsiSearchHelper.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -58,7 +58,6 @@ public interface PsiSearchHelper {
*
* @param identifier the identifier to search.
* @param searchScope the scope in which occurrences are searched.
- * @param processor
* @return false if processor returned false, true otherwise
*/
boolean processCommentsContainingIdentifier(@NotNull String identifier, @NotNull SearchScope searchScope, @NotNull Processor<PsiElement> processor);
diff --git a/platform/indexing-api/src/com/intellij/psi/search/searches/DefinitionsScopedSearch.java b/platform/indexing-api/src/com/intellij/psi/search/searches/DefinitionsScopedSearch.java
index 4e94617e7681..001712e0f529 100644
--- a/platform/indexing-api/src/com/intellij/psi/search/searches/DefinitionsScopedSearch.java
+++ b/platform/indexing-api/src/com/intellij/psi/search/searches/DefinitionsScopedSearch.java
@@ -63,8 +63,13 @@ public class DefinitionsScopedSearch extends ExtensibleQueryFactory<PsiElement,
private final SearchScope myScope;
private final boolean myCheckDeep;
- public SearchParameters(@NotNull PsiElement element) {
- this(element, element.getUseScope(), true);
+ public SearchParameters(@NotNull final PsiElement element) {
+ this(element, ApplicationManager.getApplication().runReadAction(new Computable<SearchScope>() {
+ @Override
+ public SearchScope compute() {
+ return element.getUseScope();
+ }
+ }), true);
}
public SearchParameters(@NotNull PsiElement element, @NotNull SearchScope scope, final boolean checkDeep) {
diff --git a/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/FileTypeIdIndexer.java b/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/FileTypeIdIndexer.java
index f770ac1d5d97..5c1246c7a50b 100644
--- a/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/FileTypeIdIndexer.java
+++ b/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/FileTypeIdIndexer.java
@@ -24,4 +24,7 @@ import com.intellij.util.indexing.FileContent;
* Date: Jan 16, 2008
*/
public abstract class FileTypeIdIndexer implements DataIndexer<IdIndexEntry, Integer, FileContent> {
+ public int getVersion() {
+ return 1;
+ }
}
diff --git a/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndex.java b/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndex.java
index 9929c1c586d2..af193348c71b 100644
--- a/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndex.java
+++ b/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndex.java
@@ -91,7 +91,7 @@ public class IdIndex extends FileBasedIndexExtension<IdIndexEntry, Integer> {
@Override
public int getVersion() {
- return 12 + (ourSnapshotMappingsEnabled ? 0xFF:0); // TODO: version should enumerate all word scanner versions and build version upon that set
+ return 13 + (ourSnapshotMappingsEnabled ? 0xFF:0); // TODO: version should enumerate all word scanner versions and build version upon that set
}
@Override
diff --git a/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/IdTableBuilding.java b/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/IdTableBuilding.java
index 8519453e3e6c..c2ea447400cc 100644
--- a/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/IdTableBuilding.java
+++ b/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/id/IdTableBuilding.java
@@ -161,6 +161,11 @@ public class IdTableBuilding {
});
return consumer.getResult();
}
+
+ @Override
+ public int getVersion() {
+ return myScanner instanceof VersionedWordsScanner ? ((VersionedWordsScanner)myScanner).getVersion() : -1;
+ }
}
public static void scanWords(final ScanWordProcessor processor, final CharSequence chars, final int startOffset, final int endOffset) {
diff --git a/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/todo/LexerBasedTodoIndexer.java b/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/todo/LexerBasedTodoIndexer.java
index b05ef6a9853a..04e27e91dc63 100644
--- a/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/todo/LexerBasedTodoIndexer.java
+++ b/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/todo/LexerBasedTodoIndexer.java
@@ -18,7 +18,6 @@ package com.intellij.psi.impl.cache.impl.todo;
import com.intellij.psi.impl.cache.impl.BaseFilterLexerUtil;
import com.intellij.psi.impl.cache.impl.IdAndToDoScannerBasedOnFilterLexer;
-import com.intellij.util.indexing.DataIndexer;
import com.intellij.util.indexing.FileContent;
import org.jetbrains.annotations.NotNull;
@@ -28,8 +27,7 @@ import java.util.Map;
* @author Eugene Zhuravlev
* Date: Jan 20, 2008
*/
-public abstract class LexerBasedTodoIndexer implements DataIndexer<TodoIndexEntry, Integer, FileContent>,
- IdAndToDoScannerBasedOnFilterLexer {
+public abstract class LexerBasedTodoIndexer extends VersionedTodoIndexer implements IdAndToDoScannerBasedOnFilterLexer {
@Override
@NotNull
public Map<TodoIndexEntry,Integer> map(@NotNull final FileContent inputData) {
diff --git a/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/todo/VersionedTodoIndexer.java b/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/todo/VersionedTodoIndexer.java
new file mode 100644
index 000000000000..028c24b77eed
--- /dev/null
+++ b/platform/indexing-impl/src/com/intellij/psi/impl/cache/impl/todo/VersionedTodoIndexer.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.psi.impl.cache.impl.todo;
+
+import com.intellij.util.indexing.DataIndexer;
+import com.intellij.util.indexing.FileContent;
+
+public abstract class VersionedTodoIndexer implements DataIndexer<TodoIndexEntry, Integer, FileContent> {
+ public int getVersion() {
+ return 1;
+ }
+}
diff --git a/platform/indexing-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java b/platform/indexing-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java
index b5c3dd17afb7..ba8d9ce3500e 100644
--- a/platform/indexing-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java
+++ b/platform/indexing-impl/src/com/intellij/psi/impl/search/PsiSearchHelperImpl.java
@@ -23,7 +23,6 @@ import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressIndicatorProvider;
-import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.util.TooManyUsagesStatus;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.FileIndexFacade;
@@ -56,7 +55,6 @@ import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.util.*;
-import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
@@ -132,9 +130,7 @@ public class PsiSearchHelperImpl implements PsiSearchHelper {
short searchContext,
boolean caseSensitive,
boolean processInjectedPsi) {
- final AsyncFuture<Boolean> result =
- processElementsWithWordAsync(processor, searchScope, text, searchContext, caseSensitive, processInjectedPsi, null);
- return AsyncUtil.get(result);
+ return processElementsWithWord(processor, searchScope, text, searchContext, caseSensitive, processInjectedPsi, null);
}
@NotNull
@@ -144,50 +140,39 @@ public class PsiSearchHelperImpl implements PsiSearchHelper {
@NotNull final String text,
final short searchContext,
final boolean caseSensitively) {
- return processElementsWithWordAsync(processor, searchScope, text, searchContext, caseSensitively, shouldProcessInjectedPsi(searchScope), null);
- }
-
- @NotNull
- private AsyncFuture<Boolean> processElementsWithWordAsync(@NotNull final TextOccurenceProcessor processor,
- @NotNull SearchScope searchScope,
- @NotNull final String text,
- final short searchContext,
- final boolean caseSensitively,
- boolean processInjectedPsi,
- @Nullable String containerName) {
+ boolean result =
+ processElementsWithWord(processor, searchScope, text, searchContext, caseSensitively, shouldProcessInjectedPsi(searchScope), null);
+ return AsyncUtil.wrapBoolean(result);
+ }
+
+ private boolean processElementsWithWord(@NotNull final TextOccurenceProcessor processor,
+ @NotNull SearchScope searchScope,
+ @NotNull final String text,
+ final short searchContext,
+ final boolean caseSensitively,
+ boolean processInjectedPsi,
+ @Nullable String containerName) {
if (text.isEmpty()) {
- return AsyncFutureFactory.wrapException(new IllegalArgumentException("Cannot search for elements with empty text"));
+ throw new IllegalArgumentException("Cannot search for elements with empty text");
}
final ProgressIndicator progress = ProgressIndicatorProvider.getGlobalProgressIndicator();
if (searchScope instanceof GlobalSearchScope) {
StringSearcher searcher = new StringSearcher(text, caseSensitively, true, searchContext == UsageSearchContext.IN_STRINGS);
- return processElementsWithTextInGlobalScopeAsync(processor,
- (GlobalSearchScope)searchScope,
- searcher,
- searchContext, caseSensitively, containerName, progress, processInjectedPsi);
+ return processElementsWithTextInGlobalScope(processor,
+ (GlobalSearchScope)searchScope,
+ searcher,
+ searchContext, caseSensitively, containerName, progress, processInjectedPsi);
}
LocalSearchScope scope = (LocalSearchScope)searchScope;
PsiElement[] scopeElements = scope.getScope();
final StringSearcher searcher = new StringSearcher(text, caseSensitively, true, searchContext == UsageSearchContext.IN_STRINGS);
Processor<PsiElement> localProcessor = localProcessor(processor, progress, processInjectedPsi, searcher);
- return wrapInFuture(Arrays.asList(scopeElements), progress, localProcessor);
- }
-
- private static <T> AsyncFuture<Boolean> wrapInFuture(@NotNull List<T> files, final ProgressIndicator progress, @NotNull Processor<T> processor) {
- AsyncFutureResult<Boolean> asyncFutureResult = AsyncFutureFactory.getInstance().createAsyncFutureResult();
- try {
- boolean result = JobLauncher.getInstance().invokeConcurrentlyUnderProgress(files, progress, true, true, processor);
- asyncFutureResult.set(result);
- }
- catch (Throwable t) {
- asyncFutureResult.setException(t);
- }
- return asyncFutureResult;
+ return JobLauncher.getInstance().invokeConcurrentlyUnderProgress(Arrays.asList(scopeElements), progress, true, true, localProcessor);
}
private static boolean shouldProcessInjectedPsi(SearchScope scope) {
- return scope instanceof LocalSearchScope ? !((LocalSearchScope)scope).isIgnoreInjectedPsi() : true;
+ return !(scope instanceof LocalSearchScope) || !((LocalSearchScope)scope).isIgnoreInjectedPsi();
}
@NotNull
@@ -213,14 +198,13 @@ public class PsiSearchHelperImpl implements PsiSearchHelper {
};
}
- @NotNull
- private AsyncFuture<Boolean> processElementsWithTextInGlobalScopeAsync(@NotNull final TextOccurenceProcessor processor,
- @NotNull final GlobalSearchScope scope,
- @NotNull final StringSearcher searcher,
- final short searchContext,
- final boolean caseSensitively,
- String containerName,
- final ProgressIndicator progress, final boolean processInjectedPsi) {
+ private boolean processElementsWithTextInGlobalScope(@NotNull final TextOccurenceProcessor processor,
+ @NotNull final GlobalSearchScope scope,
+ @NotNull final StringSearcher searcher,
+ final short searchContext,
+ final boolean caseSensitively,
+ String containerName,
+ final ProgressIndicator progress, final boolean processInjectedPsi) {
if (Thread.holdsLock(PsiLock.LOCK)) {
throw new AssertionError("You must not run search from within updating PSI activity. Please consider invokeLatering it instead.");
}
@@ -244,70 +228,28 @@ public class PsiSearchHelperImpl implements PsiSearchHelper {
getFilesWithText(scope, searchContext, caseSensitively, text+" "+containerName, progress, intersectionWithContainerFiles);
if (!intersectionWithContainerFiles.isEmpty()) {
int totalSize = fileSet.size();
- AsyncFuture<Boolean> intersectionResult = processPsiFileRootsAsync(intersectionWithContainerFiles, totalSize, 0, progress, localProcessor);
- AsyncFuture<Boolean> result;
- try {
- if (intersectionResult.get()) {
- fileSet.removeAll(intersectionWithContainerFiles);
- if (fileSet.isEmpty()) {
- result = intersectionResult;
- }
- else {
- AsyncFuture<Boolean> restResult =
- processPsiFileRootsAsync(new ArrayList<VirtualFile>(fileSet), totalSize, intersectionWithContainerFiles.size(), progress, localProcessor);
- result = bind(intersectionResult, restResult);
- }
- }
- else {
- result = intersectionResult;
+ boolean result = processPsiFileRoots(intersectionWithContainerFiles, totalSize, 0, progress,
+ localProcessor);
+
+ if (result) {
+ fileSet.removeAll(intersectionWithContainerFiles);
+ if (!fileSet.isEmpty()) {
+ result = processPsiFileRoots(new ArrayList<VirtualFile>(fileSet), totalSize, intersectionWithContainerFiles.size(), progress, localProcessor);
}
}
- catch (ExecutionException e) {
- Throwable cause = e.getCause();
- if (cause instanceof RuntimeException) throw (RuntimeException)cause;
- if (cause instanceof Error) throw (Error)cause;
- result = AsyncFutureFactory.wrapException(cause);
- }
- catch (InterruptedException e) {
- result = AsyncFutureFactory.wrapException(e);
- }
- return popStateAfter(result, progress);
- }
- }
-
- AsyncFuture<Boolean> result = fileSet.isEmpty()
- ? AsyncFutureFactory.wrap(Boolean.TRUE)
- : processPsiFileRootsAsync(new ArrayList<VirtualFile>(fileSet), fileSet.size(), 0, progress, localProcessor);
- return popStateAfter(result, progress);
- }
-
- @NotNull
- private static FinallyFuture<Boolean> popStateAfter(@NotNull AsyncFuture<Boolean> result, final ProgressIndicator progress) {
- return new FinallyFuture<Boolean>(result, new Runnable() {
- @Override
- public void run() {
if (progress != null) {
progress.popState();
}
+ return result;
}
- });
- }
-
- @NotNull
- private static AsyncFuture<Boolean> bind(@NotNull AsyncFuture<Boolean> first, @NotNull final AsyncFuture<Boolean> second) {
- final AsyncFutureResult<Boolean> totalResult = AsyncFutureFactory.getInstance().createAsyncFutureResult();
- first.addConsumer(SameThreadExecutor.INSTANCE, new ResultConsumer<Boolean>() {
- @Override
- public void onSuccess(Boolean value) {
- second.addConsumer(SameThreadExecutor.INSTANCE, new DefaultResultConsumer<Boolean>(totalResult));
- }
+ }
- @Override
- public void onFailure(Throwable t) {
- totalResult.setException(t);
- }
- });
- return totalResult;
+ boolean result =
+ fileSet.isEmpty() || processPsiFileRoots(new ArrayList<VirtualFile>(fileSet), fileSet.size(), 0, progress, localProcessor);
+ if (progress != null) {
+ progress.popState();
+ }
+ return result;
}
/**
@@ -315,20 +257,19 @@ public class PsiSearchHelperImpl implements PsiSearchHelper {
* @param totalSize the number of files to scan in both passes. Can be different from <code>files.size()</code> in case of
* two-pass scan, where we first scan files containing container name and then all the rest files.
* @param alreadyProcessedFiles the number of files scanned in previous pass.
+ * @return true if completed
*/
- @NotNull
- private AsyncFuture<Boolean> processPsiFileRootsAsync(@NotNull List<VirtualFile> files,
- final int totalSize,
- int alreadyProcessedFiles,
- final ProgressIndicator progress,
- @NotNull final Processor<? super PsiFile> localProcessor) {
+ private boolean processPsiFileRoots(@NotNull List<VirtualFile> files,
+ final int totalSize,
+ int alreadyProcessedFiles,
+ final ProgressIndicator progress,
+ @NotNull final Processor<? super PsiFile> localProcessor) {
myManager.startBatchFilesProcessingMode();
- final AtomicInteger counter = new AtomicInteger(alreadyProcessedFiles);
- final AtomicBoolean canceled = new AtomicBoolean(false);
-
- AsyncFutureResult<Boolean> asyncFutureResult = AsyncFutureFactory.getInstance().createAsyncFutureResult();
- final List<VirtualFile> failedFiles = Collections.synchronizedList(new SmartList<VirtualFile>());
try {
+ final AtomicInteger counter = new AtomicInteger(alreadyProcessedFiles);
+ final AtomicBoolean canceled = new AtomicBoolean(false);
+
+ final List<VirtualFile> failedFiles = Collections.synchronizedList(new SmartList<VirtualFile>());
boolean completed =
JobLauncher.getInstance().invokeConcurrentlyUnderProgress(files, progress, false, false, new Processor<VirtualFile>() {
@Override
@@ -357,14 +298,12 @@ public class PsiSearchHelperImpl implements PsiSearchHelper {
});
}
}
- asyncFutureResult.set(completed);
- myManager.finishBatchFilesProcessingMode();
+ return completed;
}
- catch (Throwable t) {
- asyncFutureResult.setException(t);
+ finally {
+ myManager.finishBatchFilesProcessingMode();
}
- return asyncFutureResult;
}
private void processVirtualFile(@NotNull final VirtualFile vfile,
@@ -423,9 +362,6 @@ public class PsiSearchHelperImpl implements PsiSearchHelper {
if (progress != null) {
progress.checkCanceled();
}
- else {
- ProgressManager.checkCanceled();
- }
}
private void getFilesWithText(@NotNull GlobalSearchScope scope,
@@ -648,65 +584,32 @@ public class PsiSearchHelperImpl implements PsiSearchHelper {
final Map<SearchRequestCollector, Processor<PsiReference>> collectors = ContainerUtil.newHashMap();
collectors.put(collector, processor);
+ ProgressIndicator progress = ProgressIndicatorProvider.getGlobalProgressIndicator();
appendCollectorsFromQueryRequests(collectors);
-
- final ProgressIndicator progress = ProgressIndicatorProvider.getGlobalProgressIndicator();
- final DoWhile doWhile = new DoWhile() {
- @NotNull
- @Override
- protected AsyncFuture<Boolean> body() {
- final AsyncFutureResult<Boolean> result = AsyncFutureFactory.getInstance().createAsyncFutureResult();
- MultiMap<Set<IdIndexEntry>, RequestWithProcessor> globals = new MultiMap<Set<IdIndexEntry>, RequestWithProcessor>();
- final List<Computable<Boolean>> customs = ContainerUtil.newArrayList();
- final Set<RequestWithProcessor> locals = ContainerUtil.newLinkedHashSet();
- Map<RequestWithProcessor, Processor<PsiElement>> localProcessors = new THashMap<RequestWithProcessor, Processor<PsiElement>>();
- distributePrimitives(collectors, locals, globals, customs, localProcessors, progress);
- AsyncFuture<Boolean> future = processGlobalRequestsOptimizedAsync(globals, progress, localProcessors);
- future.addConsumer(SameThreadExecutor.INSTANCE, new DefaultResultConsumer<Boolean>(result) {
- @Override
- public void onSuccess(Boolean value) {
- if (!value.booleanValue()) {
- result.set(value);
- }
- else {
- final Iterate<RequestWithProcessor> iterate = new Iterate<RequestWithProcessor>(locals) {
- @NotNull
- @Override
- protected AsyncFuture<Boolean> process(RequestWithProcessor local) {
- return processSingleRequestAsync(local.request, local.refProcessor);
- }
- };
-
- iterate.getResult()
- .addConsumer(SameThreadExecutor.INSTANCE, new DefaultResultConsumer<Boolean>(result) {
- @Override
- public void onSuccess(Boolean value) {
- if (!value.booleanValue()) {
- result.set(false);
- return;
- }
- for (Computable<Boolean> custom : customs) {
- if (!custom.compute()) {
- result.set(false);
- return;
- }
- }
- result.set(true);
- }
- });
- }
+ boolean result;
+ do {
+ MultiMap<Set<IdIndexEntry>, RequestWithProcessor> globals = new MultiMap<Set<IdIndexEntry>, RequestWithProcessor>();
+ final List<Computable<Boolean>> customs = ContainerUtil.newArrayList();
+ final Set<RequestWithProcessor> locals = ContainerUtil.newLinkedHashSet();
+ Map<RequestWithProcessor, Processor<PsiElement>> localProcessors = new THashMap<RequestWithProcessor, Processor<PsiElement>>();
+ distributePrimitives(collectors, locals, globals, customs, localProcessors, progress);
+ result = processGlobalRequestsOptimized(globals, progress, localProcessors);
+ if (result) {
+ for (RequestWithProcessor local : locals) {
+ result = processSingleRequest(local.request, local.refProcessor);
+ if (!result) break;
+ }
+ if (result) {
+ for (Computable<Boolean> custom : customs) {
+ result = custom.compute();
+ if (!result) break;
}
- });
- return result;
- }
-
- @Override
- protected boolean condition() {
- return appendCollectorsFromQueryRequests(collectors);
+ }
+ if (!result) break;
}
- };
-
- return doWhile.getResult();
+ }
+ while(appendCollectorsFromQueryRequests(collectors));
+ return AsyncUtil.wrapBoolean(result);
}
private static boolean appendCollectorsFromQueryRequests(@NotNull Map<SearchRequestCollector, Processor<PsiReference>> collectors) {
@@ -725,19 +628,18 @@ public class PsiSearchHelperImpl implements PsiSearchHelper {
return changed;
}
- @NotNull
- private AsyncFuture<Boolean> processGlobalRequestsOptimizedAsync(@NotNull MultiMap<Set<IdIndexEntry>, RequestWithProcessor> singles,
- final ProgressIndicator progress,
- @NotNull final Map<RequestWithProcessor, Processor<PsiElement>> localProcessors) {
+ private boolean processGlobalRequestsOptimized(@NotNull MultiMap<Set<IdIndexEntry>, RequestWithProcessor> singles,
+ final ProgressIndicator progress,
+ @NotNull final Map<RequestWithProcessor, Processor<PsiElement>> localProcessors) {
if (singles.isEmpty()) {
- return AsyncFutureFactory.wrap(true);
+ return true;
}
if (singles.size() == 1) {
final Collection<? extends RequestWithProcessor> requests = singles.values();
if (requests.size() == 1) {
final RequestWithProcessor theOnly = requests.iterator().next();
- return processSingleRequestAsync(theOnly.request, theOnly.refProcessor);
+ return processSingleRequest(theOnly.request, theOnly.refProcessor);
}
}
@@ -745,64 +647,55 @@ public class PsiSearchHelperImpl implements PsiSearchHelper {
progress.pushState();
progress.setText(PsiBundle.message("psi.scanning.files.progress"));
}
+ boolean result;
- // intersectionCandidateFiles holds files containing words from all requests in `singles` and words in corresponding container names
- final MultiMap<VirtualFile, RequestWithProcessor> intersectionCandidateFiles = createMultiMap();
- // restCandidateFiles holds files containing words from all requests in `singles` but EXCLUDING words in corresponding container names
- final MultiMap<VirtualFile, RequestWithProcessor> restCandidateFiles = createMultiMap();
- collectFiles(singles, progress, intersectionCandidateFiles, restCandidateFiles);
-
- if (intersectionCandidateFiles.isEmpty() && restCandidateFiles.isEmpty()) {
- return AsyncFutureFactory.wrap(true);
- }
+ try {
+ // intersectionCandidateFiles holds files containing words from all requests in `singles` and words in corresponding container names
+ final MultiMap<VirtualFile, RequestWithProcessor> intersectionCandidateFiles = createMultiMap();
+ // restCandidateFiles holds files containing words from all requests in `singles` but EXCLUDING words in corresponding container names
+ final MultiMap<VirtualFile, RequestWithProcessor> restCandidateFiles = createMultiMap();
+ collectFiles(singles, progress, intersectionCandidateFiles, restCandidateFiles);
- if (progress != null) {
- final Set<String> allWords = new TreeSet<String>();
- for (RequestWithProcessor singleRequest : localProcessors.keySet()) {
- allWords.add(singleRequest.request.word);
+ if (intersectionCandidateFiles.isEmpty() && restCandidateFiles.isEmpty()) {
+ return true;
}
- progress.setText(PsiBundle.message("psi.search.for.word.progress", getPresentableWordsDescription(allWords)));
- }
- AsyncFuture<Boolean> result;
- if (intersectionCandidateFiles.isEmpty()) {
- result = processCandidatesAsync(progress, localProcessors, restCandidateFiles, restCandidateFiles.size(), 0);
- }
- else {
- int totalSize = restCandidateFiles.size() + intersectionCandidateFiles.size();
- AsyncFuture<Boolean> intersectionResult = processCandidatesAsync(progress, localProcessors, intersectionCandidateFiles, totalSize, 0);
- try {
- if (intersectionResult.get()) {
- AsyncFuture<Boolean> restResult = processCandidatesAsync(progress, localProcessors, restCandidateFiles, totalSize, intersectionCandidateFiles.size());
- result = bind(intersectionResult, restResult);
- }
- else {
- result = intersectionResult;
+ if (progress != null) {
+ final Set<String> allWords = new TreeSet<String>();
+ for (RequestWithProcessor singleRequest : localProcessors.keySet()) {
+ allWords.add(singleRequest.request.word);
}
+ progress.setText(PsiBundle.message("psi.search.for.word.progress", getPresentableWordsDescription(allWords)));
}
- catch (ExecutionException e) {
- Throwable cause = e.getCause();
- if (cause instanceof RuntimeException) throw (RuntimeException)cause;
- if (cause instanceof Error) throw (Error)cause;
- result = AsyncFutureFactory.wrapException(cause);
+
+ if (intersectionCandidateFiles.isEmpty()) {
+ result = processCandidates(progress, localProcessors, restCandidateFiles, restCandidateFiles.size(), 0);
+ }
+ else {
+ int totalSize = restCandidateFiles.size() + intersectionCandidateFiles.size();
+ result = processCandidates(progress, localProcessors, intersectionCandidateFiles, totalSize, 0);
+ if (result) {
+ result = processCandidates(progress, localProcessors, restCandidateFiles, totalSize, intersectionCandidateFiles.size());
+ }
}
- catch (InterruptedException e) {
- result = AsyncFutureFactory.wrapException(e);
+ }
+ finally {
+ if (progress != null) {
+ progress.popState();
}
}
- return popStateAfter(result, progress);
+ return result;
}
- @NotNull
- private AsyncFuture<Boolean> processCandidatesAsync(final ProgressIndicator progress,
- @NotNull final Map<RequestWithProcessor, Processor<PsiElement>> localProcessors,
- @NotNull final MultiMap<VirtualFile, RequestWithProcessor> candidateFiles,
- int totalSize,
- int alreadyProcessedFiles) {
+ private boolean processCandidates(final ProgressIndicator progress,
+ @NotNull final Map<RequestWithProcessor, Processor<PsiElement>> localProcessors,
+ @NotNull final MultiMap<VirtualFile, RequestWithProcessor> candidateFiles,
+ int totalSize,
+ int alreadyProcessedFiles) {
List<VirtualFile> files = new ArrayList<VirtualFile>(candidateFiles.keySet());
- return processPsiFileRootsAsync(files, totalSize, alreadyProcessedFiles, progress, new Processor<PsiFile>() {
+ return processPsiFileRoots(files, totalSize, alreadyProcessedFiles, progress, new Processor<PsiFile>() {
@Override
public boolean process(final PsiFile psiRoot) {
return ApplicationUtil.tryRunReadAction(new Computable<Boolean>() {
@@ -1023,10 +916,9 @@ public class PsiSearchHelperImpl implements PsiSearchHelper {
collection.add(singleRequest);
}
- @NotNull
- private AsyncFuture<Boolean> processSingleRequestAsync(@NotNull PsiSearchRequest single, @NotNull Processor<PsiReference> consumer) {
- return processElementsWithWordAsync(adaptProcessor(single, consumer), single.searchScope, single.word, single.searchContext,
- single.caseSensitive, shouldProcessInjectedPsi(single.searchScope), single.containerName);
+ private boolean processSingleRequest(@NotNull PsiSearchRequest single, @NotNull Processor<PsiReference> consumer) {
+ return processElementsWithWord(adaptProcessor(single, consumer), single.searchScope, single.word, single.searchContext,
+ single.caseSensitive, shouldProcessInjectedPsi(single.searchScope), single.containerName);
}
@NotNull
diff --git a/platform/lang-api/src/com/intellij/diagnostic/logging/AdditionalTabComponent.java b/platform/lang-api/src/com/intellij/diagnostic/logging/AdditionalTabComponent.java
index b45abc181736..4991071477fb 100644
--- a/platform/lang-api/src/com/intellij/diagnostic/logging/AdditionalTabComponent.java
+++ b/platform/lang-api/src/com/intellij/diagnostic/logging/AdditionalTabComponent.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package com.intellij.diagnostic.logging;
import com.intellij.openapi.ui.ComponentContainer;
@@ -36,6 +35,7 @@ public abstract class AdditionalTabComponent extends JPanel implements Component
protected AdditionalTabComponent() {
}
+ @NotNull
public abstract String getTabTitle();
@Nullable
diff --git a/platform/lang-api/src/com/intellij/execution/DefaultExecutionResult.java b/platform/lang-api/src/com/intellij/execution/DefaultExecutionResult.java
index 8a951da7d74f..75f117122e96 100644
--- a/platform/lang-api/src/com/intellij/execution/DefaultExecutionResult.java
+++ b/platform/lang-api/src/com/intellij/execution/DefaultExecutionResult.java
@@ -34,7 +34,8 @@ public class DefaultExecutionResult implements ExecutionResult {
private final ExecutionConsole myConsole;
private final ProcessHandler myProcessHandler;
private AnAction[] myActions;
- private AnAction[] myRestartActions;
+ @NotNull
+ private AnAction[] myRestartActions = AnAction.EMPTY_ARRAY;
private final List<AnAction> myStopActions = new ArrayList<AnAction>();
public DefaultExecutionResult() {
@@ -67,12 +68,14 @@ public class DefaultExecutionResult implements ExecutionResult {
myActions = actions;
}
+ @NotNull
public AnAction[] getRestartActions() {
return myRestartActions;
}
- public void setRestartActions(AnAction... restartActions) {
- myRestartActions = restartActions;
+ // TODO: Find all usages, make sure there is no null and make this method NotNull
+ public void setRestartActions(@Nullable AnAction... restartActions) {
+ myRestartActions = (restartActions != null ? restartActions : AnAction.EMPTY_ARRAY);
}
public void addStopAction(AnAction action) {
@@ -104,7 +107,7 @@ public class DefaultExecutionResult implements ExecutionResult {
@Override
public void actionPerformed(final AnActionEvent e) {
- if(myProcessHandler.detachIsDefault()) {
+ if (myProcessHandler.detachIsDefault()) {
myProcessHandler.detachProcess();
}
else {
diff --git a/platform/lang-api/src/com/intellij/execution/ExecutionResult.java b/platform/lang-api/src/com/intellij/execution/ExecutionResult.java
index 116ce555e94d..91f888aa8dc6 100644
--- a/platform/lang-api/src/com/intellij/execution/ExecutionResult.java
+++ b/platform/lang-api/src/com/intellij/execution/ExecutionResult.java
@@ -40,6 +40,7 @@ public interface ExecutionResult {
*/
AnAction[] getActions();
+
/**
* Returns the ProcessHandler attached to the running process.
*
diff --git a/platform/lang-api/src/com/intellij/execution/configurations/AdditionalTabComponentManager.java b/platform/lang-api/src/com/intellij/execution/configurations/AdditionalTabComponentManager.java
index 26f1273b2698..701f1b294003 100644
--- a/platform/lang-api/src/com/intellij/execution/configurations/AdditionalTabComponentManager.java
+++ b/platform/lang-api/src/com/intellij/execution/configurations/AdditionalTabComponentManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
/*
* Created by IntelliJ IDEA.
* User: Anna.Kozlova
@@ -23,8 +22,10 @@
package com.intellij.execution.configurations;
import com.intellij.diagnostic.logging.AdditionalTabComponent;
+import org.jetbrains.annotations.NotNull;
public interface AdditionalTabComponentManager {
- void addAdditionalTabComponent(AdditionalTabComponent component, final String id);
- void removeAdditionalTabComponent(AdditionalTabComponent component);
+ void addAdditionalTabComponent(@NotNull AdditionalTabComponent component, @NotNull String id);
+
+ void removeAdditionalTabComponent(@NotNull AdditionalTabComponent component);
} \ No newline at end of file
diff --git a/platform/lang-api/src/com/intellij/execution/configurations/LogFileOptions.java b/platform/lang-api/src/com/intellij/execution/configurations/LogFileOptions.java
index 6f23831c9e3a..0a4132d83a52 100644
--- a/platform/lang-api/src/com/intellij/execution/configurations/LogFileOptions.java
+++ b/platform/lang-api/src/com/intellij/execution/configurations/LogFileOptions.java
@@ -20,6 +20,8 @@ import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.JDOMExternalizable;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.util.SmartList;
+import com.intellij.util.containers.SmartHashSet;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -27,8 +29,7 @@ import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.HashSet;
+import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
@@ -80,46 +81,50 @@ public class LogFileOptions implements JDOMExternalizable {
return myPathPattern;
}
+ @NotNull
public Set<String> getPaths(){
- Set<String> result = new HashSet<String>();
- final File logFile = new File(myPathPattern);
+ File logFile = new File(myPathPattern);
if (logFile.exists()){
- result.add(myPathPattern);
+ return Collections.singleton(myPathPattern);
+ }
+
+ int dirIndex = myPathPattern.lastIndexOf(File.separator);
+ if (dirIndex == -1) {
+ return Collections.emptySet();
+ }
+
+ List<File> files = new SmartList<File>();
+ collectMatchedFiles(new File(myPathPattern.substring(0, dirIndex)), Pattern.compile(FileUtil.convertAntToRegexp(myPathPattern.substring(dirIndex + File.separator.length()))), files);
+ if (files.isEmpty()) {
+ return Collections.emptySet();
+ }
+
+ if (myShowAll) {
+ SmartHashSet<String> result = new SmartHashSet<String>();
+ result.ensureCapacity(files.size());
+ for (File file : files) {
+ result.add(file.getPath());
+ }
return result;
}
- final int dirIndex = myPathPattern.lastIndexOf(File.separator);
- if (dirIndex != -1) {
- final ArrayList<File> files = new ArrayList<File>();
- final String basePath = myPathPattern.substring(0, dirIndex);
- final String pattern = myPathPattern.substring(dirIndex + File.separator.length());
- collectMatchedFiles(new File(basePath), Pattern.compile(FileUtil.convertAntToRegexp(pattern)), files);
- if (!files.isEmpty()) {
- if (myShowAll) {
- for (File file : files) {
- result.add(file.getPath());
+ else {
+ File lastFile = null;
+ for (File file : files) {
+ if (lastFile != null) {
+ if (file.lastModified() > lastFile.lastModified()) {
+ lastFile = file;
}
}
else {
- File lastFile = null;
- for (File file : files) {
- if (lastFile != null) {
- if (file.lastModified() > lastFile.lastModified()) {
- lastFile = file;
- }
- }
- else {
- lastFile = file;
- }
- }
- assert lastFile != null;
- result.add(lastFile.getPath());
+ lastFile = file;
}
}
+ assert lastFile != null;
+ return Collections.singleton(lastFile.getPath());
}
- return result;
}
- public static void collectMatchedFiles(final File root, final Pattern pattern, final List<File> files) {
+ public static void collectMatchedFiles(@NotNull File root, @NotNull Pattern pattern, @NotNull List<File> files) {
final File[] dirs = root.listFiles();
if (dirs == null) return;
for (File dir : dirs) {
diff --git a/platform/lang-api/src/com/intellij/execution/configurations/ModuleRunProfile.java b/platform/lang-api/src/com/intellij/execution/configurations/ModuleRunProfile.java
index 9a1dfad2955a..45519c91baeb 100644
--- a/platform/lang-api/src/com/intellij/execution/configurations/ModuleRunProfile.java
+++ b/platform/lang-api/src/com/intellij/execution/configurations/ModuleRunProfile.java
@@ -19,5 +19,5 @@ package com.intellij.execution.configurations;
/**
* @author spleaner
*/
-public interface ModuleRunProfile extends RunProfileWithCompileBeforeLaunchOption {
+public interface ModuleRunProfile extends RunProfileWithCompileBeforeLaunchOption, SearchScopeProvidingRunProfile {
}
diff --git a/platform/lang-api/src/com/intellij/execution/configurations/RunConfigurationBase.java b/platform/lang-api/src/com/intellij/execution/configurations/RunConfigurationBase.java
index 0e852c6c577a..d0a180114587 100644
--- a/platform/lang-api/src/com/intellij/execution/configurations/RunConfigurationBase.java
+++ b/platform/lang-api/src/com/intellij/execution/configurations/RunConfigurationBase.java
@@ -154,8 +154,9 @@ public abstract class RunConfigurationBase extends UserDataHolderBase
return myPredefinedLogFiles;
}
+ @NotNull
public ArrayList<LogFileOptions> getAllLogFiles() {
- final ArrayList<LogFileOptions> list = new ArrayList<LogFileOptions>(myLogFiles);
+ ArrayList<LogFileOptions> list = new ArrayList<LogFileOptions>(myLogFiles);
for (PredefinedLogFile predefinedLogFile : myPredefinedLogFiles) {
final LogFileOptions options = getOptionsForPredefinedLogFile(predefinedLogFile);
if (options != null) {
diff --git a/platform/lang-api/src/com/intellij/execution/configurations/RunConfigurationsSettings.java b/platform/lang-api/src/com/intellij/execution/configurations/RunConfigurationsSettings.java
index 259fd4e7484c..732976cf73a7 100644
--- a/platform/lang-api/src/com/intellij/execution/configurations/RunConfigurationsSettings.java
+++ b/platform/lang-api/src/com/intellij/execution/configurations/RunConfigurationsSettings.java
@@ -17,12 +17,11 @@ package com.intellij.execution.configurations;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.options.UnnamedConfigurable;
-import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
public interface RunConfigurationsSettings {
ExtensionPointName<RunConfigurationsSettings> EXTENSION_POINT = ExtensionPointName.create("com.intellij.runConfigurationsSettings");
@NotNull
- UnnamedConfigurable createConfigurable(@NotNull Project project);
+ UnnamedConfigurable createConfigurable();
} \ No newline at end of file
diff --git a/platform/lang-api/src/com/intellij/execution/configurations/SearchScopeProvider.java b/platform/lang-api/src/com/intellij/execution/configurations/SearchScopeProvider.java
index ea6b158e0bc2..e3f0c22a2132 100644
--- a/platform/lang-api/src/com/intellij/execution/configurations/SearchScopeProvider.java
+++ b/platform/lang-api/src/com/intellij/execution/configurations/SearchScopeProvider.java
@@ -28,8 +28,8 @@ public class SearchScopeProvider {
@NotNull
public static GlobalSearchScope createSearchScope(@NotNull Project project, @Nullable RunProfile runProfile) {
Module[] modules = null;
- if (runProfile instanceof ModuleRunProfile) {
- modules = ((ModuleRunProfile)runProfile).getModules();
+ if (runProfile instanceof SearchScopeProvidingRunProfile) {
+ modules = ((SearchScopeProvidingRunProfile)runProfile).getModules();
}
if (modules == null || modules.length == 0) {
return GlobalSearchScope.allScope(project);
diff --git a/platform/lang-api/src/com/intellij/execution/configurations/SearchScopeProvidingRunProfile.java b/platform/lang-api/src/com/intellij/execution/configurations/SearchScopeProvidingRunProfile.java
new file mode 100644
index 000000000000..afdd273384e8
--- /dev/null
+++ b/platform/lang-api/src/com/intellij/execution/configurations/SearchScopeProvidingRunProfile.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.intellij.execution.configurations;
+
+import com.intellij.openapi.module.Module;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Base interface for run configurations that can specify which part of the project should be used to search sources. This information
+ * will be used to provide more accurate navigation to sources from stack traces, debugger, etc
+ *
+ * @author nik
+ */
+public interface SearchScopeProvidingRunProfile extends RunProfile {
+ /**
+ * @return modules where to search sources for this configuration
+ */
+ @NotNull
+ Module[] getModules();
+} \ No newline at end of file
diff --git a/platform/lang-api/src/com/intellij/execution/configurations/SimpleJavaParameters.java b/platform/lang-api/src/com/intellij/execution/configurations/SimpleJavaParameters.java
index 7b3c45d5c7de..59fe6c2f1be2 100644
--- a/platform/lang-api/src/com/intellij/execution/configurations/SimpleJavaParameters.java
+++ b/platform/lang-api/src/com/intellij/execution/configurations/SimpleJavaParameters.java
@@ -40,11 +40,16 @@ public class SimpleJavaParameters extends SimpleProgramParameters {
private Charset myCharset = CharsetToolkit.getDefaultSystemCharset();
private boolean myUseDynamicClasspath;
private boolean myUseDynamicVMOptions;
-
+ private String myJarPath;
+
public String getMainClass() {
return myMainClass;
}
+ public String getJarPath() {
+ return myJarPath;
+ }
+
/**
* @return jdk used to launch the application.
* If the instance of the JavaParameters is used to configure app server startup script,
@@ -62,6 +67,9 @@ public class SimpleJavaParameters extends SimpleProgramParameters {
public void setMainClass(@NonNls final String mainClass) {
myMainClass = mainClass;
}
+ public void setJarPath(@NonNls final String jarPath) {
+ myJarPath = jarPath;
+ }
public PathsList getClassPath() {
return myClassPath;
diff --git a/platform/lang-api/src/com/intellij/execution/filters/ConsoleDependentFilterProvider.java b/platform/lang-api/src/com/intellij/execution/filters/ConsoleDependentFilterProvider.java
new file mode 100644
index 000000000000..1b5f625b9b0e
--- /dev/null
+++ b/platform/lang-api/src/com/intellij/execution/filters/ConsoleDependentFilterProvider.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.execution.filters;
+
+import com.intellij.execution.ui.ConsoleView;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.search.GlobalSearchScope;
+import org.jetbrains.annotations.NotNull;
+
+public abstract class ConsoleDependentFilterProvider implements ConsoleFilterProvider {
+ @NotNull
+ public abstract Filter[] getDefaultFilters(@NotNull ConsoleView consoleView, @NotNull Project project, @NotNull GlobalSearchScope scope);
+
+ @NotNull
+ @Override
+ public Filter[] getDefaultFilters(@NotNull Project project) {
+ return Filter.EMPTY_ARRAY;
+ }
+} \ No newline at end of file
diff --git a/platform/lang-api/src/com/intellij/execution/runners/AsyncGenericProgramRunner.java b/platform/lang-api/src/com/intellij/execution/runners/AsyncGenericProgramRunner.java
index ce7145adeaf9..6b63ec402320 100644
--- a/platform/lang-api/src/com/intellij/execution/runners/AsyncGenericProgramRunner.java
+++ b/platform/lang-api/src/com/intellij/execution/runners/AsyncGenericProgramRunner.java
@@ -21,6 +21,7 @@ import com.intellij.execution.RunProfileStarter;
import com.intellij.execution.configurations.RunProfileState;
import com.intellij.execution.configurations.RunnerSettings;
import com.intellij.execution.ui.RunContentDescriptor;
+import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.AsyncResult;
import com.intellij.util.Consumer;
import com.intellij.util.ui.UIUtil;
@@ -61,7 +62,17 @@ public abstract class AsyncGenericProgramRunner<Settings extends RunnerSettings>
* @return RunProfileStarter async result
*/
@NotNull
- protected abstract AsyncResult<RunProfileStarter> prepare(@NotNull ExecutionEnvironment environment, @NotNull RunProfileState state) throws ExecutionException;
+ protected AsyncResult<RunProfileStarter> prepare(@NotNull ExecutionEnvironment environment, @NotNull RunProfileState state) throws ExecutionException {
+ return prepare(environment.getProject(), environment, state);
+ }
+
+ /**
+ * @deprecated override {@link #prepare(ExecutionEnvironment, com.intellij.execution.configurations.RunProfileState)} instead
+ */
+ @Deprecated
+ protected AsyncResult<RunProfileStarter> prepare(@NotNull Project project, @NotNull ExecutionEnvironment environment, @NotNull RunProfileState state) throws ExecutionException {
+ throw new UnsupportedOperationException();
+ }
private static void startRunProfile(@NotNull ExecutionEnvironment environment,
@NotNull RunProfileState state,
diff --git a/platform/lang-api/src/com/intellij/execution/runners/ExecutionUtil.java b/platform/lang-api/src/com/intellij/execution/runners/ExecutionUtil.java
index b6c300c3f7e2..5a395ab5dd79 100644
--- a/platform/lang-api/src/com/intellij/execution/runners/ExecutionUtil.java
+++ b/platform/lang-api/src/com/intellij/execution/runners/ExecutionUtil.java
@@ -112,6 +112,10 @@ public class ExecutionUtil {
UIUtil.invokeLaterIfNeeded(new Runnable() {
@Override
public void run() {
+ if (project.isDisposed()) {
+ return;
+ }
+
ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(project);
if (toolWindowManager.canShowNotification(toolWindowId)) {
//noinspection SSBasedInspection
diff --git a/platform/lang-api/src/com/intellij/execution/ui/RunContentDescriptor.java b/platform/lang-api/src/com/intellij/execution/ui/RunContentDescriptor.java
index 60e7f03d54db..5a23ed45b1a9 100644
--- a/platform/lang-api/src/com/intellij/execution/ui/RunContentDescriptor.java
+++ b/platform/lang-api/src/com/intellij/execution/ui/RunContentDescriptor.java
@@ -15,11 +15,13 @@
*/
package com.intellij.execution.ui;
+import com.intellij.execution.DefaultExecutionResult;
import com.intellij.execution.ExecutionResult;
import com.intellij.execution.configurations.RunProfile;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.ide.HelpIdProvider;
import com.intellij.openapi.Disposable;
+import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Disposer;
import com.intellij.ui.content.Content;
@@ -44,6 +46,8 @@ public class RunContentDescriptor implements Disposable {
private Content myContent;
private Runnable myRestarter;
+ @NotNull
+ private AnAction[] myRestartActions = AnAction.EMPTY_ARRAY;
public RunContentDescriptor(@Nullable ExecutionConsole executionConsole,
@Nullable ProcessHandler processHandler,
@@ -66,7 +70,19 @@ public class RunContentDescriptor implements Disposable {
}
public RunContentDescriptor(@NotNull RunProfile profile, @NotNull ExecutionResult executionResult, @NotNull RunnerLayoutUi ui) {
- this(executionResult.getExecutionConsole(), executionResult.getProcessHandler(), ui.getComponent(), profile.getName(), profile.getIcon());
+ this(executionResult.getExecutionConsole(), executionResult.getProcessHandler(), ui.getComponent(), profile.getName(),
+ profile.getIcon());
+ if (executionResult instanceof DefaultExecutionResult) {
+ myRestartActions = ((DefaultExecutionResult)executionResult).getRestartActions();
+ }
+ }
+
+ /**
+ * @return actions to restart or rerun
+ */
+ @NotNull
+ public AnAction[] getRestartActions() {
+ return myRestartActions.clone();
}
public ExecutionConsole getExecutionConsole() {
@@ -81,6 +97,8 @@ public class RunContentDescriptor implements Disposable {
}
myComponent = null;
myRestarter = null;
+ myProcessHandler = null;
+ myContent = null;
}
/**
@@ -127,6 +145,7 @@ public class RunContentDescriptor implements Disposable {
myContent = content;
}
+ @SuppressWarnings("UnusedDeclaration")
@Nullable
@Deprecated
/**
diff --git a/platform/lang-api/src/com/intellij/find/FindModel.java b/platform/lang-api/src/com/intellij/find/FindModel.java
index 5dafc2db8acf..d07187796872 100644
--- a/platform/lang-api/src/com/intellij/find/FindModel.java
+++ b/platform/lang-api/src/com/intellij/find/FindModel.java
@@ -107,9 +107,7 @@ public class FindModel extends UserDataHolderBase implements Cloneable {
if (!multiline) {
initStringToFindNoMultiline(this, getStringToFind());
}
- else {
- setRegularExpressions(false);
- }
+
isMultiline = multiline;
notifyObservers();
}
diff --git a/platform/lang-api/src/com/intellij/ide/util/projectWizard/ModuleBuilder.java b/platform/lang-api/src/com/intellij/ide/util/projectWizard/ModuleBuilder.java
index fddb2b2f50b7..861123ab7839 100644
--- a/platform/lang-api/src/com/intellij/ide/util/projectWizard/ModuleBuilder.java
+++ b/platform/lang-api/src/com/intellij/ide/util/projectWizard/ModuleBuilder.java
@@ -25,6 +25,8 @@ import com.intellij.openapi.module.*;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.project.DumbAwareRunnable;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.project.ProjectType;
+import com.intellij.openapi.project.ProjectTypeService;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.ContentEntry;
import com.intellij.openapi.roots.ModifiableRootModel;
@@ -56,12 +58,12 @@ public abstract class ModuleBuilder extends AbstractModuleBuilder {
public static final ExtensionPointName<ModuleBuilderFactory> EP_NAME = ExtensionPointName.create("com.intellij.moduleBuilder");
private static final Logger LOG = Logger.getInstance("#com.intellij.ide.util.projectWizard.ModuleBuilder");
+ private final Set<ModuleConfigurationUpdater> myUpdaters = new HashSet<ModuleConfigurationUpdater>();
+ private final EventDispatcher<ModuleBuilderListener> myDispatcher = EventDispatcher.create(ModuleBuilderListener.class);
protected Sdk myJdk;
private String myName;
@NonNls private String myModuleFilePath;
private String myContentEntryPath;
- private final Set<ModuleConfigurationUpdater> myUpdaters = new HashSet<ModuleConfigurationUpdater>();
- private final EventDispatcher<ModuleBuilderListener> myDispatcher = EventDispatcher.create(ModuleBuilderListener.class);
@NotNull
public static List<ModuleBuilder> getAllBuilders() {
@@ -81,6 +83,17 @@ public abstract class ModuleBuilder extends AbstractModuleBuilder {
});
}
+ public static void deleteModuleFile(String moduleFilePath) {
+ final File moduleFile = new File(moduleFilePath);
+ if (moduleFile.exists()) {
+ FileUtil.delete(moduleFile);
+ }
+ final VirtualFile file = LocalFileSystem.getInstance().findFileByIoFile(moduleFile);
+ if (file != null) {
+ file.refresh(false, false);
+ }
+ }
+
protected boolean isAvailable() {
return true;
}
@@ -95,6 +108,11 @@ public abstract class ModuleBuilder extends AbstractModuleBuilder {
}
@Override
+ public void setName(String name) {
+ myName = acceptParameter(name);
+ }
+
+ @Override
@Nullable
public String getBuilderId() {
ModuleType moduleType = getModuleType();
@@ -167,24 +185,19 @@ public abstract class ModuleBuilder extends AbstractModuleBuilder {
return Collections.emptyList();
}
- @Override
- public void setName(String name) {
- myName = acceptParameter(name);
- }
-
public String getModuleFilePath() {
return myModuleFilePath;
}
- public void addModuleConfigurationUpdater(ModuleConfigurationUpdater updater) {
- myUpdaters.add(updater);
- }
-
@Override
public void setModuleFilePath(@NonNls String path) {
myModuleFilePath = acceptParameter(path);
}
+ public void addModuleConfigurationUpdater(ModuleConfigurationUpdater updater) {
+ myUpdaters.add(updater);
+ }
+
@Nullable
public String getContentEntryPath() {
if (myContentEntryPath == null) {
@@ -259,6 +272,7 @@ public abstract class ModuleBuilder extends AbstractModuleBuilder {
updater.update(module, modifiableModel);
}
modifiableModel.commit();
+ setProjectType(module);
}
private void onModuleInitialized(final Module module) {
@@ -269,6 +283,17 @@ public abstract class ModuleBuilder extends AbstractModuleBuilder {
public abstract ModuleType getModuleType();
+ protected ProjectType getProjectType() {
+ return null;
+ }
+
+ protected void setProjectType(Module module) {
+ ProjectType projectType = getProjectType();
+ if (projectType != null && ProjectTypeService.getProjectType(module.getProject()) == null) {
+ ProjectTypeService.setProjectType(module.getProject(), projectType);
+ }
+ }
+
@NotNull
public Module createAndCommitIfNeeded(@NotNull Project project, @Nullable ModifiableModuleModel model, boolean runFromProjectWizard)
throws InvalidDataException, ConfigurationException, IOException, JDOMException, ModuleWithNameAlreadyExists {
@@ -295,7 +320,6 @@ public abstract class ModuleBuilder extends AbstractModuleBuilder {
return module;
}
-
public void addListener(ModuleBuilderListener listener) {
myDispatcher.addListener(listener);
}
@@ -340,17 +364,6 @@ public abstract class ModuleBuilder extends AbstractModuleBuilder {
return null;
}
- public static void deleteModuleFile(String moduleFilePath) {
- final File moduleFile = new File(moduleFilePath);
- if (moduleFile.exists()) {
- FileUtil.delete(moduleFile);
- }
- final VirtualFile file = LocalFileSystem.getInstance().findFileByIoFile(moduleFile);
- if (file != null) {
- file.refresh(false, false);
- }
- }
-
public Icon getBigIcon() {
return getModuleType().getBigIcon();
}
@@ -396,14 +409,14 @@ public abstract class ModuleBuilder extends AbstractModuleBuilder {
myModuleFilePath = from.getModuleFilePath();
}
- public void setModuleJdk(Sdk jdk) {
- myJdk = jdk;
- }
-
public Sdk getModuleJdk() {
return myJdk;
}
+ public void setModuleJdk(Sdk jdk) {
+ myJdk = jdk;
+ }
+
@NotNull
public FrameworkRole getDefaultAcceptableRole() {
return getModuleType().getDefaultAcceptableRole();
diff --git a/platform/lang-api/src/com/intellij/lang/documentation/DocumentationProviderEx.java b/platform/lang-api/src/com/intellij/lang/documentation/DocumentationProviderEx.java
index 8b9143a0d995..9d7a10d6ba5e 100644
--- a/platform/lang-api/src/com/intellij/lang/documentation/DocumentationProviderEx.java
+++ b/platform/lang-api/src/com/intellij/lang/documentation/DocumentationProviderEx.java
@@ -29,6 +29,7 @@ import java.util.List;
* @author peter
*/
public class DocumentationProviderEx implements DocumentationProvider {
+ @Nullable
@Override
public String getQuickNavigateInfo(PsiElement element, PsiElement originalElement) {
return null;
diff --git a/platform/lang-api/src/com/intellij/openapi/projectRoots/JdkUtil.java b/platform/lang-api/src/com/intellij/openapi/projectRoots/JdkUtil.java
index 4291e9b401bf..337909b318e5 100644
--- a/platform/lang-api/src/com/intellij/openapi/projectRoots/JdkUtil.java
+++ b/platform/lang-api/src/com/intellij/openapi/projectRoots/JdkUtil.java
@@ -247,7 +247,15 @@ public class JdkUtil {
}
final String mainClass = javaParameters.getMainClass();
- commandLine.addParameter(mainClass);
+ String jarPath = javaParameters.getJarPath();
+ if (mainClass != null) {
+ commandLine.addParameter(mainClass);
+ }
+ else if (jarPath != null) {
+ commandLine.addParameter("-jar");
+ commandLine.addParameter(jarPath);
+ }
+
commandLine.addParameters(javaParameters.getProgramParametersList().getList());
commandLine.setWorkDirectory(javaParameters.getWorkingDirectory());
@@ -260,7 +268,7 @@ public class JdkUtil {
ParametersList parametersList) {
commandLine.addParameters(parametersList.getList());
appendEncoding(javaParameters, commandLine, parametersList);
- if (!parametersList.hasParameter("-classpath") && !parametersList.hasParameter("-cp")){
+ if (!parametersList.hasParameter("-classpath") && !parametersList.hasParameter("-cp") && !javaParameters.getClassPath().getPathList().isEmpty()){
commandLine.addParameter("-classpath");
commandLine.addParameter(javaParameters.getClassPath().getPathsString());
}
diff --git a/platform/lang-api/src/com/intellij/openapi/projectRoots/ui/PathEditor.java b/platform/lang-api/src/com/intellij/openapi/projectRoots/ui/PathEditor.java
index ecebb9db73f3..ae9f0142f246 100644
--- a/platform/lang-api/src/com/intellij/openapi/projectRoots/ui/PathEditor.java
+++ b/platform/lang-api/src/com/intellij/openapi/projectRoots/ui/PathEditor.java
@@ -23,7 +23,6 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileChooser.FileChooser;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
-import com.intellij.openapi.fileChooser.FileChooserDialog;
import com.intellij.openapi.fileTypes.FileTypes;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
@@ -67,7 +66,6 @@ public class PathEditor {
public PathEditor(final FileChooserDescriptor descriptor) {
myDescriptor = descriptor;
- myDescriptor.putUserData(FileChooserDialog.PREFER_LAST_OVER_TO_SELECT, Boolean.TRUE);
myModel = createListModel();
}
@@ -176,12 +174,8 @@ public class PathEditor {
}
protected VirtualFile[] doAdd() {
- VirtualFile baseDir = myAddBaseDir;
Project project = CommonDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(myPanel));
- if (baseDir == null && project != null) {
- baseDir = project.getBaseDir();
- }
- VirtualFile[] files = FileChooser.chooseFiles(myDescriptor, myPanel, project, baseDir);
+ VirtualFile[] files = FileChooser.chooseFiles(myDescriptor, myPanel, project, myAddBaseDir);
files = adjustAddedFileSet(myPanel, files);
List<VirtualFile> added = new ArrayList<VirtualFile>(files.length);
for (VirtualFile vFile : files) {
diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettingsCustomizable.java b/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettingsCustomizable.java
index 290078e39aa9..2ef2c998b3b4 100644
--- a/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettingsCustomizable.java
+++ b/platform/lang-api/src/com/intellij/psi/codeStyle/CodeStyleSettingsCustomizable.java
@@ -214,6 +214,7 @@ public interface CodeStyleSettingsCustomizable {
String WRAPPING_KEEP = ApplicationBundle.message("wrapping.keep.when.reformatting");
String WRAPPING_BRACES = ApplicationBundle.message("wrapping.brace.placement");
+ String WRAPPING_COMMENTS = ApplicationBundle.message("wrapping.comments");
String WRAPPING_METHOD_PARAMETERS = ApplicationBundle.message("wrapping.method.parameters");
String WRAPPING_METHOD_PARENTHESES = ApplicationBundle.message("wrapping.method.parentheses");
String WRAPPING_METHOD_ARGUMENTS_WRAPPING = ApplicationBundle.message("wrapping.method.arguments");
diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java b/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java
index 299d17215fdf..fa284c8fd33c 100644
--- a/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java
+++ b/platform/lang-api/src/com/intellij/psi/codeStyle/CommonCodeStyleSettings.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,7 +21,7 @@ import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.util.*;
import com.intellij.psi.codeStyle.arrangement.ArrangementSettings;
import com.intellij.psi.codeStyle.arrangement.ArrangementUtil;
-import com.intellij.util.containers.HashSet;
+import com.intellij.util.ReflectionUtil;
import com.intellij.util.xmlb.SkipDefaultValuesSerializationFilters;
import com.intellij.util.xmlb.XmlSerializer;
import org.intellij.lang.annotations.MagicConstant;
@@ -31,8 +31,6 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-import java.util.Arrays;
import java.util.Set;
/**
@@ -155,63 +153,20 @@ public class CommonCodeStyleSettings {
protected static void copyPublicFields(Object from, Object to) {
assert from != to;
- copyFields(to.getClass().getFields(), from, to);
+ ReflectionUtil.copyFields(to.getClass().getFields(), from, to);
}
void copyNonDefaultValuesFrom(CommonCodeStyleSettings from) {
CommonCodeStyleSettings defaultSettings = new CommonCodeStyleSettings(null);
PARENT_SETTINGS_INSTALLED =
- copyFields(getClass().getFields(), from, this, new SupportedFieldsDiffFilter(from, getSupportedFields(), defaultSettings) {
- @Override
- public boolean isAccept(@NotNull Field field) {
- if ("RIGHT_MARGIN".equals(field.getName())) return false; // Never copy RIGHT_MARGIN, it is inherited automatically if -1
- return super.isAccept(field);
- }
- });
- }
-
- private static void copyFields(Field[] fields, Object from, Object to) {
- copyFields(fields, from, to, null);
- }
-
- private static boolean copyFields(Field[] fields, Object from, Object to, @Nullable DifferenceFilter diffFilter) {
- Set<Field> sourceFields = new HashSet<Field>(Arrays.asList(from.getClass().getFields()));
- boolean valuesChanged = false;
- for (Field field : fields) {
- if (sourceFields.contains(field)) {
- if (isPublic(field) && !isFinal(field)) {
- try {
- if (diffFilter == null || diffFilter.isAccept(field)) {
- copyFieldValue(from, to, field);
- valuesChanged = true;
- }
- }
- catch (Exception e) {
- throw new RuntimeException(e);
+ ReflectionUtil
+ .copyFields(getClass().getFields(), from, this, new SupportedFieldsDiffFilter(from, getSupportedFields(), defaultSettings) {
+ @Override
+ public boolean isAccept(@NotNull Field field) {
+ if ("RIGHT_MARGIN".equals(field.getName())) return false; // Never copy RIGHT_MARGIN, it is inherited automatically if -1
+ return super.isAccept(field);
}
- }
- }
- }
- return valuesChanged;
- }
-
- private static void copyFieldValue(final Object from, Object to, final Field field)
- throws IllegalAccessException {
- Class<?> fieldType = field.getType();
- if (fieldType.isPrimitive() || fieldType.equals(String.class)) {
- field.set(to, field.get(from));
- }
- else {
- throw new RuntimeException("Field not copied " + field.getName());
- }
- }
-
- private static boolean isPublic(final Field field) {
- return (field.getModifiers() & Modifier.PUBLIC) != 0;
- }
-
- private static boolean isFinal(final Field field) {
- return (field.getModifiers() & Modifier.FINAL) != 0;
+ });
}
@Nullable
diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/autodetect/IndentOptionsDetector.java b/platform/lang-api/src/com/intellij/psi/codeStyle/autodetect/IndentOptionsDetector.java
new file mode 100644
index 000000000000..527ee9e79a49
--- /dev/null
+++ b/platform/lang-api/src/com/intellij/psi/codeStyle/autodetect/IndentOptionsDetector.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.psi.codeStyle.autodetect;
+
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+
+import static com.intellij.psi.codeStyle.CommonCodeStyleSettings.*;
+
+public class IndentOptionsDetector {
+ private static Logger LOG = Logger.getInstance("#com.intellij.psi.codeStyle.CommonCodeStyleSettings.IndentOptionsDetector");
+
+ private static final double RATE_THRESHOLD = 0.8;
+ private static final int MIN_LINES_THRESHOLD = 50;
+ private static final int MAX_INDENT_TO_DETECT = 8;
+
+ private final PsiFile myFile;
+ private final Project myProject;
+ private final Document myDocument;
+
+ public IndentOptionsDetector(@NotNull PsiFile file) {
+ myFile = file;
+ myProject = file.getProject();
+ myDocument = PsiDocumentManager.getInstance(myProject).getDocument(myFile);
+ }
+
+ @NotNull
+ public IndentOptions getIndentOptions() {
+ IndentOptions indentOptions = (IndentOptions)CodeStyleSettingsManager.getSettings(myProject).getIndentOptions(myFile.getFileType()).clone();
+
+ if (myDocument != null) {
+ List<LineIndentInfo> linesInfo = new LineIndentInfoBuilder(myDocument.getCharsSequence()).build();
+ IndentUsageStatistics stats = new IndentUsageStatisticsImpl(linesInfo);
+ adjustIndentOptions(indentOptions, stats);
+ }
+
+ return indentOptions;
+ }
+
+ private void adjustIndentOptions(@NotNull IndentOptions indentOptions, @NotNull IndentUsageStatistics stats) {
+ int linesWithTabs = stats.getTotalLinesWithLeadingTabs();
+ int linesWithWhiteSpaceIndent = stats.getTotalLinesWithLeadingSpaces();
+
+ int totalLines = linesWithTabs + linesWithWhiteSpaceIndent;
+ double lineWithTabsRate = (double)linesWithTabs / totalLines;
+
+ if (linesWithTabs > MIN_LINES_THRESHOLD && lineWithTabsRate > RATE_THRESHOLD) {
+ if (!indentOptions.USE_TAB_CHARACTER) {
+ indentOptions.USE_TAB_CHARACTER = true;
+ LOG.info("Detected tab usage in" + myFile);
+ }
+ }
+ else if (linesWithWhiteSpaceIndent > MIN_LINES_THRESHOLD && (1 - lineWithTabsRate) > RATE_THRESHOLD) {
+ int newIndentSize = getPositiveIndentSize(stats);
+ if (newIndentSize > 0 && indentOptions.INDENT_SIZE != newIndentSize) {
+ indentOptions.INDENT_SIZE = newIndentSize;
+ LOG.info("Detected indent size: " + newIndentSize + " for file " + myFile);
+ }
+ }
+ }
+
+ private static int getPositiveIndentSize(@NotNull IndentUsageStatistics stats) {
+ int totalIndentSizesDetected = stats.getTotalIndentSizesDetected();
+ if (totalIndentSizesDetected == 0) return -1;
+
+ IndentUsageInfo maxUsedIndentInfo = stats.getKMostUsedIndentInfo(0);
+ int maxUsedIndentSize = maxUsedIndentInfo.getIndentSize();
+
+ if (maxUsedIndentSize == 0) {
+ if (totalIndentSizesDetected < 1) return -1;
+
+ maxUsedIndentInfo = stats.getKMostUsedIndentInfo(1);
+ maxUsedIndentSize = maxUsedIndentInfo.getIndentSize();
+ }
+
+ if (maxUsedIndentSize <= MAX_INDENT_TO_DETECT) {
+ int totalUsagesWithoutZeroIndent = stats.getTotalLinesWithLeadingSpaces() - stats.getTimesIndentUsed(0);
+ double usageRate = (double)maxUsedIndentInfo.getTimesUsed() / totalUsagesWithoutZeroIndent;
+ if (usageRate > RATE_THRESHOLD) {
+ return maxUsedIndentSize;
+ }
+ }
+
+ return -1;
+ }
+}
diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/autodetect/IndentUsageInfo.java b/platform/lang-api/src/com/intellij/psi/codeStyle/autodetect/IndentUsageInfo.java
new file mode 100644
index 000000000000..a600483a07a6
--- /dev/null
+++ b/platform/lang-api/src/com/intellij/psi/codeStyle/autodetect/IndentUsageInfo.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.psi.codeStyle.autodetect;
+
+public class IndentUsageInfo {
+ private final int indentSize;
+ private final int timesUsed;
+
+ public IndentUsageInfo(int indentSize, int timesUsed) {
+ this.indentSize = indentSize;
+ this.timesUsed = timesUsed;
+ }
+
+ public int getIndentSize() {
+ return indentSize;
+ }
+
+ public int getTimesUsed() {
+ return timesUsed;
+ }
+
+ @Override
+ public String toString() {
+ return "indent: " + indentSize + ", used " + timesUsed;
+ }
+}
diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/autodetect/IndentUsageStatistics.java b/platform/lang-api/src/com/intellij/psi/codeStyle/autodetect/IndentUsageStatistics.java
new file mode 100644
index 000000000000..7e3bee7221da
--- /dev/null
+++ b/platform/lang-api/src/com/intellij/psi/codeStyle/autodetect/IndentUsageStatistics.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.psi.codeStyle.autodetect;
+
+public interface IndentUsageStatistics {
+
+ int getTotalLinesWithLeadingTabs();
+
+ int getTotalLinesWithLeadingSpaces();
+
+ IndentUsageInfo getKMostUsedIndentInfo(int k);
+
+ int getTotalIndentSizesDetected();
+
+ int getTimesIndentUsed(int indent);
+
+}
diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/autodetect/IndentUsageStatisticsImpl.java b/platform/lang-api/src/com/intellij/psi/codeStyle/autodetect/IndentUsageStatisticsImpl.java
new file mode 100644
index 000000000000..99de432f101d
--- /dev/null
+++ b/platform/lang-api/src/com/intellij/psi/codeStyle/autodetect/IndentUsageStatisticsImpl.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.psi.codeStyle.autodetect;
+
+import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.containers.Stack;
+import gnu.trove.TIntIntHashMap;
+import gnu.trove.TIntIntIterator;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Comparator;
+import java.util.List;
+
+public class IndentUsageStatisticsImpl implements IndentUsageStatistics {
+ private static final Comparator<IndentUsageInfo> DECREASING_ORDER = new Comparator<IndentUsageInfo>() {
+ @Override
+ public int compare(@NotNull IndentUsageInfo o1, @NotNull IndentUsageInfo o2) {
+ return o1.getTimesUsed() < o2.getTimesUsed() ? 1 : o1.getTimesUsed() == o2.getTimesUsed() ? 0 : -1;
+ }
+ };
+
+ private List<LineIndentInfo> myLineInfos;
+
+ private int myPreviousLineIndent;
+ private int myPreviousRelativeIndent;
+
+ private int myTotalLinesWithTabs = 0;
+ private int myTotalLinesWithWhiteSpaces = 0;
+
+ private TIntIntHashMap myIndentToUsagesMap = new TIntIntHashMap();
+ private List<IndentUsageInfo> myIndentUsages = ContainerUtil.newArrayList();
+ private Stack<IndentData> myParentIndents = ContainerUtil.newStack(new IndentData(0, 0));
+
+ public IndentUsageStatisticsImpl(@NotNull List<LineIndentInfo> lineInfos) {
+ myLineInfos = lineInfos;
+ buildIndentToUsagesMap();
+ myIndentUsages = toIndentUsageList(myIndentToUsagesMap);
+ ContainerUtil.sort(myIndentUsages, DECREASING_ORDER);
+ }
+
+ @NotNull
+ private static List<IndentUsageInfo> toIndentUsageList(@NotNull TIntIntHashMap indentToUsages) {
+ List<IndentUsageInfo> indentUsageInfos = ContainerUtil.newArrayList();
+ TIntIntIterator it = indentToUsages.iterator();
+ while (it.hasNext()) {
+ it.advance();
+ indentUsageInfos.add(new IndentUsageInfo(it.key(), it.value()));
+ }
+ return indentUsageInfos;
+ }
+
+ public void buildIndentToUsagesMap() {
+ myPreviousLineIndent = 0;
+ myPreviousRelativeIndent = 0;
+
+ for (LineIndentInfo lineInfo : myLineInfos) {
+ if (lineInfo.isLineWithTabs()) {
+ myTotalLinesWithTabs++;
+ }
+ else if (lineInfo.isLineWithWhiteSpaceIndent()) {
+ handleWhiteSpaceIndent(lineInfo.getIndentSize());
+ }
+ }
+ }
+
+ @NotNull
+ private IndentData findParentIndent(int indent) {
+ while (myParentIndents.size() != 1 && myParentIndents.peek().indent > indent) {
+ myParentIndents.pop();
+ }
+ return myParentIndents.peek();
+ }
+
+ private void handleWhiteSpaceIndent(int currentIndent) {
+ int relativeIndent = currentIndent - myPreviousLineIndent;
+ if (relativeIndent < 0) {
+ IndentData indentData = findParentIndent(currentIndent);
+ myPreviousLineIndent = indentData.indent;
+ myPreviousRelativeIndent = indentData.relativeIndent;
+ relativeIndent = currentIndent - myPreviousLineIndent;
+ }
+
+ if (relativeIndent == 0) {
+ relativeIndent = myPreviousRelativeIndent;
+ }
+ else {
+ myParentIndents.push(new IndentData(currentIndent, relativeIndent));
+ }
+
+ increaseIndentUsage(relativeIndent);
+
+ myPreviousRelativeIndent = relativeIndent;
+ myPreviousLineIndent = currentIndent;
+ myTotalLinesWithWhiteSpaces++;
+ }
+
+ private void increaseIndentUsage(int relativeIndent) {
+ int timesUsed = myIndentToUsagesMap.get(relativeIndent);
+ myIndentToUsagesMap.put(relativeIndent, ++timesUsed);
+ }
+
+ @Override
+ public int getTotalLinesWithLeadingTabs() {
+ return myTotalLinesWithTabs;
+ }
+
+ @Override
+ public int getTotalLinesWithLeadingSpaces() {
+ return myTotalLinesWithWhiteSpaces;
+ }
+
+ @Override
+ public IndentUsageInfo getKMostUsedIndentInfo(int k) {
+ return myIndentUsages.get(k);
+ }
+
+ @Override
+ public int getTimesIndentUsed(int indent) {
+ return myIndentToUsagesMap.get(indent);
+ }
+
+ @Override
+ public int getTotalIndentSizesDetected() {
+ return myIndentToUsagesMap.size();
+ }
+
+ private static class IndentData {
+ public final int indent;
+ public final int relativeIndent;
+
+ public IndentData(int indent, int relativeIndent) {
+ this.indent = indent;
+ this.relativeIndent = relativeIndent;
+ }
+ }
+}
diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/autodetect/LineIndentInfo.java b/platform/lang-api/src/com/intellij/psi/codeStyle/autodetect/LineIndentInfo.java
new file mode 100644
index 000000000000..d85a4cbcaa0e
--- /dev/null
+++ b/platform/lang-api/src/com/intellij/psi/codeStyle/autodetect/LineIndentInfo.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.psi.codeStyle.autodetect;
+
+import org.jetbrains.annotations.NotNull;
+
+public class LineIndentInfo {
+ public static final LineIndentInfo EMPTY_LINE = new LineIndentInfo(LineType.EMPTY_LINE, -1);
+ public static final LineIndentInfo LINE_WITH_COMMENT = new LineIndentInfo(LineType.LINE_WITH_COMMENT, -1);
+ public static final LineIndentInfo LINE_WITH_TABS = new LineIndentInfo(LineType.LINE_WITH_TABS, -1);
+
+ private final int myIndentSize;
+ private final LineType myType;
+
+ private LineIndentInfo(@NotNull LineType type, int indentSize) {
+ myType = type;
+ myIndentSize = indentSize;
+ }
+
+ @NotNull
+ public static LineIndentInfo newWhiteSpaceIndent(int indentSize) {
+ return new LineIndentInfo(LineType.LINE_WITH_WHITESPACE_INDENT, indentSize);
+ }
+
+ public int getIndentSize() {
+ return myIndentSize;
+ }
+
+ public boolean isLineWithWhiteSpaceIndent() {
+ return myType == LineType.LINE_WITH_WHITESPACE_INDENT;
+ }
+
+ public boolean isLineWithTabs() {
+ return myType == LineType.LINE_WITH_TABS;
+ }
+
+ private enum LineType {
+ EMPTY_LINE,
+ LINE_WITH_COMMENT,
+ LINE_WITH_TABS,
+ LINE_WITH_WHITESPACE_INDENT
+ }
+}
diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/autodetect/LineIndentInfoBuilder.java b/platform/lang-api/src/com/intellij/psi/codeStyle/autodetect/LineIndentInfoBuilder.java
new file mode 100644
index 000000000000..8efbbc495750
--- /dev/null
+++ b/platform/lang-api/src/com/intellij/psi/codeStyle/autodetect/LineIndentInfoBuilder.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.psi.codeStyle.autodetect;
+
+import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.text.CharArrayUtil;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+
+public class LineIndentInfoBuilder {
+ private static final int MAX_LINES_TO_PROCESS = 500;
+
+ private final CharSequence myText;
+ private final int myLength;
+
+ public LineIndentInfoBuilder(@NotNull CharSequence text) {
+ myText = text;
+ myLength = text.length();
+ }
+
+ @NotNull
+ public List<LineIndentInfo> build() {
+ List<LineIndentInfo> lineIndentInfos = ContainerUtil.newArrayList();
+
+ int lineStartOffset = 0;
+ int currentLine = 0;
+
+ while (lineStartOffset < myText.length() && currentLine < MAX_LINES_TO_PROCESS) {
+ int lineEndOffset = getLineEndOffset(lineStartOffset);
+ int textStartOffset = CharArrayUtil.shiftForward(myText, lineStartOffset, lineEndOffset, " \t");
+
+ if (textStartOffset != lineEndOffset) {
+ lineIndentInfos.add(createInfoFromWhiteSpaceRange(lineStartOffset, textStartOffset));
+ } else {
+ lineIndentInfos.add(LineIndentInfo.EMPTY_LINE);
+ }
+
+ lineStartOffset = lineEndOffset + 1;
+ currentLine++;
+ }
+
+ return lineIndentInfos;
+ }
+
+ @NotNull
+ private LineIndentInfo createInfoFromWhiteSpaceRange(int lineStartOffset, int textStartOffset) {
+ if (myText.charAt(textStartOffset) == '*') {
+ return LineIndentInfo.LINE_WITH_COMMENT;
+ }
+ else if (CharArrayUtil.indexOf(myText, "\t", lineStartOffset, textStartOffset) > 0) {
+ return LineIndentInfo.LINE_WITH_TABS;
+ }
+ else {
+ int indentSize = textStartOffset - lineStartOffset;
+ return LineIndentInfo.newWhiteSpaceIndent(indentSize);
+ }
+ }
+
+ private int getLineEndOffset(int lineStartOffset) {
+ int lineEndOffset = CharArrayUtil.indexOf(myText, "\n", lineStartOffset, myLength);
+ if (lineEndOffset < 0) {
+ lineEndOffset = myText.length();
+ }
+ return lineEndOffset;
+ }
+}
diff --git a/platform/lang-api/src/com/intellij/psi/util/PsiUtilBase.java b/platform/lang-api/src/com/intellij/psi/util/PsiUtilBase.java
index 4565832c310b..b63ee1d6ab2d 100644
--- a/platform/lang-api/src/com/intellij/psi/util/PsiUtilBase.java
+++ b/platform/lang-api/src/com/intellij/psi/util/PsiUtilBase.java
@@ -40,7 +40,9 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
+import java.awt.*;
import java.util.*;
+import java.util.List;
public class PsiUtilBase extends PsiUtilCore implements PsiEditorUtil {
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.util.PsiUtilBase");
@@ -235,6 +237,9 @@ public class PsiUtilBase extends PsiUtilCore implements PsiEditorUtil {
*/
@Nullable
public static Editor findEditor(@NotNull PsiElement element) {
+ if (!EventQueue.isDispatchThread()) {
+ LOG.warn("Invoke findEditor() from EDT only. Otherwise, it causes deadlocks.");
+ }
PsiFile psiFile = element.getContainingFile();
VirtualFile virtualFile = PsiUtilCore.getVirtualFile(element);
if (virtualFile == null) {
diff --git a/platform/lang-impl/src/com/intellij/analysis/BaseAnalysisAction.java b/platform/lang-impl/src/com/intellij/analysis/BaseAnalysisAction.java
index c63f8cdc2fd7..af46c5178f9f 100644
--- a/platform/lang-impl/src/com/intellij/analysis/BaseAnalysisAction.java
+++ b/platform/lang-impl/src/com/intellij/analysis/BaseAnalysisAction.java
@@ -70,7 +70,7 @@ public abstract class BaseAnalysisAction extends AnAction {
}
AnalysisScope scope = getInspectionScope(dataContext);
LOG.assertTrue(scope != null);
- final boolean rememberScope = e.getPlace().equals(ActionPlaces.MAIN_MENU);
+ final boolean rememberScope = ActionPlaces.isMainMenuOrActionSearch(e.getPlace());
final AnalysisUIOptions uiOptions = AnalysisUIOptions.getInstance(project);
PsiElement element = CommonDataKeys.PSI_ELEMENT.getData(dataContext);
BaseAnalysisActionDialog dlg = new BaseAnalysisActionDialog(AnalysisScopeBundle.message("specify.analysis.scope", myTitle),
diff --git a/platform/lang-impl/src/com/intellij/application/options/CodeStyleSchemesConfigurable.java b/platform/lang-impl/src/com/intellij/application/options/CodeStyleSchemesConfigurable.java
index 760d17e67d24..758aef6a9065 100644
--- a/platform/lang-impl/src/com/intellij/application/options/CodeStyleSchemesConfigurable.java
+++ b/platform/lang-impl/src/com/intellij/application/options/CodeStyleSchemesConfigurable.java
@@ -302,6 +302,11 @@ public class CodeStyleSchemesConfigurable extends SearchableConfigurable.Parent.
@Override
public boolean isModified() {
if (myModel != null) {
+ if (Registry.is("ide.new.settings.dialog")) {
+ if (myPanels != null && myPanels.size() > 0 && myPanels.get(0).isModified()) {
+ return true;
+ }
+ }
boolean schemeListModified = myModel.isSchemeListModified();
if (schemeListModified) {
myApplyCompleted = false;
diff --git a/platform/lang-impl/src/com/intellij/application/options/ModuleListCellRenderer.java b/platform/lang-impl/src/com/intellij/application/options/ModuleListCellRenderer.java
index f544517bb5d4..6bc5f6505c92 100644
--- a/platform/lang-impl/src/com/intellij/application/options/ModuleListCellRenderer.java
+++ b/platform/lang-impl/src/com/intellij/application/options/ModuleListCellRenderer.java
@@ -3,6 +3,7 @@ package com.intellij.application.options;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleType;
import com.intellij.ui.ListCellRendererWrapper;
+import org.jetbrains.annotations.NotNull;
import javax.swing.*;
@@ -10,10 +11,20 @@ import javax.swing.*;
* @author yole
*/
public class ModuleListCellRenderer extends ListCellRendererWrapper<Module> {
+ private final String myEmptySelectionText;
+
+ public ModuleListCellRenderer() {
+ this("[none]");
+ }
+
+ public ModuleListCellRenderer(@NotNull String emptySelectionText) {
+ myEmptySelectionText = emptySelectionText;
+ }
+
@Override
public void customize(JList list, Module module, int index, boolean selected, boolean hasFocus) {
if (module == null) {
- setText("[none]");
+ setText(myEmptySelectionText);
}
else {
setIcon(ModuleType.get(module).getIcon());
diff --git a/platform/lang-impl/src/com/intellij/application/options/ModulesComboBox.java b/platform/lang-impl/src/com/intellij/application/options/ModulesComboBox.java
index 17434cb0c7ba..4c2ef3a3d16c 100644
--- a/platform/lang-impl/src/com/intellij/application/options/ModulesComboBox.java
+++ b/platform/lang-impl/src/com/intellij/application/options/ModulesComboBox.java
@@ -36,6 +36,7 @@ import java.util.List;
*/
public class ModulesComboBox extends ComboBox {
private final SortedComboBoxModel<Module> myModel;
+ private boolean myAllowEmptySelection;
public ModulesComboBox() {
this(new SortedComboBoxModel<Module>(ModulesAlphaComparator.INSTANCE));
@@ -58,8 +59,17 @@ public class ModulesComboBox extends ComboBox {
setRenderer(new ModuleListCellRenderer());
}
+ public void allowEmptySelection(@NotNull String emptySelectionText) {
+ myAllowEmptySelection = true;
+ myModel.add(null);
+ setRenderer(new ModuleListCellRenderer(emptySelectionText));
+ }
+
public void setModules(@NotNull Collection<Module> modules) {
myModel.setAll(modules);
+ if (myAllowEmptySelection) {
+ myModel.add(null);
+ }
}
public void fillModules(@NotNull Project project) {
diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/ManageCodeStyleSchemesDialog.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/ManageCodeStyleSchemesDialog.java
index 653f6b51e8bd..282f44d04a60 100644
--- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/ManageCodeStyleSchemesDialog.java
+++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/ManageCodeStyleSchemesDialog.java
@@ -214,7 +214,7 @@ public class ManageCodeStyleSchemesDialog extends DialogWrapper {
return !file.isDirectory() && importer.getSourceExtension().equals(file.getExtension());
}
}, null, myContentPane);
- VirtualFile[] selection = fileChooser.choose(CodeStyleSchemesUIConfiguration.Util.getRecentImportFile(), null);
+ VirtualFile[] selection = fileChooser.choose(null, CodeStyleSchemesUIConfiguration.Util.getRecentImportFile());
if (selection.length == 1) {
VirtualFile selectedFile = selection[0];
selectedFile.refresh(false, false);
diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/WrappingAndBracesPanel.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/WrappingAndBracesPanel.java
index c192d0e2893a..2972dacf2ceb 100644
--- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/WrappingAndBracesPanel.java
+++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/WrappingAndBracesPanel.java
@@ -43,6 +43,7 @@ public class WrappingAndBracesPanel extends OptionTableWithPreviewPanel {
addOption("KEEP_SIMPLE_CLASSES_IN_ONE_LINE", ApplicationBundle.message("wrapping.keep.simple.classes.in.one.line"), WRAPPING_KEEP);
addOption("WRAP_LONG_LINES", ApplicationBundle.message("wrapping.long.lines"), null);
+ addOption("WRAP_COMMENTS", ApplicationBundle.message("wrapping.comments.wrap.at.right.margin"), WRAPPING_COMMENTS);
addOption("CLASS_BRACE_STYLE", ApplicationBundle.message("wrapping.brace.placement.class.declaration"), WRAPPING_BRACES, BRACE_PLACEMENT_OPTIONS, BRACE_PLACEMENT_VALUES);
addOption("METHOD_BRACE_STYLE", ApplicationBundle.message("wrapping.brace.placement.method.declaration"), WRAPPING_BRACES, BRACE_PLACEMENT_OPTIONS, BRACE_PLACEMENT_VALUES);
diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/AbstractArrangementRuleAction.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/AbstractArrangementRuleAction.java
new file mode 100644
index 000000000000..3036ca9ed43e
--- /dev/null
+++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/AbstractArrangementRuleAction.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.application.options.codeStyle.arrangement.action;
+
+import com.intellij.application.options.codeStyle.arrangement.match.ArrangementMatchingRulesControl;
+import com.intellij.openapi.actionSystem.AnAction;
+import org.jetbrains.annotations.NotNull;
+
+import java.awt.*;
+
+/**
+ * @author Svetlana.Zemlyanskaya
+ */
+public abstract class AbstractArrangementRuleAction extends AnAction {
+
+ protected void scrollRowToVisible(@NotNull ArrangementMatchingRulesControl control, int row) {
+ final Rectangle rect = control.getCellRect(row, 0, false);
+ if (row != control.getEditingRow() - 1) {
+ control.scrollRectToVisible(rect);
+ }
+ else {
+ final Rectangle editorRect = control.getCellRect(row + 1, 0, false);
+ if(!rect.isEmpty() && !editorRect.isEmpty()) {
+ final int height = (int)(rect.getHeight() + editorRect.getHeight());
+ final Rectangle visibleRect = new Rectangle((int)rect.getX(), (int)rect.getY(), (int)rect.getWidth(), height);
+ control.scrollRectToVisible(visibleRect);
+ }
+ }
+ }
+}
diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/AbstractMoveArrangementRuleAction.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/AbstractMoveArrangementRuleAction.java
index 0cbfa2265dc8..b790c17a659d 100644
--- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/AbstractMoveArrangementRuleAction.java
+++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/AbstractMoveArrangementRuleAction.java
@@ -17,7 +17,6 @@ package com.intellij.application.options.codeStyle.arrangement.action;
import com.intellij.application.options.codeStyle.arrangement.match.ArrangementMatchingRulesControl;
import com.intellij.application.options.codeStyle.arrangement.match.ArrangementMatchingRulesModel;
-import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.project.DumbAware;
import org.jetbrains.annotations.NotNull;
@@ -30,7 +29,7 @@ import java.util.List;
* @author Denis Zhdanov
* @since 11/13/12 7:17 PM
*/
-public abstract class AbstractMoveArrangementRuleAction extends AnAction implements DumbAware {
+public abstract class AbstractMoveArrangementRuleAction extends AbstractArrangementRuleAction implements DumbAware {
@Override
public void update(AnActionEvent e) {
@@ -95,8 +94,17 @@ public abstract class AbstractMoveArrangementRuleAction extends AnAction impleme
}
+ int visibleRow = -1;
if (newRowToEdit >= 0) {
control.showEditor(newRowToEdit);
+ visibleRow = newRowToEdit;
+ }
+ else if (!mappings.isEmpty()) {
+ visibleRow = mappings.get(0)[1];
+ }
+
+ if (visibleRow != -1) {
+ scrollRowToVisible(control, visibleRow);
}
}
});
diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/AddArrangementRuleAction.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/AddArrangementRuleAction.java
index f19b4513a628..fdde6eab9cbc 100644
--- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/AddArrangementRuleAction.java
+++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/AddArrangementRuleAction.java
@@ -19,7 +19,6 @@ import com.intellij.application.options.codeStyle.arrangement.match.ArrangementM
import com.intellij.application.options.codeStyle.arrangement.match.ArrangementMatchingRulesModel;
import com.intellij.application.options.codeStyle.arrangement.match.EmptyArrangementRuleComponent;
import com.intellij.icons.AllIcons;
-import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.application.ApplicationBundle;
import com.intellij.openapi.project.DumbAware;
@@ -31,7 +30,7 @@ import org.jetbrains.annotations.NotNull;
* @author Denis Zhdanov
* @since 8/24/12 1:54 PM
*/
-public class AddArrangementRuleAction extends AnAction implements DumbAware {
+public class AddArrangementRuleAction extends AbstractArrangementRuleAction implements DumbAware {
public AddArrangementRuleAction() {
getTemplatePresentation().setText(ApplicationBundle.message("arrangement.action.rule.add.text"));
@@ -64,6 +63,7 @@ public class AddArrangementRuleAction extends AnAction implements DumbAware {
}
showEditor(control, rowToEdit);
control.getSelectionModel().setSelectionInterval(rowToEdit, rowToEdit);
+ scrollRowToVisible(control, rowToEdit);
}
@NotNull
diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/EditArrangementRuleAction.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/EditArrangementRuleAction.java
index ffccce252176..14beaa21a1d9 100644
--- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/EditArrangementRuleAction.java
+++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/EditArrangementRuleAction.java
@@ -16,7 +16,6 @@
package com.intellij.application.options.codeStyle.arrangement.action;
import com.intellij.application.options.codeStyle.arrangement.match.ArrangementMatchingRulesControl;
-import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.Toggleable;
import com.intellij.openapi.application.ApplicationBundle;
@@ -27,7 +26,7 @@ import gnu.trove.TIntArrayList;
* @author Denis Zhdanov
* @since 10/29/12 11:01 AM
*/
-public class EditArrangementRuleAction extends AnAction implements DumbAware, Toggleable {
+public class EditArrangementRuleAction extends AbstractArrangementRuleAction implements DumbAware, Toggleable {
public EditArrangementRuleAction() {
getTemplatePresentation().setText(ApplicationBundle.message("arrangement.action.rule.edit.text"));
@@ -50,6 +49,8 @@ public class EditArrangementRuleAction extends AnAction implements DumbAware, To
if (rows.size() != 1) {
return;
}
- control.showEditor(rows.get(0));
+ final int row = rows.get(0);
+ control.showEditor(row);
+ scrollRowToVisible(control, row);
}
}
diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/RemoveArrangementRuleAction.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/RemoveArrangementRuleAction.java
index e1abf16f7eb1..5fbcdccd38e9 100644
--- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/RemoveArrangementRuleAction.java
+++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/RemoveArrangementRuleAction.java
@@ -39,7 +39,7 @@ public class RemoveArrangementRuleAction extends AnAction implements DumbAware {
@Override
public void update(AnActionEvent e) {
ArrangementMatchingRulesControl control = ArrangementMatchingRulesControl.KEY.getData(e.getDataContext());
- e.getPresentation().setEnabled(control != null && !control.getSelectedModelRows().isEmpty());
+ e.getPresentation().setEnabled(control != null && !control.getSelectedModelRows().isEmpty() && control.getEditingRow() == -1);
e.getPresentation().setIcon(SystemInfoRt.isMac ? AllIcons.ToolbarDecorator.Mac.Remove : AllIcons.ToolbarDecorator.Remove);
}
diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/group/ArrangementGroupingRulesControl.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/group/ArrangementGroupingRulesControl.java
index 581eb0aa96a2..a847aecd289f 100644
--- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/group/ArrangementGroupingRulesControl.java
+++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/group/ArrangementGroupingRulesControl.java
@@ -38,6 +38,7 @@ import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* @author Denis Zhdanov
@@ -95,17 +96,21 @@ public class ArrangementGroupingRulesControl extends JBTable {
model.removeRow(model.getRowCount() - 1);
}
- List<ArrangementSettingsToken> types = ContainerUtilRt.newArrayList(myComponents.keySet());
+ final Set<ArrangementSettingsToken> groupingTokens = ContainerUtilRt.newHashSet(myComponents.keySet());
+ for (ArrangementGroupingRule rule : rules) {
+ final ArrangementSettingsToken groupingType = rule.getGroupingType();
+ ArrangementGroupingComponent component = myComponents.get(groupingType);
+ component.setSelected(true);
+ component.setOrderType(rule.getOrderType());
+ model.addRow(new Object[]{component});
+ groupingTokens.remove(groupingType);
+ }
+
+ List<ArrangementSettingsToken> types = ContainerUtilRt.newArrayList(groupingTokens);
types = mySettingsManager.sort(types);
for (ArrangementSettingsToken type : types) {
model.addRow(new Object[]{myComponents.get(type)});
}
- for (ArrangementGroupingRule rule : rules) {
- ArrangementGroupingComponent component = myComponents.get(rule.getGroupingType());
- component.setSelected(true);
- ArrangementSettingsToken orderType = rule.getOrderType();
- component.setOrderType(orderType);
- }
}
@NotNull
diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/ArrangementMatchingRulesControl.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/ArrangementMatchingRulesControl.java
index 145ae1094e0b..a77e5cce28f0 100644
--- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/ArrangementMatchingRulesControl.java
+++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/ArrangementMatchingRulesControl.java
@@ -527,35 +527,52 @@ public class ArrangementMatchingRulesControl extends JBTable {
private class MyValidator {
@Nullable
private String validate(int index) {
- if (mySectionRuleManager == null || getModel().getSize() < index) {
+ if (getModel().getSize() < index) {
return null;
}
+ if (mySectionRuleManager != null) {
+ final ArrangementSectionRuleData data = extractSectionText(index);
+ if (data != null) {
+ return validateSectionRule(data, index);
+ }
+ }
+
+ final Object target = getModel().getElementAt(index);
+ if (target instanceof StdArrangementMatchRule) {
+ for (int i = 0; i < index; i++) {
+ final Object element = getModel().getElementAt(i);
+ if (element instanceof StdArrangementMatchRule && target.equals(element)) {
+ return ApplicationBundle.message("arrangement.settings.validation.duplicate.matching.rule");
+ }
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ private String validateSectionRule(@NotNull ArrangementSectionRuleData data, int index) {
int startSectionIndex = -1;
- final Set<String> rules = ContainerUtil.newHashSet();
+ final Set<String> sectionRules = ContainerUtil.newHashSet();
for (int i = 0; i < index; i++) {
final ArrangementSectionRuleData section = extractSectionText(i);
if (section != null) {
startSectionIndex = section.isSectionStart() ? i : -1;
if (StringUtil.isNotEmpty(section.getText())) {
- rules.add(section.getText());
+ sectionRules.add(section.getText());
}
}
}
+ if (StringUtil.isNotEmpty(data.getText()) && sectionRules.contains(data.getText())) {
+ return ApplicationBundle.message("arrangement.settings.validation.duplicate.section.text");
+ }
- final ArrangementSectionRuleData data = extractSectionText(index);
- if (data != null) {
- if (StringUtil.isNotEmpty(data.getText()) && rules.contains(data.getText())) {
- return ApplicationBundle.message("arrangement.settings.validation.duplicate.section.text");
+ if (!data.isSectionStart()) {
+ if (startSectionIndex == -1) {
+ return ApplicationBundle.message("arrangement.settings.validation.end.section.rule.without.start");
}
-
- if (!data.isSectionStart()) {
- if (startSectionIndex == -1) {
- return ApplicationBundle.message("arrangement.settings.validation.end.section.rule.without.start");
- }
- else if (startSectionIndex == index - 1) {
- return ApplicationBundle.message("arrangement.settings.validation.empty.section.rule");
- }
+ else if (startSectionIndex == index - 1) {
+ return ApplicationBundle.message("arrangement.settings.validation.empty.section.rule");
}
}
return null;
diff --git a/platform/lang-impl/src/com/intellij/application/options/editor/EditorTabsConfigurable.form b/platform/lang-impl/src/com/intellij/application/options/editor/EditorTabsConfigurable.form
index edb9fcdb9e18..4bc9490d0090 100644
--- a/platform/lang-impl/src/com/intellij/application/options/editor/EditorTabsConfigurable.form
+++ b/platform/lang-impl/src/com/intellij/application/options/editor/EditorTabsConfigurable.form
@@ -109,7 +109,7 @@
<properties/>
<border type="none"/>
<children>
- <component id="2479d" class="javax.swing.JLabel">
+ <component id="2479d" class="javax.swing.JLabel" binding="myTabTitleLimitLabel">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="4" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
diff --git a/platform/lang-impl/src/com/intellij/application/options/editor/EditorTabsConfigurable.java b/platform/lang-impl/src/com/intellij/application/options/editor/EditorTabsConfigurable.java
index 35a34085d035..93cde6a72f6d 100644
--- a/platform/lang-impl/src/com/intellij/application/options/editor/EditorTabsConfigurable.java
+++ b/platform/lang-impl/src/com/intellij/application/options/editor/EditorTabsConfigurable.java
@@ -46,6 +46,7 @@ public class EditorTabsConfigurable implements EditorOptionsProvider {
private JCheckBox myShowDirectoryInTabCheckBox;
private JRadioButton myActivateRightNeighbouringTabRadioButton;
private JTextField myTabTitleLimitField;
+ private JLabel myTabTitleLimitLabel;
public EditorTabsConfigurable() {
myEditorTabPlacement.setModel(new DefaultComboBoxModel(new Object[]{
@@ -69,21 +70,15 @@ public class EditorTabsConfigurable implements EditorOptionsProvider {
private void revalidateSingleRowCheckbox() {
final int i = ((Integer)myEditorTabPlacement.getSelectedItem()).intValue();
- if (i == UISettings.TABS_NONE) {
- myHideKnownExtensions.setEnabled(false);
- myScrollTabLayoutInEditorCheckBox.setEnabled(false);
- myCbModifiedTabsMarkedWithAsterisk.setEnabled(false);
- myShowTabsTooltipsCheckBox.setEnabled(false);
- myShowCloseButtonOnCheckBox.setEnabled(false);
- myShowDirectoryInTabCheckBox.setEnabled(false);
- } else {
- myHideKnownExtensions.setEnabled(true);
- myScrollTabLayoutInEditorCheckBox.setEnabled(true);
- myCbModifiedTabsMarkedWithAsterisk.setEnabled(true);
- myShowTabsTooltipsCheckBox.setEnabled(true);
- myShowCloseButtonOnCheckBox.setEnabled(true);
- myShowDirectoryInTabCheckBox.setEnabled(true);
- }
+ boolean none = i == UISettings.TABS_NONE;
+ myHideKnownExtensions.setEnabled(!none);
+ myScrollTabLayoutInEditorCheckBox.setEnabled(!none);
+ myCbModifiedTabsMarkedWithAsterisk.setEnabled(!none);
+ myShowTabsTooltipsCheckBox.setEnabled(!none);
+ myShowCloseButtonOnCheckBox.setEnabled(!none);
+ myShowDirectoryInTabCheckBox.setEnabled(!none);
+ myTabTitleLimitField.setEnabled(!none);
+ myTabTitleLimitLabel.setEnabled(!none);
if (SwingConstants.TOP == i) {
myScrollTabLayoutInEditorCheckBox.setEnabled(true);
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/actions/FormatChangedTextUtil.java b/platform/lang-impl/src/com/intellij/codeInsight/actions/FormatChangedTextUtil.java
index 3b51cc9ad976..dadafc7a7d84 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/actions/FormatChangedTextUtil.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/actions/FormatChangedTextUtil.java
@@ -250,7 +250,7 @@ public class FormatChangedTextUtil {
}
@NotNull
- public static List<TextRange> getChangedTextRanges(@NotNull Project project, @NotNull PsiFile file) {
+ public static List<TextRange> getChangedTextRanges(@NotNull Project project, @NotNull PsiFile file) throws FilesTooBigForDiffException {
Change change = ChangeListManager.getInstance(project).getChange(file.getVirtualFile());
if (change == null) {
return ContainerUtilRt.emptyList();
@@ -281,7 +281,10 @@ public class FormatChangedTextUtil {
}
@NotNull
- private static List<TextRange> calculateChangedTextRanges(@NotNull Project project, @NotNull PsiFile file, @NotNull String contentFromVcs) {
+ private static List<TextRange> calculateChangedTextRanges(@NotNull Project project,
+ @NotNull PsiFile file,
+ @NotNull String contentFromVcs) throws FilesTooBigForDiffException
+ {
Document documentFromVcs = ((EditorFactoryImpl)EditorFactory.getInstance()).createDocument(contentFromVcs, true, false);
Document document = PsiDocumentManager.getInstance(project).getDocument(file);
@@ -289,23 +292,16 @@ public class FormatChangedTextUtil {
return ContainerUtil.emptyList();
}
- try {
- List<Range> changedRanges;
-
- LineStatusTracker tracker = LineStatusTrackerManager.getInstance(project).getLineStatusTracker(document);
- if (tracker != null) {
- changedRanges = tracker.getRanges();
- }
- else {
- changedRanges = new RangesBuilder(document, documentFromVcs).getRanges();
- }
-
- return getChangedTextRanges(document, changedRanges);
+ List<Range> changedRanges;
+ LineStatusTracker tracker = LineStatusTrackerManager.getInstance(project).getLineStatusTracker(document);
+ if (tracker != null) {
+ changedRanges = tracker.getRanges();
}
- catch (FilesTooBigForDiffException e) {
- LOG.error("Error while calculating changed ranges for: " + file.getVirtualFile(), e);
- return ContainerUtil.emptyList();
+ else {
+ changedRanges = new RangesBuilder(document, documentFromVcs).getRanges();
}
+
+ return getChangedTextRanges(document, changedRanges);
}
@NotNull
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatCodeProcessor.java b/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatCodeProcessor.java
index ff032c22747b..270f2f92f3cf 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatCodeProcessor.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/actions/ReformatCodeProcessor.java
@@ -18,6 +18,10 @@ package com.intellij.codeInsight.actions;
import com.intellij.codeInsight.CodeInsightBundle;
import com.intellij.formatting.FormattingProgressTask;
+import com.intellij.notification.Notification;
+import com.intellij.notification.NotificationType;
+import com.intellij.openapi.application.ApplicationBundle;
+import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
@@ -27,6 +31,7 @@ import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.diff.FilesTooBigForDiffException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -90,6 +95,17 @@ public class ReformatCodeProcessor extends AbstractLayoutCodeProcessor {
CodeStyleManager.getInstance(myProject).reformatText(file, ranges);
return !FormattingProgressTask.FORMATTING_CANCELLED_FLAG.get();
}
+ catch (FilesTooBigForDiffException e) {
+ LOG.info("Error while calculating changed ranges for: " + file.getVirtualFile(), e);
+ if (!ApplicationManager.getApplication().isUnitTestMode()) {
+ Notification notification = new Notification(ApplicationBundle.message("reformat.changed.text.file.too.big.notification.groupId"),
+ ApplicationBundle.message("reformat.changed.text.file.too.big.notification.title"),
+ ApplicationBundle.message("reformat.changed.text.file.too.big.notification.text", file.getName()),
+ NotificationType.INFORMATION);
+ notification.notify(file.getProject());
+ }
+ return false;
+ }
catch (IncorrectOperationException e) {
LOG.error(e);
return false;
@@ -102,7 +118,7 @@ public class ReformatCodeProcessor extends AbstractLayoutCodeProcessor {
}
@NotNull
- private Collection<TextRange> getRangesToFormat(boolean processChangedTextOnly, PsiFile file) {
+ private Collection<TextRange> getRangesToFormat(boolean processChangedTextOnly, PsiFile file) throws FilesTooBigForDiffException {
if (processChangedTextOnly) {
return FormatChangedTextUtil.getChangedTextRanges(myProject, file);
}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java
index 3bdd05f58a40..dd506593d942 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CodeCompletionHandlerBase.java
@@ -65,9 +65,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
-import java.util.concurrent.atomic.AtomicReference;
public class CodeCompletionHandlerBase {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.completion.CodeCompletionHandlerBase");
@@ -306,16 +304,24 @@ public class CodeCompletionHandlerBase {
CompletionServiceImpl.setCompletionPhase(synchronous ? new CompletionPhase.Synchronous(indicator) : new CompletionPhase.BgCalculation(indicator));
- final AtomicReference<LookupElement[]> data = indicator.startCompletion(initContext);
+ indicator.startCompletion(initContext);
if (!synchronous) {
return;
}
if (freezeSemaphore.waitFor(2000)) {
- final LookupElement[] allItems = data.get();
- if (allItems != null && !indicator.isRunning() && !indicator.isCanceled()) { // the completion is really finished, now we may auto-insert or show lookup
- completionFinished(initContext.getStartOffset(), initContext.getSelectionEndOffset(), indicator, allItems, hasModifiers);
+ if (!indicator.isRunning() && !indicator.isCanceled()) { // the completion is really finished, now we may auto-insert or show lookup
+ try {
+ indicator.getLookup().refreshUi(true, false);
+ }
+ catch (Exception e) {
+ CompletionServiceImpl.setCompletionPhase(CompletionPhase.NoCompletion);
+ LOG.error(e);
+ return;
+ }
+
+ completionFinished(indicator, hasModifiers);
return;
}
}
@@ -324,9 +330,9 @@ public class CodeCompletionHandlerBase {
indicator.showLookup();
}
- private static void checkNotSync(CompletionProgressIndicator indicator, LookupElement[] allItems) {
+ private static void checkNotSync(CompletionProgressIndicator indicator, List<LookupElement> allItems) {
if (CompletionServiceImpl.isPhase(CompletionPhase.Synchronous.class)) {
- LOG.error("sync phase survived: " + Arrays.toString(allItems) + "; indicator=" + CompletionServiceImpl.getCompletionPhase().indicator + "; myIndicator=" + indicator);
+ LOG.error("sync phase survived: " + allItems + "; indicator=" + CompletionServiceImpl.getCompletionPhase().indicator + "; myIndicator=" + indicator);
CompletionServiceImpl.setCompletionPhase(CompletionPhase.NoCompletion);
}
}
@@ -345,17 +351,16 @@ public class CodeCompletionHandlerBase {
private static PsiElement findCompletionPositionLeaf(CompletionContext newContext, int offset, PsiFile fileCopy, PsiFile originalFile) {
final PsiElement insertedElement = newContext.file.findElementAt(offset);
CompletionAssertions.assertCompletionPositionPsiConsistent(newContext, offset, fileCopy, originalFile, insertedElement);
- assert insertedElement != null;
return insertedElement;
}
- private AutoCompletionDecision shouldAutoComplete(final CompletionProgressIndicator indicator, final LookupElement[] items) {
+ private AutoCompletionDecision shouldAutoComplete(final CompletionProgressIndicator indicator, List<LookupElement> items) {
if (!invokedExplicitly) {
return AutoCompletionDecision.SHOW_LOOKUP;
}
final CompletionParameters parameters = indicator.getParameters();
- final LookupElement item = items[0];
- if (items.length == 1) {
+ final LookupElement item = items.get(0);
+ if (items.size() == 1) {
final AutoCompletionPolicy policy = getAutocompletionPolicy(item);
if (policy == AutoCompletionPolicy.NEVER_AUTOCOMPLETE) return AutoCompletionDecision.SHOW_LOOKUP;
if (policy == AutoCompletionPolicy.ALWAYS_AUTOCOMPLETE) return AutoCompletionDecision.insertItem(item);
@@ -367,11 +372,11 @@ public class CodeCompletionHandlerBase {
if (isInsideIdentifier(indicator.getOffsetMap())) {
return AutoCompletionDecision.SHOW_LOOKUP;
}
- if (items.length == 1 && getAutocompletionPolicy(item) == AutoCompletionPolicy.GIVE_CHANCE_TO_OVERWRITE) {
+ if (items.size() == 1 && getAutocompletionPolicy(item) == AutoCompletionPolicy.GIVE_CHANCE_TO_OVERWRITE) {
return AutoCompletionDecision.insertItem(item);
}
- AutoCompletionContext context = new AutoCompletionContext(parameters, items, indicator.getOffsetMap(), indicator.getLookup());
+ AutoCompletionContext context = new AutoCompletionContext(parameters, items.toArray(new LookupElement[items.size()]), indicator.getOffsetMap(), indicator.getLookup());
for (final CompletionContributor contributor : CompletionContributor.forParameters(parameters)) {
final AutoCompletionDecision decision = contributor.handleAutoCompletionPossibility(context);
if (decision != null) {
@@ -401,12 +406,9 @@ public class CodeCompletionHandlerBase {
return offsetMap.getOffset(CompletionInitializationContext.IDENTIFIER_END_OFFSET) != offsetMap.getOffset(CompletionInitializationContext.SELECTION_END_OFFSET);
}
-
- protected void completionFinished(final int offset1,
- final int offset2,
- final CompletionProgressIndicator indicator,
- final LookupElement[] items, boolean hasModifiers) {
- if (items.length == 0) {
+ protected void completionFinished(final CompletionProgressIndicator indicator, boolean hasModifiers) {
+ final List<LookupElement> items = indicator.getLookup().getItems();
+ if (items.isEmpty()) {
LookupManager.getInstance(indicator.getProject()).hideActiveLookup();
Caret nextCaret = getNextCaretToProcess(indicator.getEditor());
@@ -424,7 +426,6 @@ public class CodeCompletionHandlerBase {
LOG.assertTrue(!indicator.isCanceled(), "canceled");
try {
- indicator.getLookup().refreshUi(true, false);
final AutoCompletionDecision decision = shouldAutoComplete(indicator, items);
if (decision == AutoCompletionDecision.SHOW_LOOKUP) {
CompletionServiceImpl.setCompletionPhase(new CompletionPhase.ItemsCalculated(indicator));
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java
index 8ca94d80463c..4f02d6bc5e54 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/completion/CompletionProgressIndicator.java
@@ -81,7 +81,6 @@ import java.beans.PropertyChangeListener;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.atomic.AtomicReference;
/**
* @author peter
@@ -742,7 +741,7 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
return false;
}
- AtomicReference<LookupElement[]> startCompletion(final CompletionInitializationContext initContext) {
+ void startCompletion(final CompletionInitializationContext initContext) {
boolean sync = ApplicationManager.getApplication().isUnitTestMode() && !CompletionAutoPopupHandler.ourTestingAutopopup;
final CompletionThreading strategy = sync ? new SyncCompletion() : new AsyncCompletion();
@@ -754,12 +753,11 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
});
final WeighingDelegate weigher = strategy.delegateWeighing(this);
- final AtomicReference<LookupElement[]> data = new AtomicReference<LookupElement[]>(null);
class CalculateItems implements Runnable {
@Override
public void run() {
try {
- data.set(calculateItems(initContext, weigher));
+ calculateItems(initContext, weigher);
}
catch (ProcessCanceledException ignore) {
cancel(); // some contributor may just throw PCE; if indicator is not canceled everything will hang
@@ -771,7 +769,6 @@ public class CompletionProgressIndicator extends ProgressIndicatorBase implement
}
}
strategy.startThread(this, new CalculateItems());
- return data;
}
private LookupElement[] calculateItems(CompletionInitializationContext initContext, WeighingDelegate weigher) {
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java
index 4ac5e686c5bc..0d02b32baed4 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/DaemonCodeAnalyzerImpl.java
@@ -58,6 +58,7 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.openapi.vfs.newvfs.RefreshQueueImpl;
import com.intellij.packageDependencies.DependencyValidationManager;
+import com.intellij.psi.FileViewProvider;
import com.intellij.psi.PsiCompiledElement;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
@@ -184,8 +185,9 @@ public class DaemonCodeAnalyzerImpl extends DaemonCodeAnalyzerEx implements JDOM
@Override
public void cleanFileLevelHighlights(@NotNull Project project, final int group, PsiFile psiFile) {
- if (psiFile == null || !psiFile.getViewProvider().isPhysical()) return;
- VirtualFile vFile = psiFile.getViewProvider().getVirtualFile();
+ if (psiFile == null) return;
+ FileViewProvider provider = psiFile.getViewProvider();
+ VirtualFile vFile = provider.getVirtualFile();
final FileEditorManager manager = FileEditorManager.getInstance(project);
for (FileEditor fileEditor : manager.getEditors(vFile)) {
final List<HighlightInfo> infos = fileEditor.getUserData(FILE_LEVEL_HIGHLIGHTS);
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PassExecutorService.java b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PassExecutorService.java
index 44df90322011..24c3d8b4a6fb 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PassExecutorService.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/daemon/impl/PassExecutorService.java
@@ -34,6 +34,7 @@ import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.TextEditor;
+import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
@@ -95,6 +96,12 @@ public class PassExecutorService implements Disposable {
catch (ProcessCanceledException ignored) {
}
+ catch (Error e) {
+ throw e;
+ }
+ catch (RuntimeException e) {
+ throw e;
+ }
catch (Throwable throwable) {
LOG.error(throwable);
}
@@ -118,6 +125,10 @@ public class PassExecutorService implements Disposable {
LOG.assertTrue(!(editor instanceof EditorWindow));
document = editor.getDocument();
}
+ else {
+ VirtualFile virtualFile = ((FileEditorManagerEx)FileEditorManager.getInstance(myProject)).getFile(fileEditor);
+ document = virtualFile == null ? null : FileDocumentManager.getInstance().getDocument(virtualFile);
+ }
int prevId = 0;
for (final HighlightingPass pass : passes) {
@@ -534,7 +545,7 @@ public class PassExecutorService implements Disposable {
return result;
}
- private void sortById(@NotNull List<TextEditorHighlightingPass> result) {
+ private static void sortById(@NotNull List<TextEditorHighlightingPass> result) {
ContainerUtil.quickSort(result, new Comparator<TextEditorHighlightingPass>() {
@Override
public int compare(TextEditorHighlightingPass o1, TextEditorHighlightingPass o2) {
@@ -548,7 +559,7 @@ public class PassExecutorService implements Disposable {
return ConcurrencyUtil.cacheOrGet(threads, Thread.currentThread(), threads.size());
}
- public static void log(ProgressIndicator progressIndicator, TextEditorHighlightingPass pass, @NonNls Object... info) {
+ public static void log(ProgressIndicator progressIndicator, TextEditorHighlightingPass pass, @NonNls @NotNull Object... info) {
if (LOG.isDebugEnabled()) {
CharSequence docText = pass == null ? "" : StringUtil.first(pass.getDocument().getCharsSequence(), 10, true);
synchronized (PassExecutorService.class) {
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java
index 50f69088033b..10515ba07bef 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationComponent.java
@@ -106,7 +106,10 @@ public class DocumentationComponent extends JPanel implements Disposable, DataPr
@Override
public Image get(Object key) {
PsiElement element = getElement();
- return element == null ? null : myManager.getElementImage(element, ((URL)key).toExternalForm());
+ if (element == null) return null;
+ URL url = (URL)key;
+ Image inMemory = myManager.getElementImage(element, url.toExternalForm());
+ return inMemory != null ? inMemory : Toolkit.getDefaultToolkit().createImage(url);
}
};
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java
index 63484f890225..319ce54196da 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/DocumentationManager.java
@@ -378,6 +378,8 @@ public class DocumentationManager extends DockablePopupManager<DocumentationComp
final PsiElement originalElement,
@Nullable final Runnable closeCallback) {
Project project = getProject(element);
+ if (!project.isOpen()) return;
+
storeOriginalElement(project, originalElement, element);
myPreviouslyFocused = WindowManagerEx.getInstanceEx().getFocusedComponent(project);
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/documentation/QuickDocUtil.java b/platform/lang-impl/src/com/intellij/codeInsight/documentation/QuickDocUtil.java
index 064bd020183b..18b28e3409f3 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/documentation/QuickDocUtil.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/documentation/QuickDocUtil.java
@@ -26,9 +26,9 @@ import com.intellij.psi.PsiElement;
import com.intellij.ui.content.Content;
import com.intellij.ui.popup.AbstractPopup;
import com.intellij.util.Producer;
+import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
-
-import javax.swing.*;
+import org.jetbrains.annotations.Nullable;
/**
* @author gregsh
@@ -40,33 +40,41 @@ public class QuickDocUtil {
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
@Override
public void run() {
- final String documentation = docProducer.produce();
- if (StringUtil.isEmpty(documentation)) return;
- // modal dialogs with fragment editors fix: can't guess proper modality state here
- //noinspection SSBasedInspection
- SwingUtilities.invokeLater(new Runnable() {
- @Override
- public void run() {
- DocumentationManager documentationManager = DocumentationManager.getInstance(project);
- DocumentationComponent component;
- JBPopup hint = documentationManager.getDocInfoHint();
- if (hint != null) {
- component = (DocumentationComponent)((AbstractPopup)hint).getComponent();
- }
- else if (documentationManager.hasActiveDockedDocWindow()) {
- ToolWindow toolWindow = ToolWindowManager.getInstance(project).getToolWindow(ToolWindowId.DOCUMENTATION);
- Content selectedContent = toolWindow == null ? null : toolWindow.getContentManager().getSelectedContent();
- component = selectedContent == null ? null : (DocumentationComponent)selectedContent.getComponent();
- }
- else {
- component = null;
- }
- if (component != null) {
- component.replaceText(documentation, element);
- }
- }
- });
+ updateQuickDoc(project, element, docProducer.produce());
}
});
}
+
+ public static void updateQuickDoc(@NotNull final Project project, @NotNull final PsiElement element, @Nullable final String documentation) {
+ if (StringUtil.isEmpty(documentation)) return;
+ // modal dialogs with fragment editors fix: can't guess proper modality state here
+ UIUtil.invokeLaterIfNeeded(new Runnable() {
+ @Override
+ public void run() {
+ DocumentationComponent component = getActiveDocComponent(project);
+ if (component != null) {
+ component.replaceText(documentation, element);
+ }
+ }
+ });
+ }
+
+ @Nullable
+ public static DocumentationComponent getActiveDocComponent(@NotNull Project project) {
+ DocumentationManager documentationManager = DocumentationManager.getInstance(project);
+ DocumentationComponent component;
+ JBPopup hint = documentationManager.getDocInfoHint();
+ if (hint != null) {
+ component = (DocumentationComponent)((AbstractPopup)hint).getComponent();
+ }
+ else if (documentationManager.hasActiveDockedDocWindow()) {
+ ToolWindow toolWindow = ToolWindowManager.getInstance(project).getToolWindow(ToolWindowId.DOCUMENTATION);
+ Content selectedContent = toolWindow == null ? null : toolWindow.getContentManager().getSelectedContent();
+ component = selectedContent == null ? null : (DocumentationComponent)selectedContent.getComponent();
+ }
+ else {
+ component = null;
+ }
+ return component;
+ }
}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/hint/actions/ShowImplementationsAction.java b/platform/lang-impl/src/com/intellij/codeInsight/hint/actions/ShowImplementationsAction.java
index afd7b230621c..376c24289617 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/hint/actions/ShowImplementationsAction.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/hint/actions/ShowImplementationsAction.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -367,12 +367,17 @@ public class ShowImplementationsAction extends AnAction implements PopupAction {
}
private static PsiElement[] filterElements(final PsiElement[] targetElements) {
- Set<PsiElement> unique = new LinkedHashSet<PsiElement>(Arrays.asList(targetElements));
- for (PsiElement elt : targetElements) {
- final PsiFile containingFile = elt.getContainingFile();
- LOG.assertTrue(containingFile != null, elt);
- PsiFile psiFile = containingFile.getOriginalFile();
- if (psiFile.getVirtualFile() == null) unique.remove(elt);
+ final Set<PsiElement> unique = new LinkedHashSet<PsiElement>(Arrays.asList(targetElements));
+ for (final PsiElement elt : targetElements) {
+ ApplicationManager.getApplication().runReadAction(new Runnable() {
+ @Override
+ public void run() {
+ final PsiFile containingFile = elt.getContainingFile();
+ LOG.assertTrue(containingFile != null, elt);
+ PsiFile psiFile = containingFile.getOriginalFile();
+ if (psiFile.getVirtualFile() == null) unique.remove(elt);
+ }
+ });
}
// special case for Python (PY-237)
// if the definition is the tree parent of the target element, filter out the target element
@@ -392,9 +397,9 @@ public class ShowImplementationsAction extends AnAction implements PopupAction {
}
private static class ImplementationsUpdaterTask extends BackgroundUpdaterTask<ImplementationViewComponent> {
- private String myCaption;
- private Editor myEditor;
- private PsiElement myElement;
+ private final String myCaption;
+ private final Editor myEditor;
+ private final PsiElement myElement;
private final boolean myIncludeSelf;
private PsiElement[] myElements;
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/QuickEditHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/QuickEditHandler.java
index 517f23c5a198..b236e1061315 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/QuickEditHandler.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/intention/impl/QuickEditHandler.java
@@ -72,7 +72,6 @@ import org.jetbrains.annotations.TestOnly;
import javax.swing.*;
import java.awt.*;
-import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -97,8 +96,7 @@ public class QuickEditHandler extends DocumentAdapter implements Disposable {
@Nullable
private final PsiFile myInjectedFile;
- private final List<Trinity<RangeMarker, RangeMarker, SmartPsiElementPointer>> myMarkers =
- new LinkedList<Trinity<RangeMarker, RangeMarker, SmartPsiElementPointer>>();
+ private final List<Trinity<RangeMarker, RangeMarker, SmartPsiElementPointer>> myMarkers = ContainerUtil.newLinkedList();
@Nullable
private final RangeMarker myAltFullRange;
@@ -199,7 +197,16 @@ public class QuickEditHandler extends DocumentAdapter implements Disposable {
}
public boolean isValid() {
- return myNewVirtualFile.isValid() && (myAltFullRange == null && myInjectedFile.isValid() || myAltFullRange.isValid());
+ boolean valid = myNewVirtualFile.isValid() && (myAltFullRange == null && myInjectedFile.isValid() || myAltFullRange.isValid());
+ if (valid) {
+ for (Trinity<RangeMarker, RangeMarker, SmartPsiElementPointer> t : myMarkers) {
+ if (!t.first.isValid() || !t.second.isValid() || t.third.getElement() == null) {
+ valid = false;
+ break;
+ }
+ }
+ }
+ return valid;
}
public void navigate(int injectedOffset) {
@@ -285,6 +292,7 @@ public class QuickEditHandler extends DocumentAdapter implements Disposable {
}
else if (e.getDocument() == myNewDocument) {
commitToOriginal();
+ if (!isValid()) closeEditor();
}
else if (e.getDocument() == myOrigDocument) {
if (myCommittingToOriginal || myAltFullRange != null && myAltFullRange.isValid()) return;
@@ -359,7 +367,6 @@ public class QuickEditHandler extends DocumentAdapter implements Disposable {
private void commitToOriginal() {
- if (!isValid()) return;
VirtualFile origVirtualFile = PsiUtilCore.getVirtualFile(myNewFile.getContext());
myCommittingToOriginal = true;
try {
@@ -401,7 +408,7 @@ public class QuickEditHandler extends DocumentAdapter implements Disposable {
ProperTextRange insideHost = null;
StringBuilder sb = new StringBuilder();
for (Trinity<RangeMarker, RangeMarker, SmartPsiElementPointer> entry : map.get(host)) {
- RangeMarker origMarker = entry.first;
+ RangeMarker origMarker = entry.first; // check for validity?
int hostOffset = host.getTextRange().getStartOffset();
ProperTextRange localInsideHost = new ProperTextRange(origMarker.getStartOffset() - hostOffset, origMarker.getEndOffset() - hostOffset);
RangeMarker rangeMarker = entry.second;
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/EditVariableDialog.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/EditVariableDialog.java
index e32fab35508b..bab6ade7b935 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/EditVariableDialog.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/EditVariableDialog.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2011 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,6 +26,7 @@ import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.help.HelpManager;
+import com.intellij.openapi.ui.ComboBox;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.ui.ToolbarDecorator;
import com.intellij.ui.table.JBTable;
@@ -107,11 +108,11 @@ class EditVariableDialog extends DialogWrapper {
myTable.getSelectionModel().setSelectionInterval(0, 0);
}
- JComboBox comboField = new JComboBox();
+ ComboBox comboField = new ComboBox();
Macro[] macros = MacroFactory.getMacros();
Arrays.sort(macros, new Comparator<Macro> () {
@Override
- public int compare(Macro m1, Macro m2) {
+ public int compare(@NotNull Macro m1, @NotNull Macro m2) {
return m1.getPresentableName().compareTo(m2.getPresentableName());
}
});
@@ -231,11 +232,13 @@ class EditVariableDialog extends DialogWrapper {
}
}
+ @NotNull
@Override
public String getColumnName(int column) {
return myNames[column];
}
+ @NotNull
@Override
public Class getColumnClass(int c) {
if (c <= 2) {
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateListPanel.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateListPanel.java
index 9a7a724e2d5d..1c0b72a5a454 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateListPanel.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateListPanel.java
@@ -19,6 +19,7 @@ package com.intellij.codeInsight.template.impl;
import com.intellij.application.options.ExportSchemeAction;
import com.intellij.application.options.SchemesToImportPopup;
import com.intellij.codeInsight.CodeInsightBundle;
+import com.intellij.icons.AllIcons;
import com.intellij.ide.DataManager;
import com.intellij.ide.dnd.*;
import com.intellij.ide.dnd.aware.DnDAwareTree;
@@ -690,6 +691,17 @@ public class TemplateListPanel extends JPanel implements Disposable {
public void updateButton(AnActionEvent e) {
e.getPresentation().setEnabled(getTemplate(getSingleSelectedIndex()) != null);
}
+ }).addExtraAction(new AnActionButton("Restore deleted defaults", AllIcons.General.TodoDefault) {
+ @Override
+ public void actionPerformed(@NotNull AnActionEvent e) {
+ TemplateSettings.getInstance().reset();
+ reset();
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return super.isEnabled() && !TemplateSettings.getInstance().getDeletedTemplates().isEmpty();
+ }
});
if (getSchemesManager().isExportAvailable()) {
decorator.addExtraAction(new AnActionButton("Share...", PlatformIcons.EXPORT_ICON) {
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateSettings.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateSettings.java
index abf28256aaef..cdefbe83a252 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateSettings.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateSettings.java
@@ -158,6 +158,10 @@ public class TemplateSettings implements PersistentStateComponent<Element>, Expo
this.key = key;
}
+ @Override
+ public String toString() {
+ return getKey()+"@" + getGroupName();
+ }
}
private TemplateKey myLastSelectedTemplate;
@@ -185,7 +189,7 @@ public class TemplateSettings implements PersistentStateComponent<Element>, Expo
}
@Override
- public Document writeScheme(@NotNull final TemplateGroup template) throws WriteExternalException {
+ public Element writeScheme(@NotNull final TemplateGroup template) throws WriteExternalException {
Element templateSetElement = new Element(TEMPLATE_SET);
templateSetElement.setAttribute(GROUP, template.getName());
@@ -195,7 +199,7 @@ public class TemplateSettings implements PersistentStateComponent<Element>, Expo
}
}
- return new Document(templateSetElement);
+ return templateSetElement;
}
@Override
@@ -750,4 +754,9 @@ public class TemplateSettings implements PersistentStateComponent<Element>, Expo
public List<TemplateKey> getDeletedTemplates() {
return myDeletedTemplates;
}
+
+ public void reset() {
+ myDeletedTemplates.clear();
+ loadDefaultLiveTemplates();
+ }
}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java
index 0c838cd05ec5..2e620c2379c9 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/template/impl/TemplateState.java
@@ -723,7 +723,10 @@ public class TemplateState implements Disposable {
ExpressionContext context = createExpressionContext(start);
Result result = isQuick ? expressionNode.calculateQuickResult(context) : expressionNode.calculateResult(context);
- if ((result == null || result.equalsToText("", element)) && defaultValue != null) {
+ if (isQuick && isEmptyResult(result, element) && !oldValue.isEmpty()) {
+ return;
+ }
+ if (isEmptyResult(result, element) && defaultValue != null) {
result = defaultValue.calculateResult(context);
}
if (element != null) {
@@ -743,6 +746,10 @@ public class TemplateState implements Disposable {
}
}
+ private static boolean isEmptyResult(Result result, PsiElement context) {
+ return result == null || result.equalsToText("", context);
+ }
+
private void replaceString(String newValue, int start, int end, int segmentNumber) {
String oldText = myDocument.getCharsSequence().subSequence(start, end).toString();
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/ElseExpressionPostfixTemplateBase.java b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/ElseExpressionPostfixTemplateBase.java
index 1e9c58488f33..4c810dcf4ff3 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/ElseExpressionPostfixTemplateBase.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/ElseExpressionPostfixTemplateBase.java
@@ -16,6 +16,7 @@
package com.intellij.codeInsight.template.postfix.templates;
import com.intellij.openapi.util.Condition;
+import com.intellij.openapi.util.Conditions;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
@@ -28,7 +29,7 @@ public abstract class ElseExpressionPostfixTemplateBase extends SurroundPostfixT
@SuppressWarnings("unchecked")
protected ElseExpressionPostfixTemplateBase(@NotNull PostfixTemplatePsiInfo psiInfo) {
- super("else", "if (!expr)", psiInfo, Condition.TRUE);
+ super("else", "if (!expr)", psiInfo, Conditions.<PsiElement>alwaysTrue());
}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/IfPostfixTemplateBase.java b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/IfPostfixTemplateBase.java
index 90a21a269fed..b7e402f31f66 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/IfPostfixTemplateBase.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/IfPostfixTemplateBase.java
@@ -17,6 +17,7 @@ package com.intellij.codeInsight.template.postfix.templates;
import com.intellij.openapi.util.Condition;
+import com.intellij.openapi.util.Conditions;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
@@ -29,6 +30,6 @@ public abstract class IfPostfixTemplateBase extends SurroundPostfixTemplateBase
@SuppressWarnings("unchecked")
protected IfPostfixTemplateBase(@NotNull PostfixTemplatePsiInfo psiInfo) {
- super("if", "if (expr)", psiInfo, Condition.TRUE);
+ super("if", "if (expr)", psiInfo, Conditions.<PsiElement>alwaysTrue());
}
}
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/PostfixLiveTemplate.java b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/PostfixLiveTemplate.java
index 0190fadbcf02..61544faf2c81 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/PostfixLiveTemplate.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/PostfixLiveTemplate.java
@@ -32,6 +32,7 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.util.Condition;
+import com.intellij.openapi.util.Conditions;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDocumentManager;
@@ -266,15 +267,13 @@ public class PostfixLiveTemplate extends CustomLiveTemplateBase {
PsiFile copyFile = copyFile(file, fileContentWithoutKey);
Document copyDocument = copyFile.getViewProvider().getDocument();
if (copyDocument == null) {
- //noinspection unchecked
- return Condition.FALSE;
+ return Conditions.alwaysFalse();
}
copyFile = provider.preCheck(copyFile, editor, newOffset);
copyDocument = copyFile.getViewProvider().getDocument();
if (copyDocument == null) {
- //noinspection unchecked
- return Condition.FALSE;
+ return Conditions.alwaysFalse();
}
final PsiElement context = CustomTemplateCallback.getContext(copyFile, positiveOffset(newOffset));
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/StatementWrapPostfixTemplate.java b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/StatementWrapPostfixTemplate.java
index 5b5c3624f33b..33b8ba541f66 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/StatementWrapPostfixTemplate.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/StatementWrapPostfixTemplate.java
@@ -17,6 +17,7 @@ package com.intellij.codeInsight.template.postfix.templates;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.util.Condition;
+import com.intellij.openapi.util.Conditions;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
@@ -28,7 +29,7 @@ public abstract class StatementWrapPostfixTemplate extends PostfixTemplateWithEx
protected StatementWrapPostfixTemplate(@NotNull String name,
@NotNull String descr,
@NotNull PostfixTemplatePsiInfo psiInfo) {
- super(name, descr, psiInfo, Condition.TRUE);
+ super(name, descr, psiInfo, Conditions.<PsiElement>alwaysTrue());
}
protected StatementWrapPostfixTemplate(@NotNull String name,
diff --git a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/SurroundPostfixTemplateBase.java b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/SurroundPostfixTemplateBase.java
index 29ea4d39ac64..09ca27a3f948 100644
--- a/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/SurroundPostfixTemplateBase.java
+++ b/platform/lang-impl/src/com/intellij/codeInsight/template/postfix/templates/SurroundPostfixTemplateBase.java
@@ -18,6 +18,7 @@ package com.intellij.codeInsight.template.postfix.templates;
import com.intellij.lang.surroundWith.Surrounder;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.util.Condition;
+import com.intellij.openapi.util.Conditions;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
@@ -35,7 +36,7 @@ public abstract class SurroundPostfixTemplateBase extends StatementWrapPostfixTe
protected SurroundPostfixTemplateBase(@NotNull String name,
@NotNull String descr,
@NotNull PostfixTemplatePsiInfo psiInfo) {
- super(name, descr, psiInfo, Condition.TRUE);
+ super(name, descr, psiInfo, Conditions.<PsiElement>alwaysTrue());
}
diff --git a/platform/lang-impl/src/com/intellij/codeInspection/actions/GotoInspectionModel.java b/platform/lang-impl/src/com/intellij/codeInspection/actions/GotoInspectionModel.java
index 4c6efc2b7897..ddcce12a9236 100644
--- a/platform/lang-impl/src/com/intellij/codeInspection/actions/GotoInspectionModel.java
+++ b/platform/lang-impl/src/com/intellij/codeInspection/actions/GotoInspectionModel.java
@@ -22,13 +22,11 @@ import com.intellij.codeInspection.ex.ScopeToolState;
import com.intellij.ide.IdeBundle;
import com.intellij.ide.util.gotoByName.SimpleChooseByNameModel;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.text.StringUtil;
import com.intellij.profile.codeInspection.InspectionProfileManager;
-import com.intellij.util.ArrayUtil;
-import com.intellij.util.containers.MultiMap;
import javax.swing.*;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@@ -36,11 +34,10 @@ import java.util.Set;
* @author Konstantin Bulenkov
*/
public class GotoInspectionModel extends SimpleChooseByNameModel {
- private final MultiMap<String, InspectionToolWrapper> myToolNames = MultiMap.createSmartList();
- private final Map<String, Set<InspectionToolWrapper>> myGroupNames = new HashMap<String, Set<InspectionToolWrapper>>();
- private final Map<String, InspectionToolWrapper> myToolShortNames = new HashMap<String, InspectionToolWrapper>();
+ private static final InspectionToolWrapper[] EMPTY_WRAPPERS_ARRAY = new InspectionToolWrapper[0];
+ private final Map<String, InspectionToolWrapper> myToolNames = new HashMap<String, InspectionToolWrapper>();
private final String[] myNames;
- private final ListCellRenderer myListCellRenderer = new InspectionListCellRenderer();
+ private final InspectionListCellRenderer myListCellRenderer = new InspectionListCellRenderer();
public GotoInspectionModel(Project project) {
@@ -48,28 +45,14 @@ public class GotoInspectionModel extends SimpleChooseByNameModel {
final InspectionProfileImpl rootProfile = (InspectionProfileImpl)InspectionProfileManager.getInstance().getRootProfile();
for (ScopeToolState state : rootProfile.getAllTools(project)) {
InspectionToolWrapper tool = state.getTool();
- InspectionToolWrapper workingTool = tool;
- if (tool instanceof LocalInspectionToolWrapper) {
- workingTool = LocalInspectionToolWrapper.findTool2RunInBatch(project, null, tool.getShortName());
- if (workingTool == null) {
- continue;
- }
+ if (tool instanceof LocalInspectionToolWrapper && ((LocalInspectionToolWrapper)tool).isUnfair()) {
+ continue;
}
- myToolNames.putValue(tool.getDisplayName(), workingTool);
- final String groupName = tool.getGroupDisplayName();
- Set<InspectionToolWrapper> toolsInGroup = myGroupNames.get(groupName);
- if (toolsInGroup == null) {
- toolsInGroup = new HashSet<InspectionToolWrapper>();
- myGroupNames.put(groupName, toolsInGroup);
- }
- toolsInGroup.add(workingTool);
- myToolShortNames.put(tool.getShortName(), workingTool);
+ final String name = tool.getDisplayName() + " " + StringUtil.join(tool.getGroupPath(), " ");
+ myToolNames.put(name, tool);
}
-
- final Set<String> nameIds = new HashSet<String>();
- nameIds.addAll(myToolNames.keySet());
- nameIds.addAll(myGroupNames.keySet());
- myNames = ArrayUtil.toStringArray(nameIds);
+ final Set<String> strings = myToolNames.keySet();
+ myNames = strings.toArray(new String[strings.size()]);
}
@Override
@@ -83,25 +66,19 @@ public class GotoInspectionModel extends SimpleChooseByNameModel {
}
@Override
- public Object[] getElementsByName(final String id, final String pattern) {
- final Set<InspectionToolWrapper> result = new HashSet<InspectionToolWrapper>();
- result.addAll(myToolNames.get(id));
- InspectionToolWrapper e = myToolShortNames.get(id);
- if (e != null) {
- result.add(e);
- }
- final Set<InspectionToolWrapper> entries = myGroupNames.get(id);
- if (entries != null) {
- result.addAll(entries);
+ public Object[] getElementsByName(final String name, final String pattern) {
+ final InspectionToolWrapper tool = myToolNames.get(name);
+ if (tool == null) {
+ return EMPTY_WRAPPERS_ARRAY;
}
- return result.toArray(new InspectionToolWrapper[result.size()]);
+ return new InspectionToolWrapper[] {tool};
}
@Override
public String getElementName(final Object element) {
if (element instanceof InspectionToolWrapper) {
InspectionToolWrapper entry = (InspectionToolWrapper)element;
- return entry.getDisplayName() + " " + entry.getGroupDisplayName();
+ return entry.getDisplayName() + " " + StringUtil.join(entry.getGroupPath(), " ");
}
return null;
}
diff --git a/platform/lang-impl/src/com/intellij/codeInspection/actions/InspectionListCellRenderer.java b/platform/lang-impl/src/com/intellij/codeInspection/actions/InspectionListCellRenderer.java
index 8608a2d13142..c7386b2ffcb5 100644
--- a/platform/lang-impl/src/com/intellij/codeInspection/actions/InspectionListCellRenderer.java
+++ b/platform/lang-impl/src/com/intellij/codeInspection/actions/InspectionListCellRenderer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,6 +20,10 @@ import com.intellij.ide.util.gotoByName.ChooseByNameBase;
import com.intellij.lang.Language;
import com.intellij.openapi.fileTypes.LanguageFileType;
import com.intellij.openapi.fileTypes.UnknownFileType;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.openapi.util.registry.Registry;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.codeStyle.MinusculeMatcher;
import com.intellij.ui.JBColor;
import com.intellij.ui.SimpleColoredComponent;
import com.intellij.ui.SimpleTextAttributes;
@@ -31,6 +35,8 @@ import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.*;
+import java.util.ArrayList;
+import java.util.List;
/**
* @author Konstantin Bulenkov
@@ -38,24 +44,31 @@ import java.awt.*;
@SuppressWarnings({"GtkPreferredJComboBoxRenderer"})
public class InspectionListCellRenderer extends DefaultListCellRenderer implements MatcherHolder {
private Matcher myMatcher;
- private final SimpleTextAttributes SELECTED;
- private final SimpleTextAttributes PLAIN;
+ private final SimpleTextAttributes mySelected;
+ private final SimpleTextAttributes myPlain;
+ private final SimpleTextAttributes myHighlighted;
public InspectionListCellRenderer() {
- SELECTED = new SimpleTextAttributes(UIUtil.getListSelectionBackground(),
- UIUtil.getListSelectionForeground(),
- JBColor.RED,
- SimpleTextAttributes.STYLE_PLAIN);
- PLAIN = new SimpleTextAttributes(UIUtil.getListBackground(),
- UIUtil.getListForeground(),
- JBColor.RED,
- SimpleTextAttributes.STYLE_PLAIN);
+ mySelected = new SimpleTextAttributes(UIUtil.getListSelectionBackground(),
+ UIUtil.getListSelectionForeground(),
+ JBColor.RED,
+ SimpleTextAttributes.STYLE_PLAIN);
+ myPlain = new SimpleTextAttributes(UIUtil.getListBackground(),
+ UIUtil.getListForeground(),
+ JBColor.RED,
+ SimpleTextAttributes.STYLE_PLAIN);
+ myHighlighted = new SimpleTextAttributes(UIUtil.getListBackground(),
+ UIUtil.getListForeground(),
+ null,
+ SimpleTextAttributes.STYLE_SEARCH_MATCH);
}
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean sel, boolean focus) {
- final JPanel panel = new JPanel(new BorderLayout());
+ final BorderLayout layout = new BorderLayout();
+ layout.setHgap(5);
+ final JPanel panel = new JPanel(layout);
panel.setOpaque(true);
final Color bg = sel ? UIUtil.getListSelectionBackground() : UIUtil.getListBackground();
@@ -63,15 +76,37 @@ public class InspectionListCellRenderer extends DefaultListCellRenderer implemen
panel.setBackground(bg);
panel.setForeground(fg);
- SimpleTextAttributes attr = sel ? SELECTED : PLAIN;
if (value instanceof InspectionToolWrapper) {
final InspectionToolWrapper toolWrapper = (InspectionToolWrapper)value;
+ final String inspectionName = " " + toolWrapper.getDisplayName();
+ final String groupName = StringUtil.join(toolWrapper.getGroupPath(), " | ");
+ final String matchingText = inspectionName + "|" + groupName;
+ List<TextRange> fragments = ((MinusculeMatcher)myMatcher).matchingFragments(matchingText);
+ List<TextRange> adjustedFragments = new ArrayList<TextRange>();
+ if (fragments != null) {
+ adjustedFragments.addAll(fragments);
+ }
+ final int splitPoint = adjustRanges(adjustedFragments, inspectionName.length() + 1);
final SimpleColoredComponent c = new SimpleColoredComponent();
- SpeedSearchUtil.appendColoredFragmentForMatcher(" " + toolWrapper.getDisplayName(), c, attr, myMatcher, bg, sel);
+ final boolean matchHighlighting = Registry.is("ide.highlight.match.in.selected.only") && !sel;
+ if (matchHighlighting) {
+ c.append(inspectionName, myPlain);
+ }
+ else {
+ final List<TextRange> ranges = adjustedFragments.subList(0, splitPoint);
+ SpeedSearchUtil.appendColoredFragments(c, inspectionName, ranges, sel ? mySelected : myPlain, myHighlighted);
+ }
panel.add(c, BorderLayout.WEST);
final SimpleColoredComponent group = new SimpleColoredComponent();
- SpeedSearchUtil.appendColoredFragmentForMatcher(toolWrapper.getGroupDisplayName() + " ", group, attr, myMatcher, bg, sel);
+ if (matchHighlighting) {
+ group.append(groupName, SimpleTextAttributes.GRAYED_ATTRIBUTES);
+ }
+ else {
+ final SimpleTextAttributes attributes = sel ? mySelected : SimpleTextAttributes.GRAYED_ATTRIBUTES;
+ final List<TextRange> ranges = adjustedFragments.subList(splitPoint, adjustedFragments.size());
+ SpeedSearchUtil.appendColoredFragments(group, groupName, ranges, attributes, myHighlighted);
+ }
final JPanel right = new JPanel(new BorderLayout());
right.setBackground(bg);
right.setForeground(fg);
@@ -91,6 +126,21 @@ public class InspectionListCellRenderer extends DefaultListCellRenderer implemen
return panel;
}
+ private static int adjustRanges(List<TextRange> ranges, int offset) {
+ int result = 0;
+ for (int i = 0; i < ranges.size(); i++) {
+ final TextRange range = ranges.get(i);
+ final int startOffset = range.getStartOffset();
+ if (startOffset < offset) {
+ result = i + 1;
+ }
+ else {
+ ranges.set(i, new TextRange(startOffset - offset, range.getEndOffset() - offset));
+ }
+ }
+ return result;
+ }
+
@NotNull
private static Icon getIcon(@NotNull InspectionToolWrapper tool) {
Icon icon = null;
diff --git a/platform/lang-impl/src/com/intellij/codeInspection/actions/ViewOfflineResultsAction.java b/platform/lang-impl/src/com/intellij/codeInspection/actions/ViewOfflineResultsAction.java
index 0a7c8b24a275..b1ee98ac92fe 100644
--- a/platform/lang-impl/src/com/intellij/codeInspection/actions/ViewOfflineResultsAction.java
+++ b/platform/lang-impl/src/com/intellij/codeInspection/actions/ViewOfflineResultsAction.java
@@ -77,7 +77,7 @@ public class ViewOfflineResultsAction extends AnAction implements DumbAware {
final Presentation presentation = event.getPresentation();
final Project project = event.getData(CommonDataKeys.PROJECT);
presentation.setEnabled(project != null);
- presentation.setVisible(ActionPlaces.MAIN_MENU.equals(event.getPlace()) && !PlatformUtils.isCidr());
+ presentation.setVisible(ActionPlaces.isMainMenuOrActionSearch(event.getPlace()) && !PlatformUtils.isCidr());
}
@Override
diff --git a/platform/lang-impl/src/com/intellij/diagnostic/logging/DebuggerLogConsoleManager.java b/platform/lang-impl/src/com/intellij/diagnostic/logging/DebuggerLogConsoleManager.java
index 6f619641acc0..c24c0e869b97 100644
--- a/platform/lang-impl/src/com/intellij/diagnostic/logging/DebuggerLogConsoleManager.java
+++ b/platform/lang-impl/src/com/intellij/diagnostic/logging/DebuggerLogConsoleManager.java
@@ -16,6 +16,7 @@
package com.intellij.diagnostic.logging;
+@Deprecated
/**
* User: anna
* Date: 01-Feb-2006
diff --git a/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConfigurationPanel.java b/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConfigurationPanel.java
index b043b3e294a2..305af75de669 100644
--- a/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConfigurationPanel.java
+++ b/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConfigurationPanel.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package com.intellij.diagnostic.logging;
import com.intellij.diagnostic.DiagnosticBundle;
@@ -32,10 +31,12 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.*;
import com.intellij.ui.components.JBCheckBox;
import com.intellij.ui.table.TableView;
+import com.intellij.util.SmartList;
import com.intellij.util.ui.AbstractTableCellEditor;
import com.intellij.util.ui.CellEditorComponentWithBrowseButton;
import com.intellij.util.ui.ColumnInfo;
import com.intellij.util.ui.ListTableModel;
+import gnu.trove.THashMap;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
@@ -44,7 +45,6 @@ import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -61,19 +61,20 @@ public class LogConfigurationPanel<T extends RunConfigurationBase> extends Setti
private TextFieldWithBrowseButton myOutputFile;
private JCheckBox myShowConsoleOnStdOutCb;
private JCheckBox myShowConsoleOnStdErrCb;
- private final Map<LogFileOptions, PredefinedLogFile> myLog2Predefined = new HashMap<LogFileOptions, PredefinedLogFile>();
- private final List<PredefinedLogFile> myUnresolvedPredefined = new ArrayList<PredefinedLogFile>();
-
- private final ColumnInfo<LogFileOptions, Boolean> IS_SHOW = new MyIsActiveColumnInfo();
- private final ColumnInfo<LogFileOptions, LogFileOptions> FILE = new MyLogFileColumnInfo();
- private final ColumnInfo<LogFileOptions, Boolean> IS_SKIP_CONTENT = new MyIsSkipColumnInfo();
+ private final Map<LogFileOptions, PredefinedLogFile> myLog2Predefined = new THashMap<LogFileOptions, PredefinedLogFile>();
+ private final List<PredefinedLogFile> myUnresolvedPredefined = new SmartList<PredefinedLogFile>();
public LogConfigurationPanel() {
+ ColumnInfo<LogFileOptions, Boolean> IS_SHOW = new MyIsActiveColumnInfo();
+ ColumnInfo<LogFileOptions, LogFileOptions> FILE = new MyLogFileColumnInfo();
+ ColumnInfo<LogFileOptions, Boolean> IS_SKIP_CONTENT = new MyIsSkipColumnInfo();
+
myModel = new ListTableModel<LogFileOptions>(IS_SHOW, FILE, IS_SKIP_CONTENT);
myFilesTable = new TableView<LogFileOptions>(myModel);
myFilesTable.getEmptyText().setText(DiagnosticBundle.message("log.monitor.no.files"));
final JTableHeader tableHeader = myFilesTable.getTableHeader();
+ @SuppressWarnings("ConstantConditions")
final FontMetrics fontMetrics = tableHeader.getFontMetrics(tableHeader.getFont());
int preferredWidth = fontMetrics.stringWidth(IS_SHOW.getName()) + 20;
@@ -109,7 +110,7 @@ public class LogConfigurationPanel<T extends RunConfigurationBase> extends Setti
public void run(AnActionButton button) {
TableUtil.stopEditing(myFilesTable);
final int[] selected = myFilesTable.getSelectedRows();
- if (selected == null || selected.length == 0) return;
+ if (selected.length == 0) return;
for (int i = selected.length - 1; i >= 0; i--) {
myModel.removeRow(selected[i]);
}
@@ -130,8 +131,8 @@ public class LogConfigurationPanel<T extends RunConfigurationBase> extends Setti
@Override
public void run(AnActionButton button) {
final int selectedRow = myFilesTable.getSelectedRow();
- final LogFileOptions selectedOptions = myFilesTable.getSelectedObject();
- showEditorDialog(selectedOptions);
+ //noinspection ConstantConditions
+ showEditorDialog(myFilesTable.getSelectedObject());
myModel.fireTableDataChanged();
myFilesTable.setRowSelectionInterval(selectedRow, selectedRow);
}
@@ -156,7 +157,7 @@ public class LogConfigurationPanel<T extends RunConfigurationBase> extends Setti
TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT);
myRedirectOutputCb.addActionListener(new ActionListener() {
@Override
- public void actionPerformed(ActionEvent e) {
+ public void actionPerformed(@NotNull ActionEvent e) {
myOutputFile.setEnabled(myRedirectOutputCb.isSelected());
}
});
@@ -218,14 +219,14 @@ public class LogConfigurationPanel<T extends RunConfigurationBase> extends Setti
@Override
protected void resetEditorFrom(final RunConfigurationBase configuration) {
ArrayList<LogFileOptions> list = new ArrayList<LogFileOptions>();
- final ArrayList<LogFileOptions> logFiles = configuration.getLogFiles();
+ final List<LogFileOptions> logFiles = configuration.getLogFiles();
for (LogFileOptions setting : logFiles) {
list.add(
new LogFileOptions(setting.getName(), setting.getPathPattern(), setting.isEnabled(), setting.isSkipContent(), setting.isShowAll()));
}
myLog2Predefined.clear();
myUnresolvedPredefined.clear();
- final ArrayList<PredefinedLogFile> predefinedLogFiles = configuration.getPredefinedLogFiles();
+ final List<PredefinedLogFile> predefinedLogFiles = configuration.getPredefinedLogFiles();
for (PredefinedLogFile predefinedLogFile : predefinedLogFiles) {
PredefinedLogFile logFile = new PredefinedLogFile(predefinedLogFile);
final LogFileOptions options = configuration.getOptionsForPredefinedLogFile(logFile);
@@ -306,8 +307,9 @@ public class LogConfigurationPanel<T extends RunConfigurationBase> extends Setti
@Override
public TableCellRenderer getRenderer(final LogFileOptions p0) {
return new DefaultTableCellRenderer() {
+ @NotNull
@Override
- public Component getTableCellRendererComponent(JTable table,
+ public Component getTableCellRendererComponent(@NotNull JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
@@ -315,6 +317,7 @@ public class LogConfigurationPanel<T extends RunConfigurationBase> extends Setti
int column) {
final Component renderer = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
setText(((LogFileOptions)value).getName());
+ //noinspection ConstantConditions
setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
setBorder(null);
return renderer;
@@ -418,7 +421,7 @@ public class LogConfigurationPanel<T extends RunConfigurationBase> extends Setti
getChildComponent().setBorder(null);
myComponent.getComponentWithButton().getButton().addActionListener(new ActionListener() {
@Override
- public void actionPerformed(ActionEvent e) {
+ public void actionPerformed(@NotNull ActionEvent e) {
showEditorDialog(myLogFileOptions);
JTextField textField = getChildComponent();
textField.setText(myLogFileOptions.getName());
diff --git a/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleBase.java b/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleBase.java
index c6226b65035e..f5882d92bcb4 100644
--- a/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleBase.java
+++ b/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleBase.java
@@ -249,6 +249,7 @@ public abstract class LogConsoleBase extends AdditionalTabComponent implements L
activate();
}
+ @NotNull
@Override
public String getTabTitle() {
return myTitle;
diff --git a/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleImpl.java b/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleImpl.java
index 5933634dfcbc..1f8a48d7c605 100644
--- a/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleImpl.java
+++ b/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleImpl.java
@@ -17,7 +17,7 @@
package com.intellij.diagnostic.logging;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.util.io.FileUtilRt;
import com.intellij.psi.search.GlobalSearchScope;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -44,7 +44,7 @@ public abstract class LogConsoleImpl extends LogConsoleBase {
@NotNull File file,
@NotNull Charset charset,
long skippedContents,
- String title,
+ @NotNull String title,
final boolean buildInActions) {
this(project, file, charset, skippedContents, title, buildInActions, GlobalSearchScope.allScope(project));
}
@@ -53,7 +53,7 @@ public abstract class LogConsoleImpl extends LogConsoleBase {
@NotNull File file,
@NotNull Charset charset,
long skippedContents,
- String title,
+ @NotNull String title,
final boolean buildInActions,
final GlobalSearchScope searchScope) {
super(project, getReader(file, charset, skippedContents), title, buildInActions, new DefaultLogFilterModel(project),
@@ -64,27 +64,30 @@ public abstract class LogConsoleImpl extends LogConsoleBase {
}
@Nullable
- private static Reader getReader(@NotNull final File file, @NotNull final Charset charset, final long skippedContents) {
- Reader reader = null;
+ private static Reader getReader(@NotNull File file, @NotNull Charset charset, long skippedContents) {
try {
try {
- final FileInputStream inputStream = new FileInputStream(file);
- reader = new BufferedReader(new InputStreamReader(inputStream, charset));
- if (file.length() >= skippedContents) { //do not skip forward
- //noinspection ResultOfMethodCallIgnored
- inputStream.skip(skippedContents);
+ @SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
+ FileInputStream inputStream = new FileInputStream(file);
+ //do not skip forward
+ if (file.length() >= skippedContents) {
+ long skipped = 0;
+ while (skipped < skippedContents) {
+ skipped += inputStream.skip(skippedContents - skipped);
+ }
}
+ return new BufferedReader(new InputStreamReader(inputStream, charset));
}
catch (FileNotFoundException ignored) {
- if (FileUtil.createIfDoesntExist(file)) {
- reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), charset));
+ if (FileUtilRt.createIfNotExists(file)) {
+ return new BufferedReader(new InputStreamReader(new FileInputStream(file), charset));
}
+ return null;
}
}
catch (Throwable ignored) {
- reader = null;
+ return null;
}
- return reader;
}
@Override
@@ -104,9 +107,10 @@ public abstract class LogConsoleImpl extends LogConsoleBase {
return null;
}
- final long length = myFile.length();
+ long length = myFile.length();
if (length < myOldLength) {
reader.close();
+ //noinspection IOResourceOpenedButNotSafelyClosed
reader = new BufferedReader(new InputStreamReader(new FileInputStream(myFile), myCharset));
}
myOldLength = length;
diff --git a/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleManager.java b/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleManager.java
index 08407236006d..e5807c674b97 100644
--- a/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleManager.java
+++ b/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,22 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package com.intellij.diagnostic.logging;
import com.intellij.execution.configurations.AdditionalTabComponentManager;
+import com.intellij.execution.configurations.RunConfigurationBase;
import org.jetbrains.annotations.NotNull;
import java.nio.charset.Charset;
-import java.io.Reader;
-
-/**
- * User: anna
- * Date: 01-Feb-2006
- */
public interface LogConsoleManager extends AdditionalTabComponentManager {
- void addLogConsole(final String name, final String path, @NotNull Charset charset, final long skippedContent);
- void addLogConsole(final String name, Reader reader, final String id);
- void removeLogConsole(final String pathOrId);
+ void addLogConsole(@NotNull String name, @NotNull String path, @NotNull Charset charset, long skippedContent, @NotNull RunConfigurationBase runConfiguration);
+
+ void removeLogConsole(@NotNull String pathOrId);
}
diff --git a/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleManagerBase.java b/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleManagerBase.java
index cb034daeaf5a..6e65ede4e04e 100644
--- a/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleManagerBase.java
+++ b/platform/lang-impl/src/com/intellij/diagnostic/logging/LogConsoleManagerBase.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,8 +16,8 @@
package com.intellij.diagnostic.logging;
import com.intellij.execution.configurations.RunConfigurationBase;
+import com.intellij.execution.configurations.RunProfile;
import com.intellij.execution.process.ProcessHandler;
-import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.ui.RunnerLayoutUi;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.project.Project;
@@ -28,93 +28,42 @@ import com.intellij.ui.content.Content;
import com.intellij.ui.content.ContentManagerAdapter;
import com.intellij.ui.content.ContentManagerEvent;
import com.intellij.util.ArrayUtil;
+import gnu.trove.THashMap;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.io.File;
-import java.io.Reader;
import java.nio.charset.Charset;
-import java.util.HashMap;
import java.util.Map;
-/**
- * Created by IntelliJ IDEA.
- * User: michael.golubev
- */
public abstract class LogConsoleManagerBase implements LogConsoleManager, Disposable {
-
private final Project myProject;
-
- private final Map<AdditionalTabComponent, Content> myAdditionalContent = new HashMap<AdditionalTabComponent, Content>();
-
- private ExecutionEnvironment myEnvironment;
+ private final Map<AdditionalTabComponent, Content> myAdditionalContent = new THashMap<AdditionalTabComponent, Content>();
private final GlobalSearchScope mySearchScope;
- /**
- * @deprecated use {@link #LogConsoleManagerBase(com.intellij.openapi.project.Project, com.intellij.psi.search.GlobalSearchScope)}
- * to remove in IDEA 15
- */
- @SuppressWarnings("UnusedDeclaration")
- protected LogConsoleManagerBase(@NotNull Project project) {
- this(project, GlobalSearchScope.allScope(project));
- }
-
protected LogConsoleManagerBase(@NotNull Project project, @NotNull GlobalSearchScope searchScope) {
myProject = project;
mySearchScope = searchScope;
}
- protected final Project getProject() {
- return myProject;
- }
-
- public void setEnvironment(@NotNull ExecutionEnvironment environment) {
- myEnvironment = environment;
- }
-
- protected final ExecutionEnvironment getEnvironment() {
- return myEnvironment;
- }
-
@Override
- public void addLogConsole(final String name, final String path, @NotNull Charset charset, final long skippedContent) {
- addLogConsole(name, path, charset, skippedContent, getDefaultIcon());
+ public void addLogConsole(@NotNull String name, @NotNull String path, @NotNull Charset charset, long skippedContent, @NotNull RunConfigurationBase runConfiguration) {
+ addLogConsole(name, path, charset, skippedContent, getDefaultIcon(), runConfiguration);
}
- public void addLogConsole(final String name, final String path, @NotNull Charset charset, final long skippedContent, Icon icon) {
+ public void addLogConsole(final String name, final String path, @NotNull Charset charset, final long skippedContent, Icon icon, @Nullable RunProfile runProfile) {
doAddLogConsole(new LogConsoleImpl(myProject, new File(path), charset, skippedContent, name, false, mySearchScope) {
-
@Override
public boolean isActive() {
return isConsoleActive(path);
}
- }, path, icon);
- }
-
- @Override
- public void addLogConsole(String name, Reader reader, final String id) {
- addLogConsole(name, reader, id, getDefaultIcon());
- }
-
- public void addLogConsole(String name, Reader reader, final String id, Icon icon) {
- doAddLogConsole(new LogConsoleBase(myProject,
- reader,
- name,
- false,
- new DefaultLogFilterModel(myProject), mySearchScope) {
-
- @Override
- public boolean isActive() {
- return isConsoleActive(id);
- }
- }, id, icon);
+ }, path, icon, runProfile);
}
- private void doAddLogConsole(final LogConsoleBase log,
- final String id,
- Icon icon) {
- if (myEnvironment != null && myEnvironment.getRunProfile() instanceof RunConfigurationBase) {
- ((RunConfigurationBase)myEnvironment.getRunProfile()).customizeLogConsole(log);
+ private void doAddLogConsole(@NotNull final LogConsoleBase log, String id, Icon icon, @Nullable RunProfile runProfile) {
+ if (runProfile instanceof RunConfigurationBase) {
+ ((RunConfigurationBase)runProfile).customizeLogConsole(log);
}
log.attachStopLogConsoleTrackingListener(getProcessHandler());
addAdditionalTabComponent(log, id, icon);
@@ -133,33 +82,28 @@ public abstract class LogConsoleManagerBase implements LogConsoleManager, Dispos
}
@Override
- public void removeLogConsole(final String path) {
- final Content content = getUi().findContent(path);
+ public void removeLogConsole(@NotNull String path) {
+ Content content = getUi().findContent(path);
if (content != null) {
- final LogConsoleBase log = (LogConsoleBase)content.getComponent();
- removeAdditionalTabComponent(log);
+ removeAdditionalTabComponent((LogConsoleBase)content.getComponent());
}
}
@Override
- public void addAdditionalTabComponent(final AdditionalTabComponent tabComponent, final String id) {
+ public void addAdditionalTabComponent(@NotNull AdditionalTabComponent tabComponent, @NotNull String id) {
addAdditionalTabComponent(tabComponent, id, getDefaultIcon());
}
- public Content addAdditionalTabComponent(final AdditionalTabComponent tabComponent, String id, Icon icon) {
- final Content logContent = createLogContent(tabComponent, id, icon);
+ public Content addAdditionalTabComponent(@NotNull AdditionalTabComponent tabComponent, @NotNull String id, @Nullable Icon icon) {
+ Content logContent = getUi().createContent(id, (ComponentWithActions)tabComponent, tabComponent.getTabTitle(), icon,
+ tabComponent.getPreferredFocusableComponent());
myAdditionalContent.put(tabComponent, logContent);
getUi().addContent(logContent);
return logContent;
}
- protected Content createLogContent(AdditionalTabComponent tabComponent, String id, Icon icon) {
- return getUi().createContent(id, (ComponentWithActions)tabComponent, tabComponent.getTabTitle(), icon,
- tabComponent.getPreferredFocusableComponent());
- }
-
@Override
- public void removeAdditionalTabComponent(AdditionalTabComponent component) {
+ public void removeAdditionalTabComponent(@NotNull AdditionalTabComponent component) {
Disposer.dispose(component);
final Content content = myAdditionalContent.remove(component);
if (!getUi().isDisposed()) {
diff --git a/platform/lang-impl/src/com/intellij/diagnostic/logging/LogFilesManager.java b/platform/lang-impl/src/com/intellij/diagnostic/logging/LogFilesManager.java
index a581a15ed6b8..0f95b541ce8a 100644
--- a/platform/lang-impl/src/com/intellij/diagnostic/logging/LogFilesManager.java
+++ b/platform/lang-impl/src/com/intellij/diagnostic/logging/LogFilesManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,135 +13,64 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package com.intellij.diagnostic.logging;
import com.intellij.execution.configurations.LogFileOptions;
import com.intellij.execution.configurations.RunConfigurationBase;
import com.intellij.execution.process.ProcessHandler;
-import com.intellij.openapi.Disposable;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Conditions;
-import com.intellij.openapi.util.Disposer;
-import com.intellij.util.Alarm;
-import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
-import javax.swing.*;
import java.io.File;
-import java.util.*;
-
-/**
- * User: anna
- * Date: 01-Feb-2006
- */
-public class LogFilesManager implements Disposable {
- public static final Logger LOG = Logger.getInstance(LogFilesManager.class);
+import java.util.Set;
+import java.util.TreeMap;
- private static final int UPDATE_INTERVAL = 500;
-
- private final Map<LogFileOptions, Set<String>> myLogFileManagerMap = new LinkedHashMap<LogFileOptions, Set<String>>();
- private final Runnable myUpdateRequest;
+public class LogFilesManager {
private final LogConsoleManager myManager;
- private final Alarm myUpdateAlarm = new Alarm(Alarm.ThreadToUse.POOLED_THREAD, this);
- private boolean myDisposed;
- public LogFilesManager(@NotNull final Project project, LogConsoleManager manager, Disposable parentDisposable) {
+ public LogFilesManager(@NotNull LogConsoleManager manager) {
myManager = manager;
- Disposer.register(parentDisposable, this);
-
- myUpdateRequest = new Runnable() {
- @Override
- public void run() {
- if (project.isDisposed() || myDisposed) return;
- myUpdateAlarm.cancelAllRequests();
- for (final LogFileOptions logFile : myLogFileManagerMap.keySet()) {
- final Set<String> oldFiles = myLogFileManagerMap.get(logFile);
- final Set<String> newFiles = logFile.getPaths(); // should not be called in UI thread
- myLogFileManagerMap.put(logFile, newFiles);
-
- final Set<String> obsoleteFiles = new THashSet<String>(oldFiles);
- obsoleteFiles.removeAll(newFiles);
-
- SwingUtilities.invokeLater(new Runnable() {
- @Override
- public void run() {
- if (project.isDisposed() || myDisposed) return;
-
- addConfigurationConsoles(logFile, new Condition<String>() {
- @Override
- public boolean value(final String file) {
- return !oldFiles.contains(file);
- }
- }, newFiles);
- for (String each : obsoleteFiles) {
- myManager.removeLogConsole(each);
- }
- myUpdateAlarm.addRequest(myUpdateRequest, UPDATE_INTERVAL);
- }
- });
- }
- }
- };
}
- public void registerFileMatcher(@NotNull RunConfigurationBase runConfiguration) {
- final ArrayList<LogFileOptions> logFiles = runConfiguration.getAllLogFiles();
- for (LogFileOptions logFile : logFiles) {
- if (logFile.isEnabled()) {
- myLogFileManagerMap.put(logFile, logFile.getPaths());
+ public void addLogConsoles(@NotNull RunConfigurationBase runConfiguration, @Nullable ProcessHandler startedProcess) {
+ for (LogFileOptions logFileOptions : runConfiguration.getAllLogFiles()) {
+ if (logFileOptions.isEnabled()) {
+ addConfigurationConsoles(logFileOptions, Conditions.<String>alwaysTrue(), logFileOptions.getPaths(), runConfiguration);
}
}
- Alarm updateAlarm = myUpdateAlarm;
- if (updateAlarm != null) {
- updateAlarm.addRequest(myUpdateRequest, UPDATE_INTERVAL);
- }
+ runConfiguration.createAdditionalTabComponents(myManager, startedProcess);
}
- @Override
- public void dispose() {
- myDisposed = true;
- if (myUpdateAlarm != null) {
- myUpdateAlarm.cancelAllRequests();
+ private void addConfigurationConsoles(@NotNull LogFileOptions logFile, @NotNull Condition<String> shouldInclude, @NotNull Set<String> paths, @NotNull RunConfigurationBase runConfiguration) {
+ if (paths.isEmpty()) {
+ return;
}
- }
- public void initLogConsoles(@NotNull RunConfigurationBase base, ProcessHandler startedProcess) {
- List<LogFileOptions> logFiles = base.getAllLogFiles();
- for (LogFileOptions logFile : logFiles) {
- if (logFile.isEnabled()) {
- addConfigurationConsoles(logFile, Conditions.<String>alwaysTrue(), logFile.getPaths());
+ TreeMap<String, String> titleToPath = new TreeMap<String, String>();
+ if (paths.size() == 1) {
+ String path = paths.iterator().next();
+ if (shouldInclude.value(path)) {
+ titleToPath.put(logFile.getName(), path);
}
}
- base.createAdditionalTabComponents(myManager, startedProcess);
- }
-
- private void addConfigurationConsoles(final LogFileOptions logFile, Condition<String> shouldInclude, final Set<String> paths) {
- if (!paths.isEmpty()) {
- final TreeMap<String, String> title2Path = new TreeMap<String, String>();
- if (paths.size() == 1) {
- final String path = paths.iterator().next();
+ else {
+ for (String path : paths) {
if (shouldInclude.value(path)) {
- title2Path.put(logFile.getName(), path);
- }
- }
- else {
- for (String path : paths) {
- if (shouldInclude.value(path)) {
- String title = new File(path).getName();
- if (title2Path.containsKey(title)) {
- title = path;
- }
- title2Path.put(title, path);
+ String title = new File(path).getName();
+ if (titleToPath.containsKey(title)) {
+ title = path;
}
+ titleToPath.put(title, path);
}
}
- for (final String title : title2Path.keySet()) {
- final String path = title2Path.get(title);
- myManager.addLogConsole(title, path, logFile.getCharset(), logFile.isSkipContent() ? new File(path).length() : 0);
- }
+ }
+
+ for (String title : titleToPath.keySet()) {
+ String path = titleToPath.get(title);
+ assert path != null;
+ myManager.addLogConsole(title, path, logFile.getCharset(), logFile.isSkipContent() ? new File(path).length() : 0, runConfiguration);
}
}
}
diff --git a/platform/lang-impl/src/com/intellij/execution/actions/RunConfigurationsComboBoxAction.java b/platform/lang-impl/src/com/intellij/execution/actions/RunConfigurationsComboBoxAction.java
index 2a124dfcca4a..e0895646e2e3 100644
--- a/platform/lang-impl/src/com/intellij/execution/actions/RunConfigurationsComboBoxAction.java
+++ b/platform/lang-impl/src/com/intellij/execution/actions/RunConfigurationsComboBoxAction.java
@@ -65,7 +65,7 @@ public class RunConfigurationsComboBoxAction extends ComboBoxAction implements D
public void update(final AnActionEvent e) {
final Presentation presentation = e.getPresentation();
final Project project = e.getData(CommonDataKeys.PROJECT);
- if (ActionPlaces.MAIN_MENU.equals(e.getPlace())) {
+ if (ActionPlaces.isMainMenuOrActionSearch(e.getPlace())) {
presentation.setDescription(ExecutionBundle.message("choose.run.configuration.action.description"));
presentation.setEnabled(findFrame(e.getData(PlatformDataKeys.CONTEXT_COMPONENT)) != null);
return;
diff --git a/platform/lang-impl/src/com/intellij/execution/actions/StopAction.java b/platform/lang-impl/src/com/intellij/execution/actions/StopAction.java
index 75466528ae2f..596b3900ba5b 100644
--- a/platform/lang-impl/src/com/intellij/execution/actions/StopAction.java
+++ b/platform/lang-impl/src/com/intellij/execution/actions/StopAction.java
@@ -56,7 +56,7 @@ class StopAction extends DumbAwareAction implements AnAction.TransparentUpdate {
Icon icon = getTemplatePresentation().getIcon();
String description = getTemplatePresentation().getDescription();
Presentation presentation = e.getPresentation();
- if (ActionPlaces.MAIN_MENU.equals(e.getPlace())) {
+ if (ActionPlaces.isMainMenuOrActionSearch(e.getPlace())) {
enable = !getCancellableProcesses(e.getProject()).isEmpty() || !getActiveDescriptors(e.getDataContext()).isEmpty();
presentation.setText(getTemplatePresentation().getText());
}
@@ -79,7 +79,8 @@ class StopAction extends DumbAwareAction implements AnAction.TransparentUpdate {
presentation.setText(getTemplatePresentation().getText());
}
else {
- presentation.setText(ExecutionBundle.message("stop.configuration.action.name", runProfile == null ? contentDescriptor.getDisplayName() : runProfile.getName()));
+ presentation.setText(ExecutionBundle.message("stop.configuration.action.name",
+ runProfile == null ? contentDescriptor.getDisplayName() : runProfile.getName()));
}
}
@@ -95,7 +96,7 @@ class StopAction extends DumbAwareAction implements AnAction.TransparentUpdate {
Project project = e.getProject();
List<Pair<TaskInfo, ProgressIndicator>> backgroundTasks = getCancellableProcesses(project);
- if (ActionPlaces.MAIN_MENU.equals(e.getPlace())) {
+ if (ActionPlaces.isMainMenuOrActionSearch(e.getPlace())) {
if (activeProcessHandler != null && !activeProcessHandler.isProcessTerminating() && !activeProcessHandler.isProcessTerminated()
&& backgroundTasks.isEmpty()) {
stopProcess(activeProcessHandler);
diff --git a/platform/lang-impl/src/com/intellij/execution/console/ConsoleExecuteAction.java b/platform/lang-impl/src/com/intellij/execution/console/ConsoleExecuteAction.java
index fcec06644765..f5bec9ac6be4 100644
--- a/platform/lang-impl/src/com/intellij/execution/console/ConsoleExecuteAction.java
+++ b/platform/lang-impl/src/com/intellij/execution/console/ConsoleExecuteAction.java
@@ -18,6 +18,7 @@ package com.intellij.execution.console;
import com.intellij.codeInsight.lookup.Lookup;
import com.intellij.codeInsight.lookup.LookupManager;
import com.intellij.execution.process.ConsoleHistoryModel;
+import com.intellij.execution.ui.ConsoleViewContentType;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.EmptyAction;
@@ -39,7 +40,7 @@ public class ConsoleExecuteAction extends DumbAwareAction {
private final LanguageConsoleView myConsoleView;
private final LanguageConsoleImpl myConsole;
- private final ConsoleExecuteActionHandler myExecuteActionHandler;
+ final ConsoleExecuteActionHandler myExecuteActionHandler;
private final Condition<LanguageConsoleImpl> myEnabledCondition;
@SuppressWarnings("UnusedDeclaration")
@@ -95,7 +96,7 @@ public class ConsoleExecuteAction extends DumbAwareAction {
}
@Override
- public final void update(AnActionEvent e) {
+ public final void update(@NotNull AnActionEvent e) {
EditorEx editor = myConsole.getConsoleEditor();
boolean enabled = !editor.isRendererMode() && isEnabled() &&
(myExecuteActionHandler.isEmptyCommandExecutionAllowed() || !StringUtil.isEmptyOrSpaces(editor.getDocument().getCharsSequence()));
@@ -109,7 +110,7 @@ public class ConsoleExecuteAction extends DumbAwareAction {
}
@Override
- public final void actionPerformed(AnActionEvent e) {
+ public final void actionPerformed(@NotNull AnActionEvent e) {
myExecuteActionHandler.runExecuteAction(myConsole, myConsoleView);
}
@@ -139,6 +140,8 @@ public class ConsoleExecuteAction extends DumbAwareAction {
private boolean myAddToHistory = true;
final boolean myPreserveMarkup;
+ boolean useProcessStdIn;
+
public ConsoleExecuteActionHandler(boolean preserveMarkup) {
myCommandHistoryModel = new ConsoleHistoryModel();
myPreserveMarkup = preserveMarkup;
@@ -156,19 +159,25 @@ public class ConsoleExecuteAction extends DumbAwareAction {
myAddToHistory = addCurrentToHistory;
}
- /**
- * @deprecated
- */
protected void beforeExecution(@NotNull LanguageConsoleImpl console) {
}
protected void runExecuteAction(@NotNull LanguageConsoleImpl console, @Nullable LanguageConsoleView consoleView) {
- //noinspection deprecation
- beforeExecution(console);
+ if (!useProcessStdIn) {
+ beforeExecution(console);
+ }
- String text = console.prepareExecuteAction(myAddToHistory, myPreserveMarkup, true);
+ String text = console.prepareExecuteAction(myAddToHistory && !useProcessStdIn, myPreserveMarkup, true);
((UndoManagerImpl)UndoManager.getInstance(console.getProject())).invalidateActionsFor(DocumentReferenceManager.getInstance().create(console.getCurrentEditor().getDocument()));
- addToCommandHistoryAndExecute(console, consoleView, text);
+
+ if (useProcessStdIn) {
+ assert consoleView != null;
+ consoleView.print(text, ConsoleViewContentType.USER_INPUT);
+ consoleView.print("\n", ConsoleViewContentType.USER_INPUT);
+ }
+ else {
+ addToCommandHistoryAndExecute(console, consoleView, text);
+ }
}
private void addToCommandHistoryAndExecute(@NotNull LanguageConsoleImpl console, @Nullable LanguageConsoleView consoleView, @NotNull String text) {
diff --git a/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleBuilder.java b/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleBuilder.java
index 329b9f0e3f13..a20b8c706ff2 100644
--- a/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleBuilder.java
+++ b/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleBuilder.java
@@ -1,6 +1,8 @@
package com.intellij.execution.console;
+import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
import com.intellij.execution.process.ProcessHandler;
+import com.intellij.ide.util.PropertiesComponent;
import com.intellij.lang.Language;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.editor.Document;
@@ -60,6 +62,8 @@ public final class LanguageConsoleBuilder {
private boolean oneLineInput;
+ private String processInputStateKey;
+
// todo to be removed
public LanguageConsoleBuilder(@SuppressWarnings("NullableProblems") @NotNull LanguageConsoleView consoleView) {
this.consoleView = consoleView;
@@ -87,6 +91,7 @@ public final class LanguageConsoleBuilder {
return this;
}
+ @NotNull
public LanguageConsoleBuilder initActions(@NotNull BaseConsoleExecuteActionHandler executeActionHandler, @NotNull String historyType) {
if (consoleView == null) {
this.executeActionHandler = executeActionHandler;
@@ -150,6 +155,13 @@ public final class LanguageConsoleBuilder {
return this;
}
+ @NotNull
+ public LanguageConsoleBuilder processInputStateKey(@Nullable String value) {
+ processInputStateKey = value;
+ return this;
+ }
+
+ @NotNull
public LanguageConsoleView build(@NotNull Project project, @NotNull Language language) {
GutteredLanguageConsole console = new GutteredLanguageConsole(language.getDisplayName() + " Console", project, language, gutterContentProvider, psiFileFactory);
if (oneLineInput) {
@@ -160,6 +172,17 @@ public final class LanguageConsoleBuilder {
assert historyType != null;
doInitAction(consoleView, executeActionHandler, historyType);
}
+
+ if (processInputStateKey != null) {
+ assert executeActionHandler != null;
+ if (PropertiesComponent.getInstance().getBoolean(processInputStateKey, false)) {
+ executeActionHandler.useProcessStdIn = true;
+ DaemonCodeAnalyzer daemonCodeAnalyzer = DaemonCodeAnalyzer.getInstance(consoleView.getProject());
+ daemonCodeAnalyzer.setHighlightingEnabled(consoleView.getConsole().getFile(), false);
+ }
+ consoleView.addCustomConsoleAction(new UseConsoleInputAction(processInputStateKey));
+ }
+
console.initComponents();
return consoleView;
}
diff --git a/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java b/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java
index d7f40f35a219..711184d9b705 100644
--- a/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java
+++ b/platform/lang-impl/src/com/intellij/execution/console/LanguageConsoleImpl.java
@@ -659,6 +659,7 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider {
if (myCurrentEditor != null && myCurrentEditor.isDisposed()) {
myCurrentEditor = null;
}
+ if (!isValid()) return;
ApplicationManager.getApplication().runReadAction(myUiUpdateRunnable);
}
}
@@ -680,6 +681,10 @@ public class LanguageConsoleImpl implements Disposable, TypeSafeDataProvider {
return ObjectUtils.assertNotNull(myVirtualFile.getLanguage());
}
+ public boolean isValid() {
+ return myVirtualFile.isValid() && myProject.isOpen();
+ }
+
public void setLanguage(@NotNull Language language) {
myVirtualFile.setLanguage(language);
myVirtualFile.setContent(myEditorDocument, myEditorDocument.getText(), false);
diff --git a/platform/lang-impl/src/com/intellij/execution/console/UseConsoleInputAction.java b/platform/lang-impl/src/com/intellij/execution/console/UseConsoleInputAction.java
new file mode 100644
index 000000000000..5b450e3bd154
--- /dev/null
+++ b/platform/lang-impl/src/com/intellij/execution/console/UseConsoleInputAction.java
@@ -0,0 +1,56 @@
+package com.intellij.execution.console;
+
+import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
+import com.intellij.icons.AllIcons;
+import com.intellij.ide.util.PropertiesComponent;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.LangDataKeys;
+import com.intellij.openapi.actionSystem.ToggleAction;
+import com.intellij.openapi.actionSystem.ex.ActionUtil;
+import com.intellij.openapi.project.DumbAware;
+import com.intellij.psi.PsiFile;
+import com.intellij.util.containers.ContainerUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+
+final class UseConsoleInputAction extends ToggleAction implements DumbAware {
+ private final String processInputStateKey;
+ private boolean useProcessStdIn;
+
+ public UseConsoleInputAction(@NotNull String processInputStateKey) {
+ super("Use Console Input", null, AllIcons.Debugger.CommandLine);
+
+ this.processInputStateKey = processInputStateKey;
+ useProcessStdIn = PropertiesComponent.getInstance().getBoolean(processInputStateKey, false);
+ }
+
+ @Override
+ public boolean isSelected(@Nullable AnActionEvent event) {
+ return !useProcessStdIn;
+ }
+
+ @Override
+ public void setSelected(AnActionEvent event, boolean state) {
+ useProcessStdIn = !state;
+
+ LanguageConsoleView consoleView = (LanguageConsoleView)event.getData(LangDataKeys.CONSOLE_VIEW);
+ assert consoleView != null;
+ DaemonCodeAnalyzer daemonCodeAnalyzer = DaemonCodeAnalyzer.getInstance(consoleView.getProject());
+ PsiFile file = consoleView.getConsole().getFile();
+ daemonCodeAnalyzer.setHighlightingEnabled(file, state);
+ daemonCodeAnalyzer.restart(file);
+ if (state) {
+ PropertiesComponent.getInstance().unsetValue(processInputStateKey);
+ }
+ else {
+ PropertiesComponent.getInstance().setValue(processInputStateKey, "true");
+ }
+
+ List<AnAction> actions = ActionUtil.getActions(consoleView.getConsole().getConsoleEditor().getComponent());
+ ConsoleExecuteAction action = ContainerUtil.findInstance(actions, ConsoleExecuteAction.class);
+ action.myExecuteActionHandler.useProcessStdIn = !state;
+ }
+} \ No newline at end of file
diff --git a/platform/lang-impl/src/com/intellij/execution/impl/BeforeRunStepsPanel.java b/platform/lang-impl/src/com/intellij/execution/impl/BeforeRunStepsPanel.java
index de5405b87a89..191c0f79b25c 100644
--- a/platform/lang-impl/src/com/intellij/execution/impl/BeforeRunStepsPanel.java
+++ b/platform/lang-impl/src/com/intellij/execution/impl/BeforeRunStepsPanel.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,7 +28,7 @@ import com.intellij.openapi.actionSystem.impl.SimpleDataContext;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.ui.popup.ListPopup;
-import com.intellij.openapi.util.Condition;
+import com.intellij.openapi.util.Conditions;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.SystemInfo;
@@ -300,7 +300,7 @@ class BeforeRunStepsPanel extends JPanel {
final ListPopup popup =
popupFactory.createActionGroupPopup(ExecutionBundle.message("add.new.run.configuration.acrtion.name"), actionGroup,
SimpleDataContext.getProjectContext(myRunConfiguration.getProject()), false, false, false, null,
- -1, Condition.TRUE);
+ -1, Conditions.<AnAction>alwaysTrue());
popup.show(button.getPreferredPopupPoint());
}
diff --git a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java
index 3fce510e725e..ae5cfe829f6c 100644
--- a/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java
+++ b/platform/lang-impl/src/com/intellij/execution/impl/ConsoleViewImpl.java
@@ -290,9 +290,16 @@ public class ConsoleViewImpl extends JPanel implements ConsoleView, ObservableCo
myFilters = new CompositeFilter(project);
if (usePredefinedMessageFilter) {
for (ConsoleFilterProvider eachProvider : Extensions.getExtensions(ConsoleFilterProvider.FILTER_PROVIDERS)) {
- Filter[] filters = eachProvider instanceof ConsoleFilterProviderEx
- ? ((ConsoleFilterProviderEx)eachProvider).getDefaultFilters(project, searchScope)
- : eachProvider.getDefaultFilters(project);
+ Filter[] filters;
+ if (eachProvider instanceof ConsoleDependentFilterProvider) {
+ filters = ((ConsoleDependentFilterProvider)eachProvider).getDefaultFilters(this, project, searchScope);
+ }
+ else if (eachProvider instanceof ConsoleFilterProviderEx) {
+ filters = ((ConsoleFilterProviderEx)eachProvider).getDefaultFilters(project, searchScope);
+ }
+ else {
+ filters = eachProvider.getDefaultFilters(project);
+ }
for (Filter filter : filters) {
myFilters.addFilter(filter);
}
diff --git a/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurable.java b/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurable.java
index 95d4db09c297..1a006c294275 100644
--- a/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurable.java
+++ b/platform/lang-impl/src/com/intellij/execution/impl/RunConfigurable.java
@@ -588,15 +588,9 @@ class RunConfigurable extends BaseConfigurable {
@Override
public JComponent createComponent() {
- for (RunConfigurationsSettings each : Extensions.getExtensions(RunConfigurationsSettings.EXTENSION_POINT)) {
- try {
- UnnamedConfigurable configurable = each.createConfigurable(myProject);
- myAdditionalSettings.add(Pair.create(configurable, configurable.createComponent()));
- }
- catch (NoSuchMethodError e) {
- // in case someone has already implemented old RunConfigurationsSettings.createConfigurable()
- LOG.error(e);
- }
+ for (RunConfigurationsSettings each : Extensions.getExtensions(RunConfigurationsSettings.EXTENSION_POINT, myProject)) {
+ UnnamedConfigurable configurable = each.createConfigurable();
+ myAdditionalSettings.add(Pair.create(configurable, configurable.createComponent()));
}
myWholePanel = new JPanel(new BorderLayout());
diff --git a/platform/lang-impl/src/com/intellij/execution/runners/RunContentBuilder.java b/platform/lang-impl/src/com/intellij/execution/runners/RunContentBuilder.java
index f16f8dadfb45..14877309db74 100644
--- a/platform/lang-impl/src/com/intellij/execution/runners/RunContentBuilder.java
+++ b/platform/lang-impl/src/com/intellij/execution/runners/RunContentBuilder.java
@@ -23,7 +23,6 @@ import com.intellij.execution.configurations.RunConfigurationBase;
import com.intellij.execution.configurations.RunProfile;
import com.intellij.execution.configurations.SearchScopeProvider;
import com.intellij.execution.impl.ConsoleViewImpl;
-import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.ui.*;
import com.intellij.execution.ui.actions.CloseAction;
import com.intellij.execution.ui.layout.PlaceInGrid;
@@ -41,7 +40,6 @@ import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import javax.swing.*;
import java.util.Collection;
import java.util.List;
@@ -113,14 +111,13 @@ public class RunContentBuilder extends RunTab {
@NotNull
private RunContentDescriptor createDescriptor() {
- final RunProfile profile = getEnvironment().getRunProfile();
+ final RunProfile profile = myEnvironment.getRunProfile();
if (ApplicationManager.getApplication().isUnitTestMode()) {
- RunContentDescriptor contentDescriptor = new RunContentDescriptor(profile, myExecutionResult, myUi);
- Disposer.register(contentDescriptor, this);
- return contentDescriptor;
+ return new RunContentDescriptor(profile, myExecutionResult, myUi);
}
final ExecutionConsole console = myExecutionResult.getExecutionConsole();
+ RunContentDescriptor contentDescriptor = new RunContentDescriptor(profile, myExecutionResult, myUi);
if (console != null) {
if (console instanceof ExecutionConsoleEx) {
((ExecutionConsoleEx)console).buildUi(myUi);
@@ -128,17 +125,15 @@ public class RunContentBuilder extends RunTab {
else {
buildConsoleUiDefault(myUi, console);
}
- initLogConsoles(profile, myExecutionResult.getProcessHandler(), console);
+ initLogConsoles(profile, contentDescriptor, console);
}
- RunContentDescriptor contentDescriptor = new RunContentDescriptor(profile, myExecutionResult, myUi);
- Disposer.register(contentDescriptor, this);
myUi.getOptions().setLeftToolbar(createActionToolbar(contentDescriptor), ActionPlaces.UNKNOWN);
if (profile instanceof RunConfigurationBase) {
if (console instanceof ObservableConsoleView && !ApplicationManager.getApplication().isUnitTestMode()) {
((ObservableConsoleView)console).addChangeListener(new ConsoleToFrontListener((RunConfigurationBase)profile,
- getProject(),
- getEnvironment().getExecutor(),
+ myProject,
+ myEnvironment.getExecutor(),
contentDescriptor,
myUi),
this);
@@ -182,19 +177,16 @@ public class RunContentBuilder extends RunTab {
}
@NotNull
- private ActionGroup createActionToolbar(@NotNull RunContentDescriptor contentDescriptor) {
+ private ActionGroup createActionToolbar(@NotNull final RunContentDescriptor contentDescriptor) {
final DefaultActionGroup actionGroup = new DefaultActionGroup();
actionGroup.add(ActionManager.getInstance().getAction(IdeActions.ACTION_RERUN));
- if (myExecutionResult instanceof DefaultExecutionResult) {
- final AnAction[] actions = ((DefaultExecutionResult)myExecutionResult).getRestartActions();
- if (actions != null) {
- actionGroup.addAll(actions);
- if (actions.length > 0) {
- actionGroup.addSeparator();
- }
- }
+ final AnAction[] actions = contentDescriptor.getRestartActions();
+ actionGroup.addAll(actions);
+ if (actions.length > 0) {
+ actionGroup.addSeparator();
}
+
actionGroup.add(ActionManager.getInstance().getAction(IdeActions.ACTION_STOP_PROGRAM));
if (myExecutionResult instanceof DefaultExecutionResult) {
actionGroup.addAll(((DefaultExecutionResult)myExecutionResult).getAdditionalStopActions());
@@ -215,37 +207,24 @@ public class RunContentBuilder extends RunTab {
actionGroup.add(myUi.getOptions().getLayoutActions());
actionGroup.addSeparator();
actionGroup.add(PinToolwindowTabAction.getPinAction());
- actionGroup.add(new CloseAction(getEnvironment().getExecutor(), contentDescriptor, getProject()));
+ actionGroup.add(new CloseAction(myEnvironment.getExecutor(), contentDescriptor, myProject));
final String helpId = contentDescriptor.getHelpId();
- actionGroup.add(new ContextHelpAction(helpId != null ? helpId : getEnvironment().getExecutor().getHelpId()));
+ actionGroup.add(new ContextHelpAction(helpId != null ? helpId : myEnvironment.getExecutor().getHelpId()));
return actionGroup;
}
- @Override
- public ProcessHandler getProcessHandler() {
- return myExecutionResult.getProcessHandler();
- }
-
/**
* @param reuseContent see {@link RunContentDescriptor#myContent}
*/
public RunContentDescriptor showRunContent(@Nullable RunContentDescriptor reuseContent) {
RunContentDescriptor descriptor = createDescriptor();
+ Disposer.register(descriptor, this);
+ Disposer.register(myProject, descriptor);
RunContentManagerImpl.copyContentAndBehavior(descriptor, reuseContent);
myRunContentDescriptor = descriptor;
return descriptor;
}
- @Override
- protected RunnerLayoutUi getUi() {
- return myUi;
- }
-
- @Override
- protected Icon getDefaultIcon() {
- return AllIcons.Debugger.Console;
- }
-
public static class ConsoleToFrontListener implements ConsoleViewImpl.ChangeListener {
@NotNull private final RunConfigurationBase myRunConfigurationBase;
@NotNull private final Project myProject;
diff --git a/platform/lang-impl/src/com/intellij/execution/runners/RunTab.java b/platform/lang-impl/src/com/intellij/execution/runners/RunTab.java
index 2edc2098ce15..6628c78f1851 100644
--- a/platform/lang-impl/src/com/intellij/execution/runners/RunTab.java
+++ b/platform/lang-impl/src/com/intellij/execution/runners/RunTab.java
@@ -25,6 +25,8 @@ import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.ui.ExecutionConsole;
import com.intellij.execution.ui.RunContentDescriptor;
import com.intellij.execution.ui.RunnerLayoutUi;
+import com.intellij.icons.AllIcons;
+import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.DataProvider;
import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.openapi.project.Project;
@@ -33,12 +35,20 @@ import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-public abstract class RunTab extends LogConsoleManagerBase implements DataProvider {
+import javax.swing.*;
+
+public abstract class RunTab implements DataProvider, Disposable {
@NotNull
protected final RunnerLayoutUi myUi;
- protected final LogFilesManager myManager;
+ private LogFilesManager myManager;
protected RunContentDescriptor myRunContentDescriptor;
+ protected ExecutionEnvironment myEnvironment;
+ protected final Project myProject;
+ private final GlobalSearchScope mySearchScope;
+
+ private LogConsoleManagerBase logConsoleManager;
+
protected RunTab(@NotNull ExecutionEnvironment environment, @NotNull String runnerType) {
this(environment.getProject(),
SearchScopeProvider.createSearchScope(environment.getProject(), environment.getRunProfile()),
@@ -46,15 +56,21 @@ public abstract class RunTab extends LogConsoleManagerBase implements DataProvid
environment.getExecutor().getId(),
environment.getRunProfile().getName());
- setEnvironment(environment);
+ myEnvironment = environment;
}
- protected RunTab(@NotNull Project project, @NotNull GlobalSearchScope searchScope, @NotNull String runnerType, @NotNull String runnerTitle, @NotNull String sessionName) {
- super(project, searchScope);
+ @Override
+ public void dispose() {
+ myRunContentDescriptor = null;
+ myEnvironment = null;
+ logConsoleManager = null;
+ }
- myManager = new LogFilesManager(project, this, this);
+ protected RunTab(@NotNull Project project, @NotNull GlobalSearchScope searchScope, @NotNull String runnerType, @NotNull String runnerTitle, @NotNull String sessionName) {
+ myProject = project;
+ mySearchScope = searchScope;
- myUi = RunnerLayoutUi.Factory.getInstance(getProject()).create(runnerType, runnerTitle, sessionName, this);
+ myUi = RunnerLayoutUi.Factory.getInstance(project).create(runnerType, runnerTitle, sessionName, this);
myUi.getContentManager().addDataProvider(this);
}
@@ -62,11 +78,10 @@ public abstract class RunTab extends LogConsoleManagerBase implements DataProvid
@Override
public Object getData(@NonNls String dataId) {
if (LangDataKeys.RUN_PROFILE.is(dataId)) {
- ExecutionEnvironment environment = getEnvironment();
- return environment == null ? null : environment.getRunProfile();
+ return myEnvironment == null ? null : myEnvironment.getRunProfile();
}
else if (LangDataKeys.EXECUTION_ENVIRONMENT.is(dataId)) {
- return getEnvironment();
+ return myEnvironment;
}
else if (LangDataKeys.RUN_CONTENT_DESCRIPTOR.is(dataId)) {
return myRunContentDescriptor;
@@ -74,21 +89,40 @@ public abstract class RunTab extends LogConsoleManagerBase implements DataProvid
return null;
}
- @Override
- public final void setEnvironment(@NotNull ExecutionEnvironment environment) {
- super.setEnvironment(environment);
+ @NotNull
+ public LogConsoleManagerBase getLogConsoleManager() {
+ if (logConsoleManager == null) {
+ logConsoleManager = new LogConsoleManagerBase(myProject, mySearchScope) {
+ @Override
+ protected Icon getDefaultIcon() {
+ return AllIcons.Debugger.Console;
+ }
+
+ @Override
+ protected RunnerLayoutUi getUi() {
+ return myUi;
+ }
- RunProfile profile = environment.getRunProfile();
- if (profile instanceof RunConfigurationBase) {
- myManager.registerFileMatcher((RunConfigurationBase)profile);
+ @Override
+ public ProcessHandler getProcessHandler() {
+ return myRunContentDescriptor == null ? null : myRunContentDescriptor.getProcessHandler();
+ }
+ };
}
+ return logConsoleManager;
}
- protected final void initLogConsoles(@NotNull RunProfile runConfiguration, @Nullable ProcessHandler processHandler, @Nullable ExecutionConsole console) {
- if (runConfiguration instanceof RunConfigurationBase && processHandler != null) {
+ protected final void initLogConsoles(@NotNull RunProfile runConfiguration, @NotNull RunContentDescriptor contentDescriptor, @Nullable ExecutionConsole console) {
+ ProcessHandler processHandler = contentDescriptor.getProcessHandler();
+ if (runConfiguration instanceof RunConfigurationBase) {
RunConfigurationBase configuration = (RunConfigurationBase)runConfiguration;
- myManager.initLogConsoles(configuration, processHandler);
- OutputFileUtil.attachDumpListener(configuration, processHandler, console);
+ if (myManager == null) {
+ myManager = new LogFilesManager(getLogConsoleManager());
+ }
+ myManager.addLogConsoles(configuration, processHandler);
+ if (processHandler != null) {
+ OutputFileUtil.attachDumpListener(configuration, processHandler, console);
+ }
}
}
}
diff --git a/platform/lang-impl/src/com/intellij/execution/ui/CommonProgramParametersPanel.java b/platform/lang-impl/src/com/intellij/execution/ui/CommonProgramParametersPanel.java
index 0f31d6223027..79284abf8356 100644
--- a/platform/lang-impl/src/com/intellij/execution/ui/CommonProgramParametersPanel.java
+++ b/platform/lang-impl/src/com/intellij/execution/ui/CommonProgramParametersPanel.java
@@ -56,6 +56,7 @@ public class CommonProgramParametersPanel extends JPanel implements PanelWithAnc
protected JComponent myAnchor;
private Module myModuleContext = null;
+ private boolean myHasModuleMacro = false;
public CommonProgramParametersPanel() {
this(true);
@@ -120,7 +121,7 @@ public class CommonProgramParametersPanel extends JPanel implements PanelWithAnc
@Override
public void actionPerformed(ActionEvent e) {
List<String> macros = new SmartList<String>(PathMacros.getInstance().getUserMacroNames());
- if (myModuleContext != null) {
+ if (myModuleContext != null || myHasModuleMacro) {
macros.add(PathMacroUtil.MODULE_DIR_MACRO_NAME);
}
@@ -172,6 +173,10 @@ public class CommonProgramParametersPanel extends JPanel implements PanelWithAnc
myModuleContext = moduleContext;
}
+ public void setHasModuleMacro() {
+ myHasModuleMacro = true;
+ }
+
public LabeledComponent<RawCommandLineEditor> getProgramParametersComponent() {
return myProgramParametersComponent;
}
diff --git a/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java b/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java
index 9613ac0dd33f..4d7eee35a462 100644
--- a/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java
+++ b/platform/lang-impl/src/com/intellij/find/EditorSearchComponent.java
@@ -425,6 +425,10 @@ public class EditorSearchComponent extends EditorHeaderComponent implements Data
myToolbarComponent.setOpaque(false);
}
+ public void selectAllText() {
+ mySearchField.selectAll();
+ }
+
private boolean secondaryActionsAvailable() {
return FindManagerImpl.ourHasSearchInCommentsAndLiterals;
}
@@ -483,10 +487,11 @@ public class EditorSearchComponent extends EditorHeaderComponent implements Data
}
private void updateUIWithFindModel() {
-
+ boolean needToResetFocus = false;
myActionsToolbar.updateActionsImmediately();
if ((myFindModel.isMultiline() && mySearchField instanceof JTextField) || (!myFindModel.isMultiline() && mySearchField instanceof JTextArea)) {
+ needToResetFocus = mySearchField.hasFocus();
myLeftComponent.removeAll();
myRightComponent.removeAll();
myReplaceRootComponent = null;
@@ -529,6 +534,7 @@ public class EditorSearchComponent extends EditorHeaderComponent implements Data
updateReplaceButton();
Utils.setSmallerFontForChildren(myToolbarComponent);
revalidate();
+ if (needToResetFocus) mySearchField.requestFocusInWindow();
}
private static boolean wholeWordsApplicable(String stringToFind) {
diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToFind.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToFind.java
index 440a76c87608..7e4b555d264c 100644
--- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToFind.java
+++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToFind.java
@@ -36,8 +36,10 @@ public class SwitchToFind extends EditorHeaderAction implements DumbAware {
action.actionPerformed(e);
return;
}
-
- final FindModel findModel = getEditorSearchComponent().getFindModel();
+
+ EditorSearchComponent component = getEditorSearchComponent();
+ final FindModel findModel = component.getFindModel();
FindUtil.configureFindModel(false, null, findModel, false);
+ component.selectAllText();
}
}
diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToReplace.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToReplace.java
index f667f019db17..2d8b48aad855 100644
--- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToReplace.java
+++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/SwitchToReplace.java
@@ -33,7 +33,9 @@ public class SwitchToReplace extends EditorHeaderAction {
@Override
public void actionPerformed(AnActionEvent e) {
- final FindModel findModel = getEditorSearchComponent().getFindModel();
+ EditorSearchComponent component = getEditorSearchComponent();
+ final FindModel findModel = component.getFindModel();
FindUtil.configureFindModel(true, null, findModel, false);
+ component.selectAllText();
}
}
diff --git a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleRegex.java b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleRegex.java
index 1a4ea149df7d..472517ab336d 100644
--- a/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleRegex.java
+++ b/platform/lang-impl/src/com/intellij/find/editorHeaderActions/ToggleRegex.java
@@ -30,12 +30,6 @@ public class ToggleRegex extends EditorHeaderToggleAction {
}
@Override
- public void update(AnActionEvent e) {
- super.update(e);
- e.getPresentation().setVisible(!getEditorSearchComponent().getFindModel().isMultiline());
- }
-
- @Override
public void setSelected(AnActionEvent e, boolean state) {
final FindModel findModel = getEditorSearchComponent().getFindModel();
findModel.setRegularExpressions(state);
diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindInProjectTask.java b/platform/lang-impl/src/com/intellij/find/impl/FindInProjectTask.java
index 7dfdbbce16d7..822ffbb64037 100644
--- a/platform/lang-impl/src/com/intellij/find/impl/FindInProjectTask.java
+++ b/platform/lang-impl/src/com/intellij/find/impl/FindInProjectTask.java
@@ -38,6 +38,7 @@ import com.intellij.openapi.project.ProjectCoreUtil;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Condition;
+import com.intellij.openapi.util.Conditions;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.util.text.TrigramBuilder;
@@ -105,7 +106,7 @@ class FindInProjectTask {
final Pattern pattern = FindInProjectUtil.createFileMaskRegExp(filter);
//noinspection unchecked
- myFileMask = pattern == null ? Condition.TRUE : new Condition<VirtualFile>() {
+ myFileMask = pattern == null ? Conditions.<VirtualFile>alwaysTrue() : new Condition<VirtualFile>() {
@Override
public boolean value(VirtualFile file) {
return file != null && pattern.matcher(file.getName()).matches();
@@ -127,6 +128,9 @@ class FindInProjectTask {
}
});
myProgress.setIndeterminate(false);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Searching for " + myFindModel.getStringToFind() + " in " + filesForFastWordSearch.size() + " indexed files");
+ }
searchInFiles(filesForFastWordSearch, processPresentation, consumer);
@@ -136,6 +140,10 @@ class FindInProjectTask {
final Collection<PsiFile> otherFiles = collectFilesInScope(filesForFastWordSearch, skipIndexed);
myProgress.setIndeterminate(false);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Searching for " + myFindModel.getStringToFind() + " in " + otherFiles.size() + " non-indexed files");
+ }
+
long start = System.currentTimeMillis();
searchInFiles(otherFiles, processPresentation, consumer);
if (skipIndexed && otherFiles.size() > 1000) {
@@ -143,7 +151,10 @@ class FindInProjectTask {
}
}
catch (ProcessCanceledException e) {
- // fine
+ processPresentation.setCanceled(true);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Usage search canceled", e);
+ }
}
if (!myLargeFiles.isEmpty()) {
diff --git a/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java b/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java
index b7d58e926e30..f077008068ad 100644
--- a/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java
+++ b/platform/lang-impl/src/com/intellij/find/impl/FindManagerImpl.java
@@ -446,8 +446,16 @@ public class FindManagerImpl extends FindManager implements PersistentStateCompo
final FindModel model = new FindModel();
model.copyFrom(findmodel);
final String s = model.getStringToFind();
- model.setStringToFind(StringUtil.escapeToRegexp(s));
- model.setRegularExpressions(true);
+ String newStringToFind;
+
+ if (findmodel.isRegularExpressions()) {
+ newStringToFind = StringUtil.replace(s, "\n", "\\n\\s*"); // add \\s* for convenience
+ } else {
+ newStringToFind = StringUtil.escapeToRegexp(s);
+ model.setRegularExpressions(true);
+ }
+ model.setStringToFind(newStringToFind);
+
return model;
}
return findmodel;
diff --git a/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreview.java b/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreview.java
index 995a67ecafa1..e104c1664857 100644
--- a/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreview.java
+++ b/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreview.java
@@ -24,7 +24,6 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.SelectionModel;
-import com.intellij.openapi.editor.colors.CodeInsightColors;
import com.intellij.openapi.editor.colors.EditorColors;
import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.event.*;
@@ -53,9 +52,7 @@ import java.io.PrintStream;
import java.util.*;
import java.util.List;
-public class LivePreview extends DocumentAdapter implements SearchResults.SearchResultsListener,
- SelectionListener {
-
+public class LivePreview extends DocumentAdapter implements SearchResults.SearchResultsListener, SelectionListener {
private static final Key<Object> IN_SELECTION_KEY = Key.create("LivePreview.IN_SELECTION_KEY");
private static final Object IN_SELECTION1 = new Object();
private static final Object IN_SELECTION2 = new Object();
@@ -73,6 +70,13 @@ public class LivePreview extends DocumentAdapter implements SearchResults.Search
private String myReplacementPreviewText;
private static boolean NotFound;
+ private final Set<RangeHighlighter> myHighlighters = new HashSet<RangeHighlighter>();
+ private RangeHighlighter myCursorHighlighter;
+ private final List<VisibleAreaListener> myVisibleAreaListenersToRemove = new ArrayList<VisibleAreaListener>();
+ private Delegate myDelegate;
+ private final SearchResults mySearchResults;
+ private Balloon myReplacementBalloon;
+
@Override
public void selectionChanged(SelectionEvent e) {
updateInSelectionHighlighters();
@@ -87,27 +91,15 @@ public class LivePreview extends DocumentAdapter implements SearchResults.Search
}
public interface Delegate {
-
@Nullable
- String getStringToReplace(Editor editor, FindResult findResult);
-
+ String getStringToReplace(@NotNull Editor editor, @Nullable FindResult findResult);
}
- private final Set<RangeHighlighter> myHighlighters = new HashSet<RangeHighlighter>();
-
- private RangeHighlighter myCursorHighlighter;
- private final List<VisibleAreaListener> myVisibleAreaListenersToRemove = new ArrayList<VisibleAreaListener>();
-
- private static TextAttributes strikout() {
- return EditorColorsManager.getInstance().getGlobalScheme().getAttributes(CodeInsightColors.DEPRECATED_ATTRIBUTES).clone();
+ private static TextAttributes strikeout() {
+ Color color = EditorColorsManager.getInstance().getGlobalScheme().getDefaultForeground();
+ return new TextAttributes(null, null, color, EffectType.STRIKEOUT, 0);
}
- private Delegate myDelegate;
-
- private final SearchResults mySearchResults;
-
- private Balloon myReplacementBalloon;
-
@Override
public void searchResultsUpdated(SearchResults sr) {
final Project project = mySearchResults.getProject();
@@ -323,7 +315,7 @@ public class LivePreview extends DocumentAdapter implements SearchResults.Search
attributes.setEffectColor(attributes.getBackgroundColor());
}
if (mySearchResults.isExcluded(range)) {
- highlightRange(range, strikout(), myHighlighters);
+ highlightRange(range, strikeout(), myHighlighters);
} else {
highlightRange(range, attributes, myHighlighters);
}
diff --git a/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewController.java b/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewController.java
index 94a6c3f9c1bc..a894781d5cb1 100644
--- a/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewController.java
+++ b/platform/lang-impl/src/com/intellij/find/impl/livePreview/LivePreviewController.java
@@ -19,7 +19,9 @@ import com.intellij.find.*;
import com.intellij.find.impl.FindResultImpl;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.editor.*;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.editor.RangeMarker;
+import com.intellij.openapi.editor.SelectionModel;
import com.intellij.openapi.editor.event.DocumentAdapter;
import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.editor.event.SelectionEvent;
@@ -29,6 +31,7 @@ import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.vfs.ReadonlyStatusHandler;
import com.intellij.util.Alarm;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
@@ -147,7 +150,7 @@ public class LivePreviewController implements LivePreview.Delegate, FindUtil.Rep
}
@Override
- public String getStringToReplace(Editor editor, FindResult findResult) {
+ public String getStringToReplace(@NotNull Editor editor, @Nullable FindResult findResult) {
if (findResult == null) {
return null;
}
diff --git a/platform/lang-impl/src/com/intellij/ide/RecentDirectoryProjectsManagerEx.java b/platform/lang-impl/src/com/intellij/ide/RecentDirectoryProjectsManagerEx.java
index 21207519fb6b..b9086439906b 100644
--- a/platform/lang-impl/src/com/intellij/ide/RecentDirectoryProjectsManagerEx.java
+++ b/platform/lang-impl/src/com/intellij/ide/RecentDirectoryProjectsManagerEx.java
@@ -29,11 +29,7 @@ import org.jetbrains.annotations.NotNull;
*/
@State(
name = "RecentDirectoryProjectsManager",
- roamingType = RoamingType.DISABLED,
- storages = {
- @Storage(
- file = StoragePathMacros.APP_CONFIG + "/other.xml"
- )}
+ storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/other.xml", roamingType = RoamingType.DISABLED)}
)
public class RecentDirectoryProjectsManagerEx extends RecentDirectoryProjectsManager {
public RecentDirectoryProjectsManagerEx(MessageBus messageBus) {
diff --git a/platform/lang-impl/src/com/intellij/ide/actions/ExternalJavaDocAction.java b/platform/lang-impl/src/com/intellij/ide/actions/ExternalJavaDocAction.java
index 71b02f867d8a..50525bc0e288 100644
--- a/platform/lang-impl/src/com/intellij/ide/actions/ExternalJavaDocAction.java
+++ b/platform/lang-impl/src/com/intellij/ide/actions/ExternalJavaDocAction.java
@@ -131,7 +131,7 @@ public class ExternalJavaDocAction extends AnAction {
}
if (editor != null) {
presentation.setEnabled(enabled);
- if (event.getPlace().equals(ActionPlaces.MAIN_MENU)) {
+ if (ActionPlaces.isMainMenuOrActionSearch(event.getPlace())) {
presentation.setVisible(true);
}
else {
diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java
index e57d1eba05ef..b54a1989e692 100644
--- a/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java
+++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoActionAction.java
@@ -96,7 +96,7 @@ public class GotoActionAction extends GotoActionBase implements DumbAware {
final DataContext context = DataManager.getInstance().getDataContext(component);
final AnActionEvent event = new AnActionEvent(e == null ? null : e.getInputEvent(),
context,
- e == null ? ActionPlaces.UNKNOWN : e.getPlace(),
+ ActionPlaces.ACTION_SEARCH,
presentation,
ActionManager.getInstance(),
e == null ? 0 : e.getModifiers());
diff --git a/platform/lang-impl/src/com/intellij/ide/actions/GotoActionBase.java b/platform/lang-impl/src/com/intellij/ide/actions/GotoActionBase.java
index c109de7a00a9..5da112b375b9 100644
--- a/platform/lang-impl/src/com/intellij/ide/actions/GotoActionBase.java
+++ b/platform/lang-impl/src/com/intellij/ide/actions/GotoActionBase.java
@@ -62,7 +62,7 @@ public abstract class GotoActionBase extends AnAction {
private int myHistoryIndex = 0;
@Override
- public void actionPerformed(AnActionEvent e) {
+ public void actionPerformed(@NotNull AnActionEvent e) {
LOG.assertTrue(!getClass().equals(myInAction));
try {
myInAction = getClass();
@@ -79,7 +79,7 @@ public abstract class GotoActionBase extends AnAction {
protected abstract void gotoActionPerformed(AnActionEvent e);
@Override
- public void update(final AnActionEvent event) {
+ public void update(@NotNull final AnActionEvent event) {
final Presentation presentation = event.getPresentation();
final DataContext dataContext = event.getDataContext();
final Project project = CommonDataKeys.PROJECT.getData(dataContext);
@@ -260,7 +260,7 @@ public abstract class GotoActionBase extends AnAction {
abstract class HistoryAction extends DumbAwareAction {
@Override
- public void update(AnActionEvent e) {
+ public void update(@NotNull AnActionEvent e) {
e.getPresentation().setEnabled(historyEnabled());
}
@@ -277,7 +277,7 @@ public abstract class GotoActionBase extends AnAction {
new HistoryAction() {
@Override
- public void actionPerformed(AnActionEvent e) {
+ public void actionPerformed(@NotNull AnActionEvent e) {
List<String> strings = ourHistory.get(myInAction);
setText(strings);
myHistoryIndex = myHistoryIndex >= strings.size() - 1 ? 0 : myHistoryIndex + 1;
@@ -287,7 +287,7 @@ public abstract class GotoActionBase extends AnAction {
new HistoryAction() {
@Override
- public void actionPerformed(AnActionEvent e) {
+ public void actionPerformed(@NotNull AnActionEvent e) {
List<String> strings = ourHistory.get(myInAction);
setText(strings);
myHistoryIndex = myHistoryIndex <= 0 ? strings.size() - 1 : myHistoryIndex - 1;
diff --git a/platform/lang-impl/src/com/intellij/ide/hierarchy/actions/BrowseCallHierarchyAction.java b/platform/lang-impl/src/com/intellij/ide/hierarchy/actions/BrowseCallHierarchyAction.java
index 853d859f9f82..9350b4b1d73c 100644
--- a/platform/lang-impl/src/com/intellij/ide/hierarchy/actions/BrowseCallHierarchyAction.java
+++ b/platform/lang-impl/src/com/intellij/ide/hierarchy/actions/BrowseCallHierarchyAction.java
@@ -30,7 +30,7 @@ public final class BrowseCallHierarchyAction extends BrowseHierarchyActionBase {
@Override
public final void update(final AnActionEvent event){
final Presentation presentation = event.getPresentation();
- if (!ActionPlaces.MAIN_MENU.equals(event.getPlace())) {
+ if (!ActionPlaces.isMainMenuOrActionSearch(event.getPlace())) {
presentation.setText(IdeBundle.message("action.browse.call.hierarchy"));
}
diff --git a/platform/lang-impl/src/com/intellij/ide/hierarchy/actions/BrowseMethodHierarchyAction.java b/platform/lang-impl/src/com/intellij/ide/hierarchy/actions/BrowseMethodHierarchyAction.java
index 7cd056f7bb16..5a23c6b3925c 100644
--- a/platform/lang-impl/src/com/intellij/ide/hierarchy/actions/BrowseMethodHierarchyAction.java
+++ b/platform/lang-impl/src/com/intellij/ide/hierarchy/actions/BrowseMethodHierarchyAction.java
@@ -30,7 +30,7 @@ public final class BrowseMethodHierarchyAction extends BrowseHierarchyActionBase
@Override
public final void update(final AnActionEvent event){
final Presentation presentation = event.getPresentation();
- if (!ActionPlaces.MAIN_MENU.equals(event.getPlace())) {
+ if (!ActionPlaces.isMainMenuOrActionSearch(event.getPlace())) {
presentation.setText(IdeBundle.message("action.browse.method.hierarchy"));
}
super.update(event);
diff --git a/platform/lang-impl/src/com/intellij/ide/hierarchy/actions/BrowseTypeHierarchyAction.java b/platform/lang-impl/src/com/intellij/ide/hierarchy/actions/BrowseTypeHierarchyAction.java
index 41234ef79679..6ac33fc1047a 100644
--- a/platform/lang-impl/src/com/intellij/ide/hierarchy/actions/BrowseTypeHierarchyAction.java
+++ b/platform/lang-impl/src/com/intellij/ide/hierarchy/actions/BrowseTypeHierarchyAction.java
@@ -30,7 +30,7 @@ public final class BrowseTypeHierarchyAction extends BrowseHierarchyActionBase {
@Override
public final void update(final AnActionEvent event){
final Presentation presentation = event.getPresentation();
- if (!ActionPlaces.MAIN_MENU.equals(event.getPlace())) {
+ if (!ActionPlaces.isMainMenuOrActionSearch(event.getPlace())) {
presentation.setText(IdeBundle.message("action.browse.type.hierarchy"));
}
super.update(event);
diff --git a/platform/lang-impl/src/com/intellij/ide/impl/convert/JDomConvertingUtil.java b/platform/lang-impl/src/com/intellij/ide/impl/convert/JDomConvertingUtil.java
index b2f040064fe4..21e55f9ab089 100644
--- a/platform/lang-impl/src/com/intellij/ide/impl/convert/JDomConvertingUtil.java
+++ b/platform/lang-impl/src/com/intellij/ide/impl/convert/JDomConvertingUtil.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -103,7 +103,7 @@ public class JDomConvertingUtil extends JDomSerializationUtil {
}
public static void copyChildren(Element from, Element to) {
- copyChildren(from, to, Condition.TRUE);
+ copyChildren(from, to, Conditions.<Element>alwaysTrue());
}
public static void copyChildren(Element from, Element to, Condition<Element> filter) {
diff --git a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarListener.java b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarListener.java
index 3fe38cea2ed3..e0a0d946c9c5 100644
--- a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarListener.java
+++ b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/NavBarListener.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,6 +18,8 @@ package com.intellij.ide.navigationToolbar;
import com.intellij.ProjectTopics;
import com.intellij.ide.actions.CopyAction;
import com.intellij.ide.actions.CutAction;
+import com.intellij.ide.ui.LafManager;
+import com.intellij.ide.ui.LafManagerListener;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.actionSystem.ex.AnActionListener;
@@ -57,7 +59,8 @@ import java.util.List;
*/
public class NavBarListener extends WolfTheProblemSolver.ProblemListener
implements ActionListener, FocusListener, FileStatusListener, AnActionListener, FileEditorManagerListener,
- PsiTreeChangeListener, ModuleRootListener, NavBarModelListener, PropertyChangeListener, KeyListener, WindowFocusListener {
+ PsiTreeChangeListener, ModuleRootListener, NavBarModelListener, PropertyChangeListener, KeyListener, WindowFocusListener,
+ LafManagerListener {
private static final String LISTENER = "NavBarListener";
private static final String BUS = "NavBarMessageBus";
private final NavBarPanel myPanel;
@@ -89,6 +92,8 @@ public class NavBarListener extends WolfTheProblemSolver.ProblemListener
if (window != null) {
window.addWindowFocusListener(listener);
}
+ } else {
+ LafManager.getInstance().addLafManagerListener(listener);
}
}
@@ -107,6 +112,7 @@ public class NavBarListener extends WolfTheProblemSolver.ProblemListener
if (connection != null) {
connection.disconnect();
}
+ LafManager.getInstance().removeLafManagerListener(listener);
}
}
@@ -356,15 +362,19 @@ public class NavBarListener extends WolfTheProblemSolver.ProblemListener
}
@Override
- public void windowLostFocus(WindowEvent e) {
- final Window window = e.getWindow();
- final Window oppositeWindow = e.getOppositeWindow();
+ public void lookAndFeelChanged(LafManager source) {
+ myPanel.getNavBarUI().clearItems();
+ myPanel.revalidate();
+ myPanel.repaint();
}
+
//---- Ignored
@Override
- public void windowGainedFocus(WindowEvent e) {
- }
+ public void windowLostFocus(WindowEvent e) {}
+
+ @Override
+ public void windowGainedFocus(WindowEvent e) {}
@Override
public void keyTyped(KeyEvent e) {}
diff --git a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/ui/AbstractNavBarUI.java b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/ui/AbstractNavBarUI.java
index 1201e146869d..5e0f6e58d106 100644
--- a/platform/lang-impl/src/com/intellij/ide/navigationToolbar/ui/AbstractNavBarUI.java
+++ b/platform/lang-impl/src/com/intellij/ide/navigationToolbar/ui/AbstractNavBarUI.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -40,7 +40,7 @@ import java.util.Map;
*/
public abstract class AbstractNavBarUI implements NavBarUI {
- private final Map<NavBarItem, Map<ImageType, BufferedImage>> myCache = new THashMap<NavBarItem, Map<ImageType, BufferedImage>>();
+ private final static Map<NavBarItem, Map<ImageType, BufferedImage>> myCache = new THashMap<NavBarItem, Map<ImageType, BufferedImage>>();
private enum ImageType {
INACTIVE, NEXT_ACTIVE, ACTIVE, INACTIVE_FLOATING, NEXT_ACTIVE_FLOATING, ACTIVE_FLOATING,
diff --git a/platform/lang-impl/src/com/intellij/ide/scratch/CreateScratchFileAction.java b/platform/lang-impl/src/com/intellij/ide/scratch/CreateScratchFileAction.java
index 024c3feabe5e..7a190f6be71c 100644
--- a/platform/lang-impl/src/com/intellij/ide/scratch/CreateScratchFileAction.java
+++ b/platform/lang-impl/src/com/intellij/ide/scratch/CreateScratchFileAction.java
@@ -34,6 +34,7 @@ import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.containers.ContainerUtilRt;
import com.intellij.util.ui.EmptyIcon;
import org.jetbrains.annotations.NotNull;
@@ -136,7 +137,7 @@ public class CreateScratchFileAction extends AnAction implements DumbAware {
@NotNull
public static List<Language> getLanguages() {
- Set<Language> result = ContainerUtil.newTreeSet(new Comparator<Language>() {
+ Set<Language> result = ContainerUtilRt.newTreeSet(new Comparator<Language>() {
@Override
public int compare(@NotNull Language l1, @NotNull Language l2) {
return l1.getDisplayName().compareTo(l2.getDisplayName());
diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java
index 348283dc3885..05d9bb771978 100644
--- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java
+++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java
@@ -40,6 +40,7 @@ import com.intellij.ui.components.JBLabel;
import com.intellij.ui.speedSearch.SpeedSearchUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.containers.ContainerUtilRt;
import com.intellij.util.ui.EmptyIcon;
import com.intellij.util.ui.UIUtil;
import org.apache.oro.text.regex.*;
@@ -492,7 +493,7 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel, C
@NotNull
@Override
public SortedSet<Object> sort(@NotNull Set<Object> elements) {
- TreeSet<Object> objects = ContainerUtil.newTreeSet(this);
+ TreeSet<Object> objects = ContainerUtilRt.newTreeSet(this);
objects.addAll(elements);
return objects;
}
diff --git a/platform/lang-impl/src/com/intellij/ide/util/scopeChooser/ScopeChooserCombo.java b/platform/lang-impl/src/com/intellij/ide/util/scopeChooser/ScopeChooserCombo.java
index 8297a3db8e1f..98190010159b 100644
--- a/platform/lang-impl/src/com/intellij/ide/util/scopeChooser/ScopeChooserCombo.java
+++ b/platform/lang-impl/src/com/intellij/ide/util/scopeChooser/ScopeChooserCombo.java
@@ -29,6 +29,7 @@ import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.module.*;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.vfs.VirtualFile;
@@ -411,21 +412,32 @@ public class ScopeChooserCombo extends ComboboxWithBrowseButton implements Dispo
}
}
- if (dataContext != null) {
- final VirtualFile[] files = CommonDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext);
- if (files != null) {
- final List<VirtualFile> openFiles = Arrays.asList(files);
- result.add(new DelegatingGlobalSearchScope(GlobalSearchScope.filesScope(project, openFiles)){
+ ContainerUtil.addIfNotNull(result, getSelectedFilesScope(project, dataContext));
+
+ return ContainerUtil.newArrayList(result);
+ }
+
+ @Nullable
+ private static SearchScope getSelectedFilesScope(final Project project, @Nullable DataContext dataContext) {
+ final VirtualFile[] filesOrDirs = dataContext == null ? null : CommonDataKeys.VIRTUAL_FILE_ARRAY.getData(dataContext);
+ if (filesOrDirs != null) {
+ final List<VirtualFile> selectedFiles = ContainerUtil.filter(filesOrDirs, new Condition<VirtualFile>() {
+ @Override
+ public boolean value(VirtualFile file) {
+ return !file.isDirectory();
+ }
+ });
+ if (!selectedFiles.isEmpty()) {
+ return new DelegatingGlobalSearchScope(GlobalSearchScope.filesScope(project, selectedFiles)){
@NotNull
@Override
public String getDisplayName() {
return "Selected Files";
}
- });
+ };
}
}
-
- return ContainerUtil.newArrayList(result);
+ return null;
}
protected static Set<VirtualFile> collectFiles(Set<Usage> usages, boolean findFirst) {
diff --git a/platform/lang-impl/src/com/intellij/ide/util/scopeChooser/ScopeChooserConfigurable.java b/platform/lang-impl/src/com/intellij/ide/util/scopeChooser/ScopeChooserConfigurable.java
index 96de48a0db13..a2bf7a47af28 100644
--- a/platform/lang-impl/src/com/intellij/ide/util/scopeChooser/ScopeChooserConfigurable.java
+++ b/platform/lang-impl/src/com/intellij/ide/util/scopeChooser/ScopeChooserConfigurable.java
@@ -81,7 +81,7 @@ public class ScopeChooserConfigurable extends MasterDetailsComponent implements
@Override
protected Dimension getPanelPreferredSize() {
- return new Dimension(-1, -1);
+ return new Dimension(400, 200);
}
@Override
diff --git a/platform/lang-impl/src/com/intellij/lang/customFolding/CustomFoldingRegionsPopup.java b/platform/lang-impl/src/com/intellij/lang/customFolding/CustomFoldingRegionsPopup.java
new file mode 100644
index 000000000000..203179709dae
--- /dev/null
+++ b/platform/lang-impl/src/com/intellij/lang/customFolding/CustomFoldingRegionsPopup.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.lang.customFolding;
+
+import com.intellij.ide.IdeBundle;
+import com.intellij.lang.folding.FoldingDescriptor;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.editor.ScrollType;
+import com.intellij.openapi.fileEditor.ex.IdeDocumentHistory;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.popup.JBPopup;
+import com.intellij.openapi.ui.popup.JBPopupFactory;
+import com.intellij.openapi.ui.popup.PopupChooserBuilder;
+import com.intellij.psi.PsiElement;
+import com.intellij.ui.components.JBList;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.util.*;
+
+/**
+ * @author Rustam Vishnyakov
+ */
+public class CustomFoldingRegionsPopup {
+ private final @NotNull JBList myRegionsList;
+ private final @NotNull JBPopup myPopup;
+ private final @NotNull Editor myEditor;
+
+ CustomFoldingRegionsPopup(@NotNull Collection<FoldingDescriptor> descriptors,
+ @NotNull final Editor editor,
+ @NotNull final Project project) {
+ myEditor = editor;
+ myRegionsList = new JBList();
+ //noinspection unchecked
+ myRegionsList.setModel(new MyListModel(orderByPosition(descriptors)));
+ myRegionsList.setSelectedIndex(0);
+
+ final PopupChooserBuilder popupBuilder = JBPopupFactory.getInstance().createListPopupBuilder(myRegionsList);
+ myPopup = popupBuilder
+ .setTitle(IdeBundle.message("goto.custom.region.command"))
+ .setResizable(false)
+ .setMovable(false)
+ .setItemChoosenCallback(new Runnable() {
+ @Override
+ public void run() {
+ PsiElement navigationElement = getNavigationElement();
+ if (navigationElement != null) {
+ navigateTo(editor, navigationElement);
+ IdeDocumentHistory.getInstance(project).includeCurrentCommandAsNavigation();
+ }
+ }
+ }).createPopup();
+ }
+
+ void show() {
+ myPopup.showInBestPositionFor(myEditor);
+ }
+
+ private static class MyListModel extends DefaultListModel {
+ private MyListModel(Collection<FoldingDescriptor> descriptors) {
+ for (FoldingDescriptor descriptor : descriptors) {
+ //noinspection unchecked
+ super.addElement(new MyFoldingDescriptorWrapper(descriptor));
+ }
+ }
+ }
+
+ private static class MyFoldingDescriptorWrapper {
+ private final @NotNull FoldingDescriptor myDescriptor;
+
+ private MyFoldingDescriptorWrapper(@NotNull FoldingDescriptor descriptor) {
+ myDescriptor = descriptor;
+ }
+
+ @NotNull
+ public FoldingDescriptor getDescriptor() {
+ return myDescriptor;
+ }
+
+ @Nullable
+ @Override
+ public String toString() {
+ return myDescriptor.getPlaceholderText();
+ }
+ }
+
+ @Nullable
+ public PsiElement getNavigationElement() {
+ Object selection = myRegionsList.getSelectedValue();
+ if (selection instanceof MyFoldingDescriptorWrapper) {
+ return ((MyFoldingDescriptorWrapper)selection).getDescriptor().getElement().getPsi();
+ }
+ return null;
+ }
+
+ private static Collection<FoldingDescriptor> orderByPosition(Collection<FoldingDescriptor> descriptors) {
+ List<FoldingDescriptor> sorted = new ArrayList<FoldingDescriptor>(descriptors.size());
+ sorted.addAll(descriptors);
+ Collections.sort(sorted, new Comparator<FoldingDescriptor>() {
+ @Override
+ public int compare(FoldingDescriptor descriptor1, FoldingDescriptor descriptor2) {
+ int pos1 = descriptor1.getElement().getTextRange().getStartOffset();
+ int pos2 = descriptor2.getElement().getTextRange().getStartOffset();
+ return pos1 - pos2;
+ }
+ });
+ return sorted;
+ }
+
+ private static void navigateTo(@NotNull Editor editor, @NotNull PsiElement element) {
+ int offset = element.getTextRange().getStartOffset();
+ if (offset >= 0 && offset < editor.getDocument().getTextLength()) {
+ editor.getCaretModel().removeSecondaryCarets();
+ editor.getCaretModel().moveToOffset(offset);
+ editor.getScrollingModel().scrollToCaret(ScrollType.CENTER);
+ editor.getSelectionModel().removeSelection();
+ }
+ }
+}
diff --git a/platform/lang-impl/src/com/intellij/lang/customFolding/GotoCustomRegionAction.java b/platform/lang-impl/src/com/intellij/lang/customFolding/GotoCustomRegionAction.java
index 016f7f14cc4d..e0117affbcad 100644
--- a/platform/lang-impl/src/com/intellij/lang/customFolding/GotoCustomRegionAction.java
+++ b/platform/lang-impl/src/com/intellij/lang/customFolding/GotoCustomRegionAction.java
@@ -16,26 +16,35 @@
package com.intellij.lang.customFolding;
import com.intellij.ide.IdeBundle;
-import com.intellij.openapi.actionSystem.AnAction;
-import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.actionSystem.CommonDataKeys;
-import com.intellij.openapi.actionSystem.PlatformDataKeys;
-import com.intellij.openapi.actionSystem.Presentation;
+import com.intellij.lang.Language;
+import com.intellij.lang.folding.*;
+import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.command.CommandProcessor;
+import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
-import com.intellij.openapi.editor.ScrollType;
-import com.intellij.openapi.fileEditor.ex.IdeDocumentHistory;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
-import com.intellij.psi.PsiElement;
+import com.intellij.openapi.ui.MessageType;
+import com.intellij.openapi.ui.popup.Balloon;
+import com.intellij.openapi.ui.popup.JBPopupFactory;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.psi.FileViewProvider;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.PsiFile;
+import com.intellij.util.containers.HashSet;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Collection;
+import java.util.Set;
/**
* @author Rustam Vishnyakov
*/
-public class GotoCustomRegionAction extends AnAction implements DumbAware {
+public class GotoCustomRegionAction extends AnAction implements DumbAware, PopupAction {
@Override
- public void actionPerformed(AnActionEvent e) {
+ public void actionPerformed(final AnActionEvent e) {
final Project project = e.getProject();
final Editor editor = e.getData(CommonDataKeys.EDITOR);
if (Boolean.TRUE.equals(e.getData(PlatformDataKeys.IS_MODAL_CONTEXT))) {
@@ -52,14 +61,13 @@ public class GotoCustomRegionAction extends AnAction implements DumbAware {
new Runnable() {
@Override
public void run() {
- GotoCustomRegionDialog dialog = new GotoCustomRegionDialog(project, editor);
- dialog.show();
- if (dialog.isOK()) {
- PsiElement navigationElement = dialog.getNavigationElement();
- if (navigationElement != null) {
- navigateTo(editor, navigationElement);
- IdeDocumentHistory.getInstance(project).includeCurrentCommandAsNavigation();
- }
+ Collection<FoldingDescriptor> foldingDescriptors = getCustomFoldingDescriptors(editor, project);
+ if (foldingDescriptors.size() > 0) {
+ CustomFoldingRegionsPopup regionsPopup = new CustomFoldingRegionsPopup(foldingDescriptors, editor, project);
+ regionsPopup.show();
+ }
+ else {
+ notifyCustomRegionsUnavailable(editor, project);
}
}
},
@@ -71,7 +79,7 @@ public class GotoCustomRegionAction extends AnAction implements DumbAware {
@Override
public void update(AnActionEvent e) {
Presentation presentation = e.getPresentation();
- presentation.setText("Custom Region...");
+ presentation.setText(IdeBundle.message("goto.custom.region.menu.item"));
final Editor editor = e.getData(CommonDataKeys.EDITOR);
final Project project = e.getProject();
boolean isAvailable = editor != null && project != null;
@@ -79,13 +87,49 @@ public class GotoCustomRegionAction extends AnAction implements DumbAware {
presentation.setVisible(isAvailable);
}
- private static void navigateTo(Editor editor, PsiElement element) {
- int offset = element.getTextRange().getStartOffset();
- if (offset >= 0 && offset < editor.getDocument().getTextLength()) {
- editor.getCaretModel().removeSecondaryCarets();
- editor.getCaretModel().moveToOffset(offset);
- editor.getScrollingModel().scrollToCaret(ScrollType.CENTER);
- editor.getSelectionModel().removeSelection();
+ @NotNull
+ private static Collection<FoldingDescriptor> getCustomFoldingDescriptors(@NotNull Editor editor, @NotNull Project project) {
+ Set<FoldingDescriptor> foldingDescriptors = new HashSet<FoldingDescriptor>();
+ final Document document = editor.getDocument();
+ PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project);
+ PsiFile file = documentManager != null ? documentManager.getPsiFile(document) : null;
+ if (file != null) {
+ final FileViewProvider viewProvider = file.getViewProvider();
+ for (final Language language : viewProvider.getLanguages()) {
+ final PsiFile psi = viewProvider.getPsi(language);
+ final FoldingBuilder foldingBuilder = LanguageFolding.INSTANCE.forLanguage(language);
+ if (psi != null) {
+ for (FoldingDescriptor descriptor : LanguageFolding.buildFoldingDescriptors(foldingBuilder, psi, document, false)) {
+ CustomFoldingBuilder customFoldingBuilder = getCustomFoldingBuilder(foldingBuilder, descriptor);
+ if (customFoldingBuilder != null) {
+ if (customFoldingBuilder.isCustomRegionStart(descriptor.getElement())) {
+ foldingDescriptors.add(descriptor);
+ }
+ }
+ }
+ }
+ }
}
+ return foldingDescriptors;
+ }
+
+ @Nullable
+ private static CustomFoldingBuilder getCustomFoldingBuilder(FoldingBuilder builder, FoldingDescriptor descriptor) {
+ if (builder instanceof CustomFoldingBuilder) return (CustomFoldingBuilder)builder;
+ FoldingBuilder originalBuilder = descriptor.getElement().getUserData(CompositeFoldingBuilder.FOLDING_BUILDER);
+ if (originalBuilder instanceof CustomFoldingBuilder) return (CustomFoldingBuilder)originalBuilder;
+ return null;
+ }
+
+ private static void notifyCustomRegionsUnavailable(@NotNull Editor editor, @NotNull Project project) {
+ final JBPopupFactory popupFactory = JBPopupFactory.getInstance();
+ Balloon balloon = popupFactory
+ .createHtmlTextBalloonBuilder(IdeBundle.message("goto.custom.region.message.unavailable"), MessageType.INFO, null)
+ .setFadeoutTime(2000)
+ .setHideOnClickOutside(true)
+ .setHideOnKeyOutside(true)
+ .createBalloon();
+ Disposer.register(project, balloon);
+ balloon.show(popupFactory.guessBestPopupLocation(editor), Balloon.Position.above);
}
}
diff --git a/platform/lang-impl/src/com/intellij/lang/customFolding/GotoCustomRegionDialog.form b/platform/lang-impl/src/com/intellij/lang/customFolding/GotoCustomRegionDialog.form
deleted file mode 100644
index c155616c8186..000000000000
--- a/platform/lang-impl/src/com/intellij/lang/customFolding/GotoCustomRegionDialog.form
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.lang.customFolding.GotoCustomRegionDialog">
- <grid id="27dc6" binding="myContentPane" layout-manager="BorderLayout" hgap="0" vgap="0">
- <constraints>
- <xy x="20" y="20" width="500" height="400"/>
- </constraints>
- <properties/>
- <border type="none"/>
- <children>
- <scrollpane id="7557d" class="com.intellij.ui.components.JBScrollPane" binding="myScrollPane" custom-create="true">
- <constraints border-constraint="Center"/>
- <properties/>
- <border type="none"/>
- <children>
- <component id="2f5d5" class="com.intellij.ui.components.JBList" binding="myRegionsList" custom-create="true">
- <constraints/>
- <properties>
- <selectionMode value="0"/>
- </properties>
- </component>
- </children>
- </scrollpane>
- </children>
- </grid>
-</form>
diff --git a/platform/lang-impl/src/com/intellij/lang/customFolding/GotoCustomRegionDialog.java b/platform/lang-impl/src/com/intellij/lang/customFolding/GotoCustomRegionDialog.java
deleted file mode 100644
index 49d63dfe24b9..000000000000
--- a/platform/lang-impl/src/com/intellij/lang/customFolding/GotoCustomRegionDialog.java
+++ /dev/null
@@ -1,169 +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.lang.customFolding;
-
-import com.intellij.ide.IdeBundle;
-import com.intellij.lang.Language;
-import com.intellij.lang.folding.*;
-import com.intellij.openapi.editor.Document;
-import com.intellij.openapi.editor.Editor;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.ui.DialogWrapper;
-import com.intellij.psi.FileViewProvider;
-import com.intellij.psi.PsiDocumentManager;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiFile;
-import com.intellij.ui.components.JBList;
-import com.intellij.ui.components.JBScrollPane;
-import com.intellij.util.containers.HashSet;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import javax.swing.*;
-import java.awt.*;
-import java.util.*;
-import java.util.List;
-
-/**
- * @author Rustam Vishnyakov
- */
-public class GotoCustomRegionDialog extends DialogWrapper {
- private JBList myRegionsList;
- private JPanel myContentPane;
- private JBScrollPane myScrollPane;
- private final Editor myEditor;
- private final Project myProject;
-
- protected GotoCustomRegionDialog(@Nullable Project project, @NotNull Editor editor) {
- super(project);
- myEditor = editor;
- myProject = project;
- Collection<FoldingDescriptor> descriptors = getCustomFoldingDescriptors();
- init();
- if (descriptors.size() == 0) {
- myScrollPane.setVisible(false);
- myContentPane.add(new JLabel(IdeBundle.message("goto.custom.region.message.unavailable")), BorderLayout.NORTH);
- setOKActionEnabled(false);
- }
- else {
- myRegionsList.setModel(new MyListModel(orderByPosition(descriptors)));
- myRegionsList.setSelectedIndex(0);
- }
- setTitle(IdeBundle.message("goto.custom.region.command"));
- }
-
- @Override
- public JComponent getPreferredFocusedComponent() {
- if (!myRegionsList.isEmpty()) {
- return myRegionsList;
- }
- return super.getPreferredFocusedComponent();
- }
-
- @Override
- protected JComponent createCenterPanel() {
- return myContentPane;
- }
-
- private Collection<FoldingDescriptor> getCustomFoldingDescriptors() {
- Set<FoldingDescriptor> foldingDescriptors = new HashSet<FoldingDescriptor>();
- final Document document = myEditor.getDocument();
- PsiDocumentManager documentManager = PsiDocumentManager.getInstance(myProject);
- PsiFile file = documentManager != null ? documentManager.getPsiFile(document) : null;
- if (file != null) {
- final FileViewProvider viewProvider = file.getViewProvider();
- for (final Language language : viewProvider.getLanguages()) {
- final PsiFile psi = viewProvider.getPsi(language);
- final FoldingBuilder foldingBuilder = LanguageFolding.INSTANCE.forLanguage(language);
- if (psi != null) {
- for (FoldingDescriptor descriptor : LanguageFolding.buildFoldingDescriptors(foldingBuilder, psi, document, false)) {
- CustomFoldingBuilder customFoldingBuilder = getCustomFoldingBuilder(foldingBuilder, descriptor);
- if (customFoldingBuilder != null) {
- if (customFoldingBuilder.isCustomRegionStart(descriptor.getElement())) {
- foldingDescriptors.add(descriptor);
- }
- }
- }
- }
- }
- }
- return foldingDescriptors;
- }
-
- private static Collection<FoldingDescriptor> orderByPosition(Collection<FoldingDescriptor> descriptors) {
- List<FoldingDescriptor> sorted = new ArrayList<FoldingDescriptor>(descriptors.size());
- sorted.addAll(descriptors);
- Collections.sort(sorted, new Comparator<FoldingDescriptor>() {
- @Override
- public int compare(FoldingDescriptor descriptor1, FoldingDescriptor descriptor2) {
- int pos1 = descriptor1.getElement().getTextRange().getStartOffset();
- int pos2 = descriptor2.getElement().getTextRange().getStartOffset();
- return pos1 - pos2;
- }
- });
- return sorted;
- }
-
- private void createUIComponents() {
- myRegionsList = new JBList();
- myScrollPane = new JBScrollPane(myRegionsList);
- }
-
- @Nullable
- private static CustomFoldingBuilder getCustomFoldingBuilder(FoldingBuilder builder, FoldingDescriptor descriptor) {
- if (builder instanceof CustomFoldingBuilder) return (CustomFoldingBuilder)builder;
- FoldingBuilder originalBuilder = descriptor.getElement().getUserData(CompositeFoldingBuilder.FOLDING_BUILDER);
- if (originalBuilder instanceof CustomFoldingBuilder) return (CustomFoldingBuilder)originalBuilder;
- return null;
- }
-
-
- private static class MyListModel extends DefaultListModel {
- private MyListModel(Collection<FoldingDescriptor> descriptors) {
- for (FoldingDescriptor descriptor : descriptors) {
- super.addElement(new MyFoldingDescriptorWrapper(descriptor));
- }
- }
- }
-
- private static class MyFoldingDescriptorWrapper {
- private final @NotNull FoldingDescriptor myDescriptor;
-
- private MyFoldingDescriptorWrapper(@NotNull FoldingDescriptor descriptor) {
- myDescriptor = descriptor;
- }
-
- @NotNull
- public FoldingDescriptor getDescriptor() {
- return myDescriptor;
- }
-
- @Nullable
- @Override
- public String toString() {
- return myDescriptor.getPlaceholderText();
- }
- }
-
- @Nullable
- public PsiElement getNavigationElement() {
- Object selection = myRegionsList.getSelectedValue();
- if (selection instanceof MyFoldingDescriptorWrapper) {
- return ((MyFoldingDescriptorWrapper)selection).getDescriptor().getElement().getPsi();
- }
- return null;
- }
-}
diff --git a/platform/lang-impl/src/com/intellij/openapi/components/impl/stores/ModuleStoreImpl.java b/platform/lang-impl/src/com/intellij/openapi/components/impl/stores/ModuleStoreImpl.java
index e35319819e32..216f368d4a1d 100644
--- a/platform/lang-impl/src/com/intellij/openapi/components/impl/stores/ModuleStoreImpl.java
+++ b/platform/lang-impl/src/com/intellij/openapi/components/impl/stores/ModuleStoreImpl.java
@@ -29,25 +29,26 @@ import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ArrayUtil;
+import com.intellij.util.PathUtilRt;
import gnu.trove.THashMap;
import org.jdom.Attribute;
import org.jdom.Element;
-import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
-import java.util.*;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
public class ModuleStoreImpl extends BaseFileConfigurableStoreImpl implements IModuleStore {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.components.impl.stores.ModuleStoreImpl");
- @NonNls private static final String MODULE_FILE_MACRO = "MODULE_FILE";
private final ModuleImpl myModule;
- public static final String DEFAULT_STATE_STORAGE = "$" + MODULE_FILE_MACRO + "$";
-
+ public static final String DEFAULT_STATE_STORAGE = "$MODULE_FILE$";
@SuppressWarnings({"UnusedDeclaration"})
public ModuleStoreImpl(final ComponentManagerImpl componentManager, final ModuleImpl module) {
@@ -56,8 +57,8 @@ public class ModuleStoreImpl extends BaseFileConfigurableStoreImpl implements IM
}
@Override
- protected XmlElementStorage getMainStorage() {
- final XmlElementStorage storage = (XmlElementStorage)getStateStorageManager().getFileStateStorage(DEFAULT_STATE_STORAGE);
+ protected FileBasedStorage getMainStorage() {
+ FileBasedStorage storage = (FileBasedStorage)getStateStorageManager().getStateStorage(DEFAULT_STATE_STORAGE, RoamingType.PER_USER);
assert storage != null;
return storage;
}
@@ -116,8 +117,8 @@ public class ModuleStoreImpl extends BaseFileConfigurableStoreImpl implements IM
}
@Override
- public void load(@NotNull final Element rootElement) throws IOException {
- super.load(rootElement);
+ public void load(@NotNull Element rootElement, @Nullable PathMacroSubstitutor pathMacroSubstitutor, boolean intern) {
+ super.load(rootElement, pathMacroSubstitutor, intern);
for (Attribute attribute : rootElement.getAttributes()) {
myOptions.put(attribute.getName(), attribute.getValue());
@@ -132,8 +133,7 @@ public class ModuleStoreImpl extends BaseFileConfigurableStoreImpl implements IM
@Override
@NotNull
protected Element save() {
- final Element root = super.save();
-
+ Element root = super.save();
myOptions.put(VERSION_OPTION, Integer.toString(myVersion));
String[] options = ArrayUtil.toStringArray(myOptions.keySet());
Arrays.sort(options);
@@ -187,31 +187,25 @@ public class ModuleStoreImpl extends BaseFileConfigurableStoreImpl implements IM
LocalFileSystem.getInstance().refreshAndFindFileByPath(path);
final StateStorageManager storageManager = getStateStorageManager();
storageManager.clearStateStorage(DEFAULT_STATE_STORAGE);
- storageManager.addMacro(MODULE_FILE_MACRO, path);
+ storageManager.addMacro(DEFAULT_STATE_STORAGE, path);
}
@Override
@Nullable
public VirtualFile getModuleFile() {
- final FileBasedStorage storage = (FileBasedStorage)getStateStorageManager().getFileStateStorage(DEFAULT_STATE_STORAGE);
- assert storage != null;
- return storage.getVirtualFile();
+ return getMainStorage().getVirtualFile();
}
@Override
@NotNull
public String getModuleFilePath() {
- final FileBasedStorage storage = (FileBasedStorage)getStateStorageManager().getFileStateStorage(DEFAULT_STATE_STORAGE);
- assert storage != null;
- return storage.getFilePath();
+ return getMainStorage().getFilePath();
}
@Override
@NotNull
public String getModuleFileName() {
- final FileBasedStorage storage = (FileBasedStorage)getStateStorageManager().getFileStateStorage(DEFAULT_STATE_STORAGE);
- assert storage != null;
- return storage.getFileName();
+ return PathUtilRt.getFileName(getMainStorage().getFilePath());
}
@Override
diff --git a/platform/lang-impl/src/com/intellij/openapi/components/impl/stores/ProjectWithModulesStoreImpl.java b/platform/lang-impl/src/com/intellij/openapi/components/impl/stores/ProjectWithModulesStoreImpl.java
index eb03fa86fdab..c109c8c0e14d 100644
--- a/platform/lang-impl/src/com/intellij/openapi/components/impl/stores/ProjectWithModulesStoreImpl.java
+++ b/platform/lang-impl/src/com/intellij/openapi/components/impl/stores/ProjectWithModulesStoreImpl.java
@@ -25,10 +25,10 @@ import com.intellij.openapi.module.impl.ModuleImpl;
import com.intellij.openapi.project.impl.ProjectImpl;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.util.io.fs.IFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -102,15 +102,13 @@ public class ProjectWithModulesStoreImpl extends ProjectStoreImpl {
@NotNull
@Override
- public List<IFile> getAllStorageFiles(final boolean includingSubStructures) {
- final List<IFile> result = super.getAllStorageFiles(includingSubStructures);
-
+ public List<File> getAllStorageFiles(final boolean includingSubStructures) {
+ List<File> result = super.getAllStorageFiles(includingSubStructures);
if (includingSubStructures) {
for (SaveSession moduleSaveSession : myModuleSaveSessions) {
result.addAll(moduleSaveSession.getAllStorageFiles(true));
}
}
-
return result;
}
@@ -172,10 +170,9 @@ public class ProjectWithModulesStoreImpl extends ProjectStoreImpl {
}
@Override
- protected void collectSubfilesToSave(final List<IFile> result) throws IOException {
+ protected void collectSubFilesToSave(final List<File> result) throws IOException {
for (SaveSession moduleSaveSession : myModuleSaveSessions) {
- final List<IFile> moduleFiles = moduleSaveSession.getAllStorageFilesToSave(true);
- result.addAll(moduleFiles);
+ result.addAll(moduleSaveSession.getAllStorageFilesToSave(true));
}
}
}
diff --git a/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/PsiAwareFileEditorManagerImpl.java b/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/PsiAwareFileEditorManagerImpl.java
index 7713734d07de..eaed20f2960d 100644
--- a/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/PsiAwareFileEditorManagerImpl.java
+++ b/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/PsiAwareFileEditorManagerImpl.java
@@ -102,8 +102,9 @@ public class PsiAwareFileEditorManagerImpl extends FileEditorManagerImpl {
return myProblemSolver.isProblemFile(file);
}
+ @NotNull
@Override
- public String getFileTooltipText(final VirtualFile file) {
+ public String getFileTooltipText(@NotNull final VirtualFile file) {
final StringBuilder tooltipText = new StringBuilder();
final Module module = ModuleUtilCore.findModuleForFile(file, getProject());
if (module != null) {
@@ -116,7 +117,7 @@ public class PsiAwareFileEditorManagerImpl extends FileEditorManagerImpl {
}
@Override
- protected Editor getOpenedEditor(final Editor editor, final boolean focusEditor) {
+ protected Editor getOpenedEditor(@NotNull final Editor editor, final boolean focusEditor) {
PsiDocumentManager documentManager = PsiDocumentManager.getInstance(getProject());
Document document = editor.getDocument();
PsiFile psiFile = documentManager.getPsiFile(document);
@@ -200,7 +201,7 @@ public class PsiAwareFileEditorManagerImpl extends FileEditorManagerImpl {
updateFile(file);
}
- private void updateFile(final VirtualFile file) {
+ private void updateFile(@NotNull VirtualFile file) {
queueUpdateFile(file);
}
}
diff --git a/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/TestEditorManagerImpl.java b/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/TestEditorManagerImpl.java
index 79ac777a6fd8..958daee0098a 100644
--- a/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/TestEditorManagerImpl.java
+++ b/platform/lang-impl/src/com/intellij/openapi/fileEditor/impl/TestEditorManagerImpl.java
@@ -38,6 +38,7 @@ import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.testFramework.LightVirtualFile;
+import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.HashMap;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
@@ -195,7 +196,7 @@ public class TestEditorManagerImpl extends FileEditorManagerEx implements Applic
return openTextEditor(descriptor, false);
}
- private FileEditorProvider getProvider(FileEditor editor) {
+ private static FileEditorProvider getProvider(FileEditor editor) {
return new FileEditorProvider() {
@Override
public boolean accept(@NotNull Project project, @NotNull VirtualFile file) {
@@ -205,18 +206,17 @@ public class TestEditorManagerImpl extends FileEditorManagerEx implements Applic
@Override
@NotNull
public FileEditor createEditor(@NotNull Project project, @NotNull VirtualFile file) {
- return null;
+ throw new IncorrectOperationException();
}
@Override
public void disposeEditor(@NotNull FileEditor editor) {
- //Disposer.dispose(editor);
}
@Override
@NotNull
public FileEditorState readState(@NotNull Element sourceElement, @NotNull Project project, @NotNull VirtualFile file) {
- return null;
+ throw new IncorrectOperationException();
}
@Override
@@ -233,7 +233,7 @@ public class TestEditorManagerImpl extends FileEditorManagerEx implements Applic
@Override
@NotNull
public FileEditorPolicy getPolicy() {
- return null;
+ throw new IncorrectOperationException();
}
};
}
@@ -482,7 +482,7 @@ public class TestEditorManagerImpl extends FileEditorManagerEx implements Applic
@NotNull
@Override
public EditorsSplitters getSplitters() {
- return null;
+ throw new IncorrectOperationException();
}
@NotNull
@@ -492,6 +492,6 @@ public class TestEditorManagerImpl extends FileEditorManagerEx implements Applic
}
@Override
- public void setSelectedEditor(@NotNull VirtualFile file, String fileEditorProviderId) {
+ public void setSelectedEditor(@NotNull VirtualFile file, @NotNull String fileEditorProviderId) {
}
}
diff --git a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/ProjectJdkTableImpl.java b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/ProjectJdkTableImpl.java
index d5becac99ede..d36fe1b1e05d 100644
--- a/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/ProjectJdkTableImpl.java
+++ b/platform/lang-impl/src/com/intellij/openapi/projectRoots/impl/ProjectJdkTableImpl.java
@@ -41,12 +41,8 @@ import java.util.List;
import java.util.Map;
@State(
- name="ProjectJdkTable",
- roamingType = RoamingType.DISABLED,
- storages= {
- @Storage(
- file = StoragePathMacros.APP_CONFIG + "/jdk.table.xml"
- )}
+ name = "ProjectJdkTable",
+ storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/jdk.table.xml", roamingType = RoamingType.DISABLED)}
)
public class ProjectJdkTableImpl extends ProjectJdkTable implements PersistentStateComponent<Element>, ExportableComponent {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.projectRoots.impl.ProjectJdkTableImpl");
diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/impl/libraries/ExportableApplicationLibraryTable.java b/platform/lang-impl/src/com/intellij/openapi/roots/impl/libraries/ExportableApplicationLibraryTable.java
index 4be66eedde76..c3bed20a5052 100644
--- a/platform/lang-impl/src/com/intellij/openapi/roots/impl/libraries/ExportableApplicationLibraryTable.java
+++ b/platform/lang-impl/src/com/intellij/openapi/roots/impl/libraries/ExportableApplicationLibraryTable.java
@@ -27,10 +27,7 @@ import java.io.File;
*/
@State(
name = "libraryTable",
- roamingType = RoamingType.DISABLED,
- storages = {
- @Storage( file = StoragePathMacros.APP_CONFIG + "/applicationLibraries.xml")
- }
+ storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/applicationLibraries.xml", roamingType = RoamingType.DISABLED)}
)
public class ExportableApplicationLibraryTable extends ApplicationLibraryTable implements ExportableComponent {
@Override
diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/impl/storage/ClasspathStorage.java b/platform/lang-impl/src/com/intellij/openapi/roots/impl/storage/ClasspathStorage.java
index b1f034d2dcb2..36e344ff0acc 100644
--- a/platform/lang-impl/src/com/intellij/openapi/roots/impl/storage/ClasspathStorage.java
+++ b/platform/lang-impl/src/com/intellij/openapi/roots/impl/storage/ClasspathStorage.java
@@ -39,8 +39,6 @@ import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.*;
import com.intellij.openapi.vfs.tracker.VirtualFileTracker;
import com.intellij.util.containers.ContainerUtil;
-import com.intellij.util.io.fs.FileSystem;
-import com.intellij.util.io.fs.IFile;
import com.intellij.util.messages.MessageBus;
import org.jdom.Element;
import org.jetbrains.annotations.Nls;
@@ -104,7 +102,7 @@ public class ClasspathStorage implements StateStorage {
@Override
@Nullable
- public <T> T getState(final Object component, final String componentName, Class<T> stateClass, @Nullable T mergeInto)
+ public <T> T getState(final Object component, @NotNull final String componentName, Class<T> stateClass, @Nullable T mergeInto)
throws StateStorageException {
assert component instanceof ModuleRootManager;
assert componentName.equals("NewModuleRootManager");
@@ -144,7 +142,7 @@ public class ClasspathStorage implements StateStorage {
}
@Override
- public boolean hasState(final Object component, final String componentName, final Class<?> aClass, final boolean reloadData)
+ public boolean hasState(final Object component, @NotNull final String componentName, final Class<?> aClass, final boolean reloadData)
throws StateStorageException {
return true;
}
@@ -192,10 +190,9 @@ public class ClasspathStorage implements StateStorage {
return session;
}
- private static void convert2Io(List<IFile> list, ArrayList<VirtualFile> virtualFiles) {
+ private static void convert2Io(List<File> list, ArrayList<VirtualFile> virtualFiles) {
for (VirtualFile virtualFile : virtualFiles) {
- final File ioFile = VfsUtilCore.virtualToIoFile(virtualFile);
- list.add(FileSystem.FILE_SYSTEM.createFile(ioFile.getAbsolutePath()));
+ list.add(VfsUtilCore.virtualToIoFile(virtualFile));
}
}
@@ -384,12 +381,12 @@ public class ClasspathStorage implements StateStorage {
}
@Override
- public Set<String> getClasspath(final ModifiableRootModel model, final Element element) throws IOException, InvalidDataException {
+ public Set<String> getClasspath(final ModifiableRootModel model, final Element element) throws InvalidDataException {
throw new InvalidDataException(getDescription());
}
@Override
- public void setClasspath(ModuleRootModel model) throws IOException, WriteExternalException {
+ public void setClasspath(ModuleRootModel model) throws WriteExternalException {
throw new WriteExternalException(getDescription());
}
};
@@ -426,9 +423,9 @@ public class ClasspathStorage implements StateStorage {
@NotNull
@Override
- public Collection<IFile> getStorageFilesToSave() throws StateStorageException {
+ public Collection<File> getStorageFilesToSave() throws StateStorageException {
if (needsSave()) {
- final List<IFile> list = new ArrayList<IFile>();
+ final List<File> list = new ArrayList<File>();
final ArrayList<VirtualFile> virtualFiles = new ArrayList<VirtualFile>();
getFileSet().listModifiedFiles(virtualFiles);
convert2Io(list, virtualFiles);
@@ -441,9 +438,9 @@ public class ClasspathStorage implements StateStorage {
@NotNull
@Override
- public List<IFile> getAllStorageFiles() {
- final List<IFile> list = new ArrayList<IFile>();
- final ArrayList<VirtualFile> virtualFiles = new ArrayList<VirtualFile>();
+ public List<File> getAllStorageFiles() {
+ List<File> list = new ArrayList<File>();
+ ArrayList<VirtualFile> virtualFiles = new ArrayList<VirtualFile>();
getFileSet().listFiles(virtualFiles);
convert2Io(list, virtualFiles);
return list;
diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/libraries/ui/impl/RootDetectionUtil.java b/platform/lang-impl/src/com/intellij/openapi/roots/libraries/ui/impl/RootDetectionUtil.java
index 5a3efe1a31b7..ca273ba2373d 100644
--- a/platform/lang-impl/src/com/intellij/openapi/roots/libraries/ui/impl/RootDetectionUtil.java
+++ b/platform/lang-impl/src/com/intellij/openapi/roots/libraries/ui/impl/RootDetectionUtil.java
@@ -70,7 +70,7 @@ public class RootDetectionUtil {
try {
for (VirtualFile rootCandidate : rootCandidates) {
final Collection<DetectedLibraryRoot> roots = detector.detectRoots(rootCandidate, indicator);
- if (!roots.isEmpty() && allRootsHaveOneTypeAndEqualTo(roots, rootCandidate)) {
+ if (!roots.isEmpty() && allRootsHaveOneTypeAndEqualToOrAreDirectParentOf(roots, rootCandidate)) {
for (DetectedLibraryRoot root : roots) {
final LibraryRootType libraryRootType = root.getTypes().get(0);
result.add(new OrderRoot(root.getFile(), libraryRootType.getType(), libraryRootType.isJarDirectory()));
@@ -81,7 +81,7 @@ public class RootDetectionUtil {
final HashMap<LibraryRootType, String> names = new HashMap<LibraryRootType, String>();
for (LibraryRootType type : root.getTypes()) {
final String typeName = detector.getRootTypeName(type);
- LOG.assertTrue(typeName != null, "Unexpected root type " + type.getType().name() + (type.isJarDirectory() ? " (jar directory)" : "") + ", detectors: " + detector);
+ LOG.assertTrue(typeName != null, "Unexpected root type " + type.getType().name() + (type.isJarDirectory() ? " (JAR directory)" : "") + ", detectors: " + detector);
names.put(type, typeName);
}
suggestedRoots.add(new SuggestedChildRootInfo(rootCandidate, root, names));
@@ -141,9 +141,9 @@ public class RootDetectionUtil {
return result;
}
- private static boolean allRootsHaveOneTypeAndEqualTo(Collection<DetectedLibraryRoot> roots, VirtualFile candidate) {
+ private static boolean allRootsHaveOneTypeAndEqualToOrAreDirectParentOf(Collection<DetectedLibraryRoot> roots, VirtualFile candidate) {
for (DetectedLibraryRoot root : roots) {
- if (root.getTypes().size() > 1 || !root.getFile().equals(candidate)) {
+ if (root.getTypes().size() > 1 || !root.getFile().equals(candidate) && !root.getFile().equals(candidate.getParent())) {
return false;
}
}
diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ModulesAlphaComparator.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ModulesAlphaComparator.java
index 8a561e4003b4..61a5c71861c3 100644
--- a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ModulesAlphaComparator.java
+++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/ModulesAlphaComparator.java
@@ -29,8 +29,9 @@ public class ModulesAlphaComparator implements Comparator<Module>{
@Override
public int compare(Module module1, Module module2) {
- final String name1 = module1.getName();
- final String name2 = module2.getName();
- return name1.compareToIgnoreCase(name2);
+ if (module1 == null && module2 == null) return 0;
+ if (module1 == null && module2 != null) return -1;
+ if (module1 != null && module2 == null) return 1;
+ return module1.getName().compareToIgnoreCase(module2.getName());
}
}
diff --git a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ProjectSdksModel.java b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ProjectSdksModel.java
index e4c690ec05ed..87df147a745f 100644
--- a/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ProjectSdksModel.java
+++ b/platform/lang-impl/src/com/intellij/openapi/roots/ui/configuration/projectRoot/ProjectSdksModel.java
@@ -86,6 +86,15 @@ public class ProjectSdksModel implements SdkModel {
}
public void reset(@Nullable Project project) {
+ resetSdkModel();
+ if (project != null) {
+ myProjectSdk = findSdk(ProjectRootManager.getInstance(project).getProjectSdkName());
+ }
+ myModified = false;
+ myInitialized = true;
+ }
+
+ private void resetSdkModel() {
myProjectSdks.clear();
final Sdk[] projectSdks = ProjectJdkTable.getInstance().getAllJdks();
for (Sdk sdk : projectSdks) {
@@ -96,11 +105,6 @@ public class ProjectSdksModel implements SdkModel {
LOG.error(e);
}
}
- if (project != null) {
- myProjectSdk = findSdk(ProjectRootManager.getInstance(project).getProjectSdkName());
- }
- myModified = false;
- myInitialized = true;
}
public void disposeUIResources() {
@@ -154,6 +158,7 @@ public class ProjectSdksModel implements SdkModel {
for (Sdk originalJdk : itemsInTable) {
final Sdk modifiedJdk = myProjectSdks.get(originalJdk);
LOG.assertTrue(modifiedJdk != null);
+ LOG.assertTrue(originalJdk != modifiedJdk);
jdkTable.updateJdk(originalJdk, modifiedJdk);
}
// Add new items to table
@@ -166,6 +171,7 @@ public class ProjectSdksModel implements SdkModel {
}
}
});
+ resetSdkModel();
myModified = false;
}
diff --git a/platform/lang-impl/src/com/intellij/openapi/util/registry/RegistryUi.java b/platform/lang-impl/src/com/intellij/openapi/util/registry/RegistryUi.java
index 65f2d758fcfd..a30ccd677682 100644
--- a/platform/lang-impl/src/com/intellij/openapi/util/registry/RegistryUi.java
+++ b/platform/lang-impl/src/com/intellij/openapi/util/registry/RegistryUi.java
@@ -471,9 +471,10 @@ public class RegistryUi implements Disposable {
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
myValue = ((MyTableModel)table.getModel()).getRegistryValue(row);
if (myValue.asColor(null) != null) {
- final Color color = ColorChooser.chooseColor(table, "Choose color", ((RegistryValue)value).asColor(Color.WHITE));
+ final Color color = ColorChooser.chooseColor(table, "Choose color", myValue.asColor(Color.WHITE));
if (color != null) {
myValue.setValue(color.getRed() + "," + color.getGreen() + "," + color.getBlue());
+ keyChanged(myValue.getKey());
}
return null;
} else if (myValue.isBoolean()) {
diff --git a/platform/lang-impl/src/com/intellij/openapi/wm/impl/status/TogglePopupHintsPanel.java b/platform/lang-impl/src/com/intellij/openapi/wm/impl/status/TogglePopupHintsPanel.java
index b30661e6e840..a83f0b5703da 100644
--- a/platform/lang-impl/src/com/intellij/openapi/wm/impl/status/TogglePopupHintsPanel.java
+++ b/platform/lang-impl/src/com/intellij/openapi/wm/impl/status/TogglePopupHintsPanel.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -125,21 +125,21 @@ public class TogglePopupHintsPanel extends EditorBasedWidget implements StatusBa
if (isStateChangeable(file)) {
if (PowerSaveMode.isEnabled()) {
myCurrentIcon = AllIcons.Ide.HectorNo;
- myToolTipText = "Code analysis is disabled in power save mode. ";
+ myToolTipText = "Code analysis is disabled in power save mode.\n";
}
else if (HighlightingLevelManager.getInstance(myProject).shouldInspect(file)) {
myCurrentIcon = AllIcons.Ide.HectorOn;
myToolTipText = "Current inspection profile: " +
InspectionProjectProfileManager.getInstance(file.getProject()).getInspectionProfile().getName() +
- ". ";
+ ".\n";
}
else if (HighlightingLevelManager.getInstance(myProject).shouldHighlight(file)) {
myCurrentIcon = AllIcons.Ide.HectorSyntax;
- myToolTipText = "Highlighting level is: Syntax. ";
+ myToolTipText = "Highlighting level is: Syntax.\n";
}
else {
myCurrentIcon = AllIcons.Ide.HectorOff;
- myToolTipText = "Inspections are off. ";
+ myToolTipText = "Inspections are off.\n";
}
myToolTipText += UIBundle.message("popup.hints.panel.click.to.configure.highlighting.tooltip.text");
}
diff --git a/platform/lang-impl/src/com/intellij/platform/templates/github/DownloadUtil.java b/platform/lang-impl/src/com/intellij/platform/templates/github/DownloadUtil.java
index bbffc7c98ba4..02ddd0b64608 100644
--- a/platform/lang-impl/src/com/intellij/platform/templates/github/DownloadUtil.java
+++ b/platform/lang-impl/src/com/intellij/platform/templates/github/DownloadUtil.java
@@ -1,5 +1,6 @@
package com.intellij.platform.templates.github;
+import com.intellij.openapi.application.ex.ApplicationInfoEx;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
@@ -19,7 +20,6 @@ import java.net.HttpURLConnection;
import java.net.URLConnection;
import java.util.Locale;
import java.util.concurrent.Callable;
-import java.util.concurrent.TimeUnit;
/**
* @author Sergey Simonchik
@@ -176,6 +176,7 @@ public class DownloadUtil {
URLConnection urlConnection = HttpConfigurable.getInstance().openConnection(location);
HttpURLConnection httpURLConnection = ObjectUtils.tryCast(urlConnection, HttpURLConnection.class);
try {
+ urlConnection.setRequestProperty("User-Agent", ApplicationInfoEx.getInstanceEx().getFullApplicationName());
urlConnection.connect();
InputStream in = urlConnection.getInputStream();
int contentLength = urlConnection.getContentLength();
diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/InspectionProfileManagerImpl.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/InspectionProfileManagerImpl.java
index de8ee09198c1..08c9e9f0d518 100644
--- a/platform/lang-impl/src/com/intellij/profile/codeInspection/InspectionProfileManagerImpl.java
+++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/InspectionProfileManagerImpl.java
@@ -42,13 +42,17 @@ import com.intellij.openapi.options.*;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.ui.Messages;
-import com.intellij.openapi.util.*;
+import com.intellij.openapi.util.Comparing;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.JDOMExternalizable;
+import com.intellij.openapi.util.WriteExternalException;
import com.intellij.profile.Profile;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ui.UIUtil;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
+import org.jdom.Parent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.TestOnly;
@@ -94,7 +98,7 @@ public class InspectionProfileManagerImpl extends InspectionProfileManager imple
@Override
- public Document writeScheme(@NotNull final InspectionProfileImpl scheme) throws WriteExternalException {
+ public Element writeScheme(@NotNull final InspectionProfileImpl scheme) throws WriteExternalException {
return scheme.saveToDocument();
}
diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/LevelChooser.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/LevelChooser.java
deleted file mode 100644
index 5bc792545c96..000000000000
--- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/LevelChooser.java
+++ /dev/null
@@ -1,102 +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.
- */
-
-/*
- * User: anna
- * Date: 19-Apr-2009
- */
-package com.intellij.profile.codeInspection.ui;
-
-import com.intellij.codeHighlighting.HighlightDisplayLevel;
-import com.intellij.codeInsight.daemon.impl.HighlightInfoType;
-import com.intellij.codeInsight.daemon.impl.SeverityRegistrar;
-import com.intellij.codeInsight.daemon.impl.SeverityUtil;
-import com.intellij.codeInspection.ex.SeverityEditorDialog;
-import com.intellij.ui.ListCellRendererWrapper;
-import com.intellij.lang.annotation.HighlightSeverity;
-import com.intellij.ui.ComboboxWithBrowseButton;
-import org.jetbrains.annotations.NotNull;
-
-import javax.swing.*;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.util.TreeSet;
-
-public class LevelChooser extends ComboboxWithBrowseButton {
- public LevelChooser(final SeverityRegistrar severityRegistrar) {
- final JComboBox comboBox = getComboBox();
- final DefaultComboBoxModel model = new DefaultComboBoxModel();
- comboBox.setModel(model);
- fillModel(model, severityRegistrar);
- getButton().setToolTipText("Edit severities (" + getButton().getToolTipText(null) + ")");
-
- comboBox.setRenderer(new ListCellRendererWrapper<HighlightSeverity>() {
- @Override
- public void customize(final JList list, final HighlightSeverity value, final int index, final boolean selected, final boolean hasFocus) {
- if (value != null) {
- setText(SingleInspectionProfilePanel.renderSeverity(value));
- setIcon(HighlightDisplayLevel.find(value).getIcon());
- }
- }
- });
-
- addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- final SeverityEditorDialog dlg =
- new SeverityEditorDialog(LevelChooser.this, (HighlightSeverity)getComboBox().getSelectedItem(), severityRegistrar);
- dlg.show();
- if (dlg.isOK()) {
- final Object item = getComboBox().getSelectedItem();
- fillModel(model, severityRegistrar);
- final HighlightInfoType type = dlg.getSelectedType();
- if (type != null) {
- getComboBox().setSelectedItem(type.getSeverity(null));
- }
- else {
- getComboBox().setSelectedItem(item);
- }
- }
- }
- });
- }
-
- private static void fillModel(DefaultComboBoxModel model, final SeverityRegistrar severityRegistrar) {
- model.removeAllElements();
- final TreeSet<HighlightSeverity> severities = new TreeSet<HighlightSeverity>(severityRegistrar);
- for (SeverityRegistrar.SeverityBasedTextAttributes type : SeverityUtil.getRegisteredHighlightingInfoTypes(severityRegistrar)) {
- severities.add(type.getSeverity());
- }
- severities.add(HighlightSeverity.ERROR);
- severities.add(HighlightSeverity.WARNING);
- severities.add(HighlightSeverity.WEAK_WARNING);
- severities.add(HighlightSeverity.GENERIC_SERVER_ERROR_OR_WARNING);
- for (HighlightSeverity severity : severities) {
- model.addElement(severity);
- }
- }
-
- @NotNull
- public HighlightDisplayLevel getLevel() {
- HighlightSeverity severity = (HighlightSeverity)getComboBox().getSelectedItem();
- if (severity == null) return HighlightDisplayLevel.WARNING;
- return HighlightDisplayLevel.find(severity);
- }
-
- public void setLevel(HighlightDisplayLevel level) {
- getComboBox().setSelectedItem(level.getSeverity());
- }
-} \ No newline at end of file
diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java
index 81d0bf651688..2320d059c146 100644
--- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java
+++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/SingleInspectionProfilePanel.java
@@ -1005,11 +1005,10 @@ public class SingleInspectionProfilePanel extends JPanel {
northPanel.add(createTreeToolbarPanel().getComponent(), new GridBagConstraints(1, 0, 1, 1, 0.5, 1, GridBagConstraints.BASELINE_LEADING, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
treePanel.add(northPanel, BorderLayout.NORTH);
- myMainSplitter = new Splitter(false);
+ myMainSplitter = new Splitter(false, myProperties.getFloat(VERTICAL_DIVIDER_PROPORTION, 0.5f), 0.01f, 0.99f);
myMainSplitter.setFirstComponent(treePanel);
myMainSplitter.setSecondComponent(myRightSplitter);
myMainSplitter.setHonorComponentsMinimumSize(false);
- myMainSplitter.setProportion(myProperties.getFloat(VERTICAL_DIVIDER_PROPORTION, 0.5f));
final JPanel panel = new JPanel(new BorderLayout());
panel.add(myMainSplitter, BorderLayout.CENTER);
diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/InspectionsConfigTreeTable.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/InspectionsConfigTreeTable.java
index 5607816ad13c..fe36408cf61a 100644
--- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/InspectionsConfigTreeTable.java
+++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/inspectionsTree/InspectionsConfigTreeTable.java
@@ -220,7 +220,7 @@ public class InspectionsConfigTreeTable extends TreeTable {
@Override
public void setValueAt(final Object aValue, final Object node, final int column) {
LOG.assertTrue(column == IS_ENABLED_COLUMN);
- LOG.assertTrue(aValue != null);
+ LOG.assertTrue(aValue != null, "node = " + node);
final boolean doEnable = (Boolean) aValue;
for (final InspectionConfigTreeNode aNode : InspectionsAggregationUtil.getInspectionsNodes((InspectionConfigTreeNode) node)) {
final String toolId = aNode.getKey().toString();
diff --git a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/table/ScopesAndSeveritiesTable.java b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/table/ScopesAndSeveritiesTable.java
index 385b764af027..58e35083a247 100644
--- a/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/table/ScopesAndSeveritiesTable.java
+++ b/platform/lang-impl/src/com/intellij/profile/codeInspection/ui/table/ScopesAndSeveritiesTable.java
@@ -357,6 +357,9 @@ public class ScopesAndSeveritiesTable extends JBTable {
}
else if (columnIndex == SCOPE_ENABLED_COLUMN) {
final NamedScope scope = getScope(rowIndex);
+ if (scope == null) {
+ return;
+ }
if ((Boolean)value) {
if (rowIndex == lastRowIndex()) {
myInspectionProfile.enableToolsByDefault(myKeyNames, myProject);
@@ -381,7 +384,7 @@ public class ScopesAndSeveritiesTable extends JBTable {
@Override
public void removeRow(final int idx) {
if (idx != lastRowIndex()) {
- myInspectionProfile.removeScopes(myKeyNames, getScope(idx), myProject);
+ myInspectionProfile.removeScopes(myKeyNames, getScopeName(idx), myProject);
refreshAggregatedScopes();
myTableSettings.onScopeRemoved(getRowCount());
}
diff --git a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndexImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndexImpl.java
index 537d997e5a50..1773a260a706 100644
--- a/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndexImpl.java
+++ b/platform/lang-impl/src/com/intellij/psi/impl/cache/impl/id/IdIndexImpl.java
@@ -15,6 +15,9 @@
*/
package com.intellij.psi.impl.cache.impl.id;
+import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.openapi.fileTypes.FileTypeRegistry;
+import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.ThreadLocalCachedIntArray;
import com.intellij.util.indexing.CustomInputsIndexFileBasedIndexExtension;
import com.intellij.util.io.DataExternalizer;
@@ -27,9 +30,35 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Comparator;
public class IdIndexImpl extends IdIndex implements CustomInputsIndexFileBasedIndexExtension<IdIndexEntry> {
private static final ThreadLocalCachedIntArray spareBufferLocal = new ThreadLocalCachedIntArray();
+ private final FileTypeRegistry myFileTypeManager;
+
+ public IdIndexImpl(FileTypeRegistry manager) {
+ myFileTypeManager = manager;
+ }
+
+ @Override
+ public int getVersion() {
+ FileType[] types = myFileTypeManager.getRegisteredFileTypes();
+ Arrays.sort(types, new Comparator<FileType>() {
+ @Override
+ public int compare(FileType o1, FileType o2) {
+ return Comparing.compare(o1.getName(), o2.getName());
+ }
+ });
+
+ int version = super.getVersion();
+ for(FileType fileType:types) {
+ if (!isIndexable(fileType)) continue;
+ FileTypeIdIndexer indexer = IdIndexers.INSTANCE.forFileType(fileType);
+ if (indexer == null) continue;
+ version = version * 31 + (indexer.getVersion() ^ indexer.getClass().getName().hashCode());
+ }
+ return version;
+ }
@NotNull
@Override
diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleSchemeImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleSchemeImpl.java
index 99320b44c5e6..59f3767c3a3b 100644
--- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleSchemeImpl.java
+++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleSchemeImpl.java
@@ -161,12 +161,11 @@ public class CodeStyleSchemeImpl implements JDOMExternalizable, CodeStyleScheme,
}
}
- public Document saveToDocument() throws WriteExternalException {
+ public Element saveToDocument() throws WriteExternalException {
Element newElement = new Element(CODE_SCHEME);
newElement.setAttribute(NAME, getName());
writeExternal(newElement);
-
- return new Document(newElement);
+ return newElement;
}
@Override
diff --git a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleSchemesImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleSchemesImpl.java
index b12dee17e9fd..87914f151df3 100644
--- a/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleSchemesImpl.java
+++ b/platform/lang-impl/src/com/intellij/psi/impl/source/codeStyle/CodeStyleSchemesImpl.java
@@ -29,6 +29,7 @@ import com.intellij.psi.codeStyle.CodeStyleScheme;
import com.intellij.psi.codeStyle.CodeStyleSchemes;
import org.jdom.Document;
import org.jdom.JDOMException;
+import org.jdom.Parent;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -57,7 +58,7 @@ public abstract class CodeStyleSchemesImpl extends CodeStyleSchemes implements E
}
@Override
- public Document writeScheme(@NotNull final CodeStyleSchemeImpl scheme) throws WriteExternalException {
+ public Parent writeScheme(@NotNull final CodeStyleSchemeImpl scheme) throws WriteExternalException {
return scheme.saveToDocument();
}
diff --git a/platform/lang-impl/src/com/intellij/psi/search/scope/packageSet/PackageSetFactoryImpl.java b/platform/lang-impl/src/com/intellij/psi/search/scope/packageSet/PackageSetFactoryImpl.java
index 1a3e45d72df7..10f1ec94555e 100644
--- a/platform/lang-impl/src/com/intellij/psi/search/scope/packageSet/PackageSetFactoryImpl.java
+++ b/platform/lang-impl/src/com/intellij/psi/search/scope/packageSet/PackageSetFactoryImpl.java
@@ -137,8 +137,7 @@ public class PackageSetFactoryImpl extends PackageSetFactory {
else if (myLexer.getTokenType() == ScopeTokenTypes.COLON) {
pattern.append(":");
} else {
- error(AnalysisScopeBundle.message("error.packageset.token.expectations", getTokenText()));
- break;
+ pattern.append(getTokenText());
}
myLexer.advance();
}
diff --git a/platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java b/platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java
index 493d1d6cd519..ffc7de7c9b12 100644
--- a/platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java
+++ b/platform/lang-impl/src/com/intellij/psi/stubs/StubIndexImpl.java
@@ -63,11 +63,7 @@ import java.util.concurrent.locks.Lock;
@State(
name = "FileBasedIndex",
- roamingType = RoamingType.DISABLED,
- storages = {
- @Storage(
- file = StoragePathMacros.APP_CONFIG + "/stubIndex.xml")
- }
+ storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/stubIndex.xml", roamingType = RoamingType.DISABLED)}
)
public class StubIndexImpl extends StubIndex implements ApplicationComponent, PersistentStateComponent<StubIndexState> {
private static final AtomicReference<Boolean> ourForcedClean = new AtomicReference<Boolean>(null);
@@ -109,7 +105,7 @@ public class StubIndexImpl extends StubIndex implements ApplicationComponent, Pe
myStubProcessingHelper = new StubProcessingHelper(fileBasedIndex);
}
-
+
@Nullable
public static StubIndexImpl getInstanceOrInvalidate() {
if (ourForcedClean.compareAndSet(null, Boolean.TRUE)) {
diff --git a/platform/lang-impl/src/com/intellij/refactoring/actions/RefactoringQuickListPopupAction.java b/platform/lang-impl/src/com/intellij/refactoring/actions/RefactoringQuickListPopupAction.java
index 159279570cf2..f166c5d08981 100644
--- a/platform/lang-impl/src/com/intellij/refactoring/actions/RefactoringQuickListPopupAction.java
+++ b/platform/lang-impl/src/com/intellij/refactoring/actions/RefactoringQuickListPopupAction.java
@@ -98,7 +98,8 @@ public class RefactoringQuickListPopupAction extends QuickSwitchSchemeAction {
@Override
public void update(AnActionEvent e) {
super.update(e);
- e.getPresentation().setVisible(e.getPlace() == ActionPlaces.MAIN_MENU || e.getPlace() == ActionPlaces.ACTION_PLACE_QUICK_LIST_POPUP_ACTION);
+ e.getPresentation().setVisible(
+ ActionPlaces.isMainMenuOrActionSearch(e.getPlace()) || ActionPlaces.ACTION_PLACE_QUICK_LIST_POPUP_ACTION.equals(e.getPlace()));
}
@Override
diff --git a/platform/lang-impl/src/com/intellij/refactoring/rename/RenameUtil.java b/platform/lang-impl/src/com/intellij/refactoring/rename/RenameUtil.java
index 59595bcc81d0..490efeea1734 100644
--- a/platform/lang-impl/src/com/intellij/refactoring/rename/RenameUtil.java
+++ b/platform/lang-impl/src/com/intellij/refactoring/rename/RenameUtil.java
@@ -240,10 +240,17 @@ public class RenameUtil {
for (UsageInfo usage : usages) {
final PsiReference ref = usage.getReference();
if (ref instanceof BindablePsiReference) {
- try {
- ref.bindToElement(namedElement);
+ boolean fallback = true;
+ if (!(ref instanceof FragmentaryPsiReference
+ && ((FragmentaryPsiReference)ref).isFragmentOnlyRename())) {
+ try {
+ ref.bindToElement(namedElement);
+ fallback = false;
+ }
+ catch (IncorrectOperationException ignored) {
+ }
}
- catch (IncorrectOperationException e) {//fall back to old scheme
+ if (fallback) {//fall back to old scheme
ref.handleElementRename(newName);
}
}
diff --git a/platform/lang-impl/src/com/intellij/tools/BaseExternalToolsGroup.java b/platform/lang-impl/src/com/intellij/tools/BaseExternalToolsGroup.java
index 4d0d2867e387..7dd25a6ec7dd 100644
--- a/platform/lang-impl/src/com/intellij/tools/BaseExternalToolsGroup.java
+++ b/platform/lang-impl/src/com/intellij/tools/BaseExternalToolsGroup.java
@@ -102,7 +102,7 @@ public abstract class BaseExternalToolsGroup<T extends Tool> extends SimpleActio
) {
return tool.isShownInProjectViews();
}
- else if (ActionPlaces.MAIN_MENU.equals(context)) {
+ else if (ActionPlaces.isMainMenuOrActionSearch(context)) {
return tool.isShownInMainMenu();
}
else if (ActionPlaces.USAGE_VIEW_POPUP.equals(context)) {
diff --git a/platform/lang-impl/src/com/intellij/tools/ToolsProcessor.java b/platform/lang-impl/src/com/intellij/tools/ToolsProcessor.java
index 1efa7b05d19b..3846d9c87416 100644
--- a/platform/lang-impl/src/com/intellij/tools/ToolsProcessor.java
+++ b/platform/lang-impl/src/com/intellij/tools/ToolsProcessor.java
@@ -25,6 +25,7 @@ import com.intellij.openapi.util.text.StringUtil;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
+import org.jdom.Parent;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -134,7 +135,7 @@ abstract public class ToolsProcessor<T extends Tool> extends BaseSchemeProcessor
protected abstract T createTool();
@Override
- public Document writeScheme(@NotNull final ToolsGroup<T> scheme) throws WriteExternalException {
+ public Element writeScheme(@NotNull final ToolsGroup<T> scheme) throws WriteExternalException {
Element groupElement = new Element(TOOL_SET);
if (scheme.getName() != null) {
groupElement.setAttribute(ATTRIBUTE_NAME, scheme.getName());
@@ -144,7 +145,7 @@ abstract public class ToolsProcessor<T extends Tool> extends BaseSchemeProcessor
saveTool(tool, groupElement);
}
- return new Document(groupElement);
+ return groupElement;
}
@Override
diff --git a/platform/lang-impl/src/com/intellij/ui/ReplacePromptDialog.java b/platform/lang-impl/src/com/intellij/ui/ReplacePromptDialog.java
index 27622cad5a93..3cf239f46632 100644
--- a/platform/lang-impl/src/com/intellij/ui/ReplacePromptDialog.java
+++ b/platform/lang-impl/src/com/intellij/ui/ReplacePromptDialog.java
@@ -51,6 +51,7 @@ public class ReplacePromptDialog extends DialogWrapper {
replaceAction.putValue(DEFAULT_ACTION,Boolean.TRUE);
if (myException == null) {
if (myIsMultiple){
+ setCancelButtonText(UIBundle.message("replace.prompt.review.action"));
return new Action[]{
replaceAction,
createSkipAction(),
diff --git a/platform/lang-impl/src/com/intellij/ui/tabs/EditorTabColorProviderImpl.java b/platform/lang-impl/src/com/intellij/ui/tabs/EditorTabColorProviderImpl.java
index 93ebe1f0573a..5c2083710f2a 100644
--- a/platform/lang-impl/src/com/intellij/ui/tabs/EditorTabColorProviderImpl.java
+++ b/platform/lang-impl/src/com/intellij/ui/tabs/EditorTabColorProviderImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@ import com.intellij.openapi.fileEditor.impl.EditorTabColorProvider;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.FileColorManager;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.awt.*;
@@ -31,7 +32,7 @@ public class EditorTabColorProviderImpl implements EditorTabColorProvider {
@Override
@Nullable
- public Color getEditorTabColor(Project project, VirtualFile file) {
+ public Color getEditorTabColor(@NotNull Project project, @NotNull VirtualFile file) {
FileColorManager colorManager = FileColorManager.getInstance(project);
return colorManager.isEnabledForTabs() ? colorManager.getFileColor(file) : null;
}
diff --git a/platform/lang-impl/src/com/intellij/util/download/impl/FileDownloaderImpl.java b/platform/lang-impl/src/com/intellij/util/download/impl/FileDownloaderImpl.java
index e9be287a24d3..20d889d1edfa 100644
--- a/platform/lang-impl/src/com/intellij/util/download/impl/FileDownloaderImpl.java
+++ b/platform/lang-impl/src/com/intellij/util/download/impl/FileDownloaderImpl.java
@@ -379,6 +379,7 @@ public class FileDownloaderImpl implements FileDownloader {
private final ProgressIndicator myParent;
private final int myTasksCount;
private final AtomicDouble myTotalFraction;
+ private final Object myLock = new Object();
private LinkedHashMap<SubTaskProgressIndicator, String> myText2Stack = new LinkedHashMap<SubTaskProgressIndicator, String>();
private ConcurrentTasksProgressManager(ProgressIndicator parent, int tasksCount) {
@@ -398,12 +399,17 @@ public class FileDownloaderImpl implements FileDownloader {
public void setText2(@NotNull SubTaskProgressIndicator subTask, @Nullable String text) {
if (text != null) {
- myText2Stack.put(subTask, text);
+ synchronized (myLock) {
+ myText2Stack.put(subTask, text);
+ }
myParent.setText2(text);
}
else {
- myText2Stack.remove(subTask);
- String prev = myText2Stack.getLastValue();
+ String prev;
+ synchronized (myLock) {
+ myText2Stack.remove(subTask);
+ prev = myText2Stack.getLastValue();
+ }
if (prev != null) {
myParent.setText2(prev);
}
diff --git a/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerImpl.java b/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerImpl.java
index 3e7f3bd03739..90f29dccb4d1 100644
--- a/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerImpl.java
+++ b/platform/lang-impl/src/com/intellij/util/indexing/ValueContainerImpl.java
@@ -458,7 +458,7 @@ class ValueContainerImpl<Value> extends UpdatableValueContainer<Value> implement
} else {
// serialize positive file ids with delta encoding
ChangeBufferingList originalInput = (ChangeBufferingList)fileSetObject;
- IntIterator intIterator = originalInput.intIterator();
+ IntIterator intIterator = originalInput.rawIntIterator();
DataInputOutputUtil.writeINT(out, -intIterator.size());
if (intIterator.hasAscendingOrder()) {
@@ -493,7 +493,7 @@ class ValueContainerImpl<Value> extends UpdatableValueContainer<Value> implement
final int[] bits = ourSpareBuffer.getBuffer(bitsLength);
for(int i = 0; i < bitsLength; ++i) bits[i] = 0;
- intIterator = originalInput.intIterator();
+ intIterator = originalInput.rawIntIterator();
while(intIterator.hasNext()) {
final int id = intIterator.next() - offset;
bits[id >> INT_BITS_SHIFT] |= (1 << (id));
diff --git a/platform/lang-impl/src/com/intellij/util/indexing/containers/ChangeBufferingList.java b/platform/lang-impl/src/com/intellij/util/indexing/containers/ChangeBufferingList.java
index 103f7d5fb587..a1373c06a23f 100644
--- a/platform/lang-impl/src/com/intellij/util/indexing/containers/ChangeBufferingList.java
+++ b/platform/lang-impl/src/com/intellij/util/indexing/containers/ChangeBufferingList.java
@@ -19,8 +19,6 @@ import com.intellij.util.indexing.DebugAssertions;
import com.intellij.util.indexing.ValueContainer;
import gnu.trove.TIntProcedure;
-import java.util.Arrays;
-
import static com.intellij.util.indexing.DebugAssertions.DEBUG;
/**
@@ -37,7 +35,8 @@ public class ChangeBufferingList implements Cloneable {
//static final int MAX_FILES = 100;
private volatile int[] changes;
private short length;
- private short removals;
+ private boolean hasRemovals;
+ private volatile boolean mayHaveDupes;
private volatile RandomAccessIntContainer randomAccessContainer;
private IdSet checkSet;
@@ -75,7 +74,8 @@ public class ChangeBufferingList implements Cloneable {
private void addChange(int value) {
changes[length++] = value;
- if (value < 0) ++removals;
+ if (value < 0 && !hasRemovals) hasRemovals = true;
+ if(!mayHaveDupes) mayHaveDupes = true;
}
public void remove(int value) {
@@ -118,37 +118,26 @@ public class ChangeBufferingList implements Cloneable {
RandomAccessIntContainer idSet;
if (randomAccessContainer == null) {
- int someElementsNumberEstimation = length - removals;
+ int someElementsNumberEstimation = length;
int[] minMax = calcMinMax(changes, length);
// todo we can check these lengths instead of only relying upon reaching MAX_FILES
- int lengthOfBitSet = IdBitSet.sizeInBytes(minMax[1], minMax[0]);
- int lengthOfIntSet = 4 * length;
+ //int lengthOfBitSet = IdBitSet.sizeInBytes(minMax[1], minMax[0]);
+ //int lengthOfIntSet = 4 * length;
if (someElementsNumberEstimation < MAX_FILES) {
- if (removals == 0) {
- if (DEBUG) {
- ValueContainer.IntIterator sorted = SortedFileIdSetIterator.getTransientIterator(new ChangesIterator(changes, length));
- int lastIndex = 0;
- while(sorted.hasNext()) {
- currentChanges[lastIndex++] = sorted.next();
- }
-
- DebugAssertions.assertTrue(lastIndex == length);
- idSet = new SortedIdSet(currentChanges, lastIndex);
- } else {
- Arrays.sort(currentChanges, 0, length);
- idSet = new SortedIdSet(currentChanges, length);
+ if (!hasRemovals) {
+ if (mayHaveDupes) {
+ mergeChangesRemovingDupes();
}
+ idSet = new SortedIdSet(currentChanges, length);
+
copyChanges = false;
} else {
idSet = new SortedIdSet(Math.max(someElementsNumberEstimation, 3));
}
}
- else if (removals == 0) {
- if (lengthOfBitSet > lengthOfIntSet) {
- int a = 1;
- }
+ else if (!hasRemovals) {
idSet = new IdBitSet(changes, length, 0);
copyChanges = false;
} else {
@@ -186,13 +175,26 @@ public class ChangeBufferingList implements Cloneable {
}
length = 0;
- removals = 0;
+ hasRemovals = false;
+ mayHaveDupes = false;
randomAccessContainer = idSet;
changes = null;
return randomAccessContainer;
}
}
+ private void mergeChangesRemovingDupes() { // duplicated ids can be present for some index due to cancellation of indexing for next index
+ int[] currentChanges = changes;
+ ValueContainer.IntIterator sorted = SortedFileIdSetIterator.getTransientIterator(new ChangesIterator(currentChanges, length));
+ int lastIndex = 0;
+ while(sorted.hasNext()) {
+ currentChanges[lastIndex++] = sorted.next();
+ }
+
+ length = (short)lastIndex;
+ mayHaveDupes = false;
+ }
+
public void ensureCapacity(int diff) {
RandomAccessIntContainer intContainer = randomAccessContainer;
if (length == MAX_FILES) {
@@ -224,7 +226,7 @@ public class ChangeBufferingList implements Cloneable {
if (DEBUG) DebugAssertions.assertTrue(checkSet.isEmpty());
return true;
}
- if (removals == 0) {
+ if (!hasRemovals) {
boolean b = length == 0;
if (DEBUG) DebugAssertions.assertTrue(b == checkSet.isEmpty());
return b;
@@ -252,14 +254,24 @@ public class ChangeBufferingList implements Cloneable {
public ValueContainer.IntIterator intIterator() {
RandomAccessIntContainer intContainer = randomAccessContainer;
- if (intContainer == null && removals == 0) {
- ValueContainer.IntIterator iterator = new ChangesIterator(changes, length);
- if (DEBUG) {
- ValueContainer.IntIterator iteratorSurelyWithoutDupes = SortedFileIdSetIterator.getTransientIterator(iterator);
- DebugAssertions.assertTrue(iteratorSurelyWithoutDupes.size() == length);
- iterator = iterator.createCopyInInitialState();
+ if (intContainer == null && !hasRemovals) {
+ int[] currentChanges = changes;
+ if (currentChanges != null) {
+ if (mayHaveDupes) {
+ synchronized (currentChanges) {
+ if (mayHaveDupes) mergeChangesRemovingDupes();
+ }
+ }
+ return new ChangesIterator(currentChanges, length);
}
- return iterator;
+ }
+ return getRandomAccessContainer().intIterator();
+ }
+
+ public ValueContainer.IntIterator rawIntIterator() {
+ RandomAccessIntContainer intContainer = randomAccessContainer;
+ if (intContainer == null && !hasRemovals) {
+ return new ChangesIterator(changes, length); // dupes are possible
}
return getRandomAccessContainer().intIterator();
}
diff --git a/platform/platform-api/src/com/intellij/execution/util/ExecUtil.java b/platform/platform-api/src/com/intellij/execution/util/ExecUtil.java
index 00c20735da1b..ca99fca910f8 100644
--- a/platform/platform-api/src/com/intellij/execution/util/ExecUtil.java
+++ b/platform/platform-api/src/com/intellij/execution/util/ExecUtil.java
@@ -83,16 +83,35 @@ public class ExecUtil {
private ExecUtil() { }
+ /**
+ * Run the command using safe escaping and quoting when appropriate.
+ *
+ * @param command the command and its arguments, can contain any characters
+ * @param workDir working directory
+ * @param environment environment variables
+ * @return the running process
+ */
+ @NotNull
+ public static Process exec(@NotNull final List<String> command, @Nullable final String workDir,
+ @Nullable final Map<String, String> environment) throws ExecutionException {
+ assert command.size() > 0;
+ final GeneralCommandLine commandLine = new GeneralCommandLine(command);
+ if (workDir != null) {
+ commandLine.setWorkDirectory(workDir);
+ }
+ if (environment != null) {
+ commandLine.getEnvironment().putAll(environment);
+ }
+ return commandLine.createProcess();
+ }
+
public static int execAndGetResult(final String... command) throws ExecutionException, InterruptedException {
assert command != null && command.length > 0;
return execAndGetResult(Arrays.asList(command));
}
public static int execAndGetResult(@NotNull final List<String> command) throws ExecutionException, InterruptedException {
- assert command.size() > 0;
- final GeneralCommandLine commandLine = new GeneralCommandLine(command);
- final Process process = commandLine.createProcess();
- return process.waitFor();
+ return exec(command, null, null).waitFor();
}
@NotNull
@@ -151,10 +170,7 @@ public class ExecUtil {
@NotNull
public static ProcessOutput execAndGetOutput(@NotNull final List<String> command,
@Nullable final String workDir) throws ExecutionException {
- assert command.size() > 0;
- final GeneralCommandLine commandLine = new GeneralCommandLine(command);
- commandLine.setWorkDirectory(workDir);
- final Process process = commandLine.createProcess();
+ final Process process = exec(command, workDir, null);
final CapturingProcessHandler processHandler = new CapturingProcessHandler(process);
return processHandler.runProcess();
}
@@ -167,7 +183,7 @@ public class ExecUtil {
@Nullable
public static String execAndReadLine(@Nullable Charset charset, final String... command) {
try {
- return readFirstLine(new GeneralCommandLine(command).createProcess().getInputStream(), charset);
+ return readFirstLine(exec(Arrays.asList(command), null, null).getInputStream(), charset);
}
catch (Exception ignored) {
return null;
@@ -199,12 +215,12 @@ public class ExecUtil {
* @param command the command and its arguments, can contain any characters
* @param prompt the prompt string for the users
* @param workDir working directory
+ * @param environment environment variables
* @return the results of running the process
*/
@NotNull
- public static ProcessOutput sudoAndGetOutput(@NotNull List<String> command,
- @NotNull String prompt,
- @Nullable String workDir) throws IOException, ExecutionException {
+ public static Process sudo(@NotNull final List<String> command, @NotNull final String prompt, @Nullable final String workDir,
+ @Nullable final Map<String, String> environment) throws ExecutionException, IOException {
if (SystemInfo.isMac) {
final String escapedCommandLine = StringUtil.join(command, new Function<String, String>() {
@Override
@@ -213,28 +229,28 @@ public class ExecUtil {
}
}, " & \" \" & ");
final String escapedScript = "do shell script " + escapedCommandLine + " with administrator privileges";
- return execAndGetOutput(Arrays.asList(getOsascriptPath(), "-e", escapedScript), workDir);
+ return exec(Arrays.asList(getOsascriptPath(), "-e", escapedScript), workDir, environment);
}
else if ("root".equals(System.getenv("USER"))) {
- return execAndGetOutput(command, workDir);
+ return exec(command, workDir, environment);
}
else if (hasGkSudo.getValue()) {
final List<String> sudoCommand = new ArrayList<String>();
sudoCommand.addAll(Arrays.asList("gksudo", "--message", prompt, "--"));
sudoCommand.addAll(command);
- return execAndGetOutput(sudoCommand, workDir);
+ return exec(sudoCommand, workDir, environment);
}
else if (hasKdeSudo.getValue()) {
final List<String> sudoCommand = new ArrayList<String>();
sudoCommand.addAll(Arrays.asList("kdesudo", "--comment", prompt, "--"));
sudoCommand.addAll(command);
- return execAndGetOutput(sudoCommand, workDir);
+ return exec(sudoCommand, workDir, environment);
}
else if (hasPkExec.getValue()) {
final List<String> sudoCommand = new ArrayList<String>();
sudoCommand.add("pkexec");
sudoCommand.addAll(command);
- return execAndGetOutput(sudoCommand, workDir);
+ return exec(sudoCommand, workDir, environment);
}
else if (SystemInfo.isUnix && hasTerminalApp()) {
final String escapedCommandLine = StringUtil.join(command, new Function<String, String>() {
@@ -253,13 +269,21 @@ public class ExecUtil {
"echo\n" +
"read -p \"Press Enter to close this window...\" TEMP\n" +
"exit $STATUS\n");
- return execAndGetOutput(getTerminalCommand("Install", script.getAbsolutePath()), workDir);
+ return exec(getTerminalCommand("Install", script.getAbsolutePath()), workDir, environment);
}
throw new UnsupportedSystemException();
}
@NotNull
+ public static ProcessOutput sudoAndGetOutput(@NotNull List<String> command, @NotNull String prompt,
+ @Nullable String workDir) throws IOException, ExecutionException {
+ final Process process = sudo(command, prompt, workDir, null);
+ final CapturingProcessHandler processHandler = new CapturingProcessHandler(process);
+ return processHandler.runProcess();
+ }
+
+ @NotNull
private static String escapeAppleScriptArgument(@NotNull String arg) {
return "quoted form of \"" + arg.replace("\"", "\\\"") + "\"";
}
diff --git a/platform/platform-api/src/com/intellij/ide/BrowserUtil.java b/platform/platform-api/src/com/intellij/ide/BrowserUtil.java
index cd1d1b0dba49..85c0efd2b5cd 100644
--- a/platform/platform-api/src/com/intellij/ide/BrowserUtil.java
+++ b/platform/platform-api/src/com/intellij/ide/BrowserUtil.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -35,6 +35,7 @@ import java.net.URL;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -53,7 +54,7 @@ public class BrowserUtil {
private BrowserUtil() { }
public static boolean isAbsoluteURL(String url) {
- return ourExternalPrefix.matcher(url.toLowerCase()).find();
+ return ourExternalPrefix.matcher(url.toLowerCase(Locale.ENGLISH)).find();
}
public static String getDocURL(String url) {
diff --git a/platform/platform-api/src/com/intellij/ide/actions/ContextHelpAction.java b/platform/platform-api/src/com/intellij/ide/actions/ContextHelpAction.java
index b453bb2e174c..1ba3368f2066 100644
--- a/platform/platform-api/src/com/intellij/ide/actions/ContextHelpAction.java
+++ b/platform/platform-api/src/com/intellij/ide/actions/ContextHelpAction.java
@@ -55,7 +55,7 @@ public class ContextHelpAction extends AnAction implements DumbAware {
return;
}
- if (ActionPlaces.MAIN_MENU.equals(event.getPlace())) {
+ if (ActionPlaces.isMainMenuOrActionSearch(event.getPlace())) {
DataContext dataContext = event.getDataContext();
presentation.setEnabled(getHelpId(dataContext) != null);
}
diff --git a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java
index 10285d05fbee..cd8499850430 100644
--- a/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java
+++ b/platform/platform-api/src/com/intellij/ide/util/treeView/AbstractTreeUi.java
@@ -1305,7 +1305,7 @@ public class AbstractTreeUi {
}
if (isSelectionInside(node)) {
- addSelectionPath(getPathFor(node), true, Condition.TRUE, null);
+ addSelectionPath(getPathFor(node), true, Conditions.alwaysTrue(), null);
}
processInnerChange(new Runnable() {
@@ -4853,7 +4853,7 @@ public class AbstractTreeUi {
}
if (pathToSelect != null && myTree.isSelectionEmpty()) {
- addSelectionPath(pathToSelect, true, Condition.FALSE, null);
+ addSelectionPath(pathToSelect, true, Conditions.alwaysFalse(), null);
}
}
}
diff --git a/platform/platform-api/src/com/intellij/ide/util/treeView/UpdaterTreeState.java b/platform/platform-api/src/com/intellij/ide/util/treeView/UpdaterTreeState.java
index d8ab18646aee..e1b0d7f63fe6 100644
--- a/platform/platform-api/src/com/intellij/ide/util/treeView/UpdaterTreeState.java
+++ b/platform/platform-api/src/com/intellij/ide/util/treeView/UpdaterTreeState.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@ package com.intellij.ide.util.treeView;
import com.intellij.openapi.util.ActionCallback;
import com.intellij.openapi.util.Condition;
+import com.intellij.openapi.util.Conditions;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
@@ -214,7 +215,7 @@ public class UpdaterTreeState {
if (!children.contains(eachToSelect)) {
toSelect.remove();
if (!myToSelect.containsKey(readyElement) && !myUi.getSelectedElements().contains(eachToSelect)) {
- addAdjustedSelection(eachToSelect, Condition.FALSE, null);
+ addAdjustedSelection(eachToSelect, Conditions.alwaysFalse(), null);
}
}
}
diff --git a/platform/platform-api/src/com/intellij/notification/Notification.java b/platform/platform-api/src/com/intellij/notification/Notification.java
index 674e20282334..7b3ecd67ca47 100644
--- a/platform/platform-api/src/com/intellij/notification/Notification.java
+++ b/platform/platform-api/src/com/intellij/notification/Notification.java
@@ -20,6 +20,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.Balloon;
import com.intellij.openapi.ui.popup.JBPopupAdapter;
import com.intellij.openapi.ui.popup.LightweightWindowEvent;
+import com.intellij.openapi.util.text.StringUtil;
import com.intellij.reference.SoftReference;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -62,7 +63,7 @@ public class Notification {
myType = type;
myListener = listener;
- LOG.assertTrue(myContent.trim().length() > 0, "Notification should have content, groupId: " + myGroupId);
+ LOG.assertTrue(!StringUtil.isEmptyOrSpaces(myContent), "Notification should have content, groupId: " + myGroupId);
}
@SuppressWarnings("MethodMayBeStatic")
diff --git a/platform/platform-api/src/com/intellij/notification/NotificationGroup.java b/platform/platform-api/src/com/intellij/notification/NotificationGroup.java
index df68daff1584..a1b838676f41 100644
--- a/platform/platform-api/src/com/intellij/notification/NotificationGroup.java
+++ b/platform/platform-api/src/com/intellij/notification/NotificationGroup.java
@@ -54,18 +54,22 @@ public final class NotificationGroup {
ourRegisteredGroups.put(displayId, this);
}
+ @NotNull
public static NotificationGroup balloonGroup(@NotNull String displayId) {
return new NotificationGroup(displayId, NotificationDisplayType.BALLOON, true);
}
+ @NotNull
public static NotificationGroup logOnlyGroup(@NotNull String displayId) {
return new NotificationGroup(displayId, NotificationDisplayType.NONE, true);
}
+ @NotNull
public static NotificationGroup toolWindowGroup(@NotNull String displayId, @NotNull String toolWindowId, final boolean logByDefault) {
return new NotificationGroup(displayId, NotificationDisplayType.TOOL_WINDOW, logByDefault, toolWindowId);
}
+ @NotNull
public static NotificationGroup toolWindowGroup(@NotNull String displayId, @NotNull String toolWindowId) {
return toolWindowGroup(displayId, toolWindowId, true);
}
@@ -78,10 +82,12 @@ public final class NotificationGroup {
return createNotification(content, type.toNotificationType());
}
+ @NotNull
public Notification createNotification(@NotNull final String content, @NotNull final NotificationType type) {
return createNotification("", content, type, null);
}
+ @NotNull
public Notification createNotification(@NotNull final String title,
@NotNull final String content,
@NotNull final NotificationType type,
diff --git a/platform/platform-api/src/com/intellij/notification/NotificationListener.java b/platform/platform-api/src/com/intellij/notification/NotificationListener.java
index 8577d7d6a469..e88204f6888a 100644
--- a/platform/platform-api/src/com/intellij/notification/NotificationListener.java
+++ b/platform/platform-api/src/com/intellij/notification/NotificationListener.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -35,7 +35,7 @@ public interface NotificationListener {
protected abstract void hyperlinkActivated(@NotNull Notification notification, @NotNull HyperlinkEvent e);
}
- NotificationListener URL_OPENING_LISTENER = new UrlOpeningListener(false);
+ NotificationListener URL_OPENING_LISTENER = new UrlOpeningListener(true);
class UrlOpeningListener extends Adapter {
private final boolean myExpireNotification;
diff --git a/platform/platform-api/src/com/intellij/openapi/actionSystem/ActionPlaces.java b/platform/platform-api/src/com/intellij/openapi/actionSystem/ActionPlaces.java
index 16a81d2218d2..aa1248775a21 100644
--- a/platform/platform-api/src/com/intellij/openapi/actionSystem/ActionPlaces.java
+++ b/platform/platform-api/src/com/intellij/openapi/actionSystem/ActionPlaces.java
@@ -26,6 +26,9 @@ import org.jetbrains.annotations.NotNull;
public abstract class ActionPlaces {
public static final String UNKNOWN = "unknown";
+ /**
+ * consider to use {@link #isMainMenuOrActionSearch(String)} instead
+ */
public static final String MAIN_MENU = "MainMenu";
public static final String MAIN_TOOLBAR = "MainToolbar";
public static final String EDITOR_POPUP = "EditorPopup";
@@ -45,6 +48,7 @@ public abstract class ActionPlaces {
public static final String STATUS_BAR_PLACE = "StatusBarPlace";
public static final String SCOPE_VIEW_POPUP = "ScopeViewPopup";
+ public static final String ACTION_SEARCH = "GoToAction";
public static final String TESTTREE_VIEW_POPUP = "TestTreeViewPopup";
public static final String TESTTREE_VIEW_TOOLBAR = "TestTreeViewToolbar";
@@ -127,6 +131,10 @@ public abstract class ActionPlaces {
return ArrayUtil.find(ourToolbarPlaces, place) != -1;
}
+ public static boolean isMainMenuOrActionSearch(String place) {
+ return MAIN_MENU.equals(place) || ACTION_SEARCH.equals(place);
+ }
+
private static final String[] ourPopupPlaces = {EDITOR_POPUP, EDITOR_TAB_POPUP, COMMANDER_POPUP,
PROJECT_VIEW_POPUP, FAVORITES_VIEW_POPUP, SCOPE_VIEW_POPUP, TESTTREE_VIEW_POPUP, TESTSTATISTICS_VIEW_POPUP, TYPE_HIERARCHY_VIEW_POPUP,
METHOD_HIERARCHY_VIEW_POPUP, CALL_HIERARCHY_VIEW_POPUP, J2EE_ATTRIBUTES_VIEW_POPUP, J2EE_VIEW_POPUP, USAGE_VIEW_POPUP,
diff --git a/platform/platform-api/src/com/intellij/openapi/actionSystem/Separator.java b/platform/platform-api/src/com/intellij/openapi/actionSystem/Separator.java
index 2dd2ee50d120..191c8c01ce32 100644
--- a/platform/platform-api/src/com/intellij/openapi/actionSystem/Separator.java
+++ b/platform/platform-api/src/com/intellij/openapi/actionSystem/Separator.java
@@ -42,6 +42,11 @@ public final class Separator extends AnAction implements DumbAware {
}
@Override
+ public String toString() {
+ return "Separator (" + myText + ")";
+ }
+
+ @Override
public void actionPerformed(AnActionEvent e){
throw new UnsupportedOperationException();
}
diff --git a/platform/platform-api/src/com/intellij/openapi/actionSystem/ex/CheckboxAction.java b/platform/platform-api/src/com/intellij/openapi/actionSystem/ex/CheckboxAction.java
index 5f179baad831..3e52f26d0b87 100644
--- a/platform/platform-api/src/com/intellij/openapi/actionSystem/ex/CheckboxAction.java
+++ b/platform/platform-api/src/com/intellij/openapi/actionSystem/ex/CheckboxAction.java
@@ -43,12 +43,8 @@ public abstract class CheckboxAction extends ToggleAction implements CustomCompo
public JComponent createCustomComponent(Presentation presentation) {
// this component cannot be stored right here because of action system architecture:
// one action can be shown on multiple toolbars simultaneously
- JCheckBox checkBox = new JCheckBox(presentation.getText());
+ JCheckBox checkBox = new JCheckBox();
checkBox.setOpaque(false);
- checkBox.setToolTipText(presentation.getDescription());
- checkBox.setMnemonic(presentation.getMnemonic());
- checkBox.setDisplayedMnemonicIndex(presentation.getDisplayedMnemonicIndex());
- checkBox.setSelected(Boolean.TRUE.equals(presentation.getClientProperty(SELECTED_PROPERTY)));
checkBox.addActionListener(new ActionListener() {
@Override
@@ -69,13 +65,19 @@ public abstract class CheckboxAction extends ToggleAction implements CustomCompo
@Override
public void update(final AnActionEvent e) {
super.update(e);
- Object property = e.getPresentation().getClientProperty(CUSTOM_COMPONENT_PROPERTY);
+ Presentation presentation = e.getPresentation();
+ Object property = presentation.getClientProperty(CUSTOM_COMPONENT_PROPERTY);
if (property instanceof JCheckBox) {
JCheckBox checkBox = (JCheckBox)property;
- checkBox.setSelected(Boolean.TRUE.equals(e.getPresentation().getClientProperty(SELECTED_PROPERTY)));
- checkBox.setEnabled(e.getPresentation().isEnabled());
- checkBox.setVisible(e.getPresentation().isVisible());
+ checkBox.setText(presentation.getText());
+ checkBox.setToolTipText(presentation.getDescription());
+ checkBox.setMnemonic(presentation.getMnemonic());
+ checkBox.setDisplayedMnemonicIndex(presentation.getDisplayedMnemonicIndex());
+ checkBox.setSelected(Boolean.TRUE.equals(presentation.getClientProperty(SELECTED_PROPERTY)));
+
+ checkBox.setEnabled(presentation.isEnabled());
+ checkBox.setVisible(presentation.isVisible());
}
}
}
diff --git a/platform/platform-api/src/com/intellij/openapi/actionSystem/ex/ComboBoxAction.java b/platform/platform-api/src/com/intellij/openapi/actionSystem/ex/ComboBoxAction.java
index 7398bf706c78..6ce522141f16 100644
--- a/platform/platform-api/src/com/intellij/openapi/actionSystem/ex/ComboBoxAction.java
+++ b/platform/platform-api/src/com/intellij/openapi/actionSystem/ex/ComboBoxAction.java
@@ -26,10 +26,7 @@ import com.intellij.openapi.util.IconLoader;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.wm.IdeFocusManager;
-import com.intellij.ui.ColorUtil;
-import com.intellij.ui.Gray;
-import com.intellij.ui.IdeBorderFactory;
-import com.intellij.ui.JBColor;
+import com.intellij.ui.*;
import com.intellij.ui.awt.RelativePoint;
import com.intellij.util.ui.GraphicsUtil;
import com.intellij.util.ui.UIUtil;
@@ -103,7 +100,7 @@ public abstract class ComboBoxAction extends AnAction implements CustomComponent
return 1;
}
- protected class ComboBoxButton extends JButton {
+ protected class ComboBoxButton extends JButton implements UserActivityProviderComponent {
private final Presentation myPresentation;
private boolean myForcePressed = false;
private PropertyChangeListener myButtonSynchronizer;
@@ -227,6 +224,7 @@ public abstract class ComboBoxAction extends AnAction implements CustomComponent
}
});
repaint();
+ fireStateChanged();
}
};
diff --git a/platform/platform-api/src/com/intellij/openapi/application/ApplicationStarterEx.java b/platform/platform-api/src/com/intellij/openapi/application/ApplicationStarterEx.java
index c4b3a6384f56..86e322f6e0e3 100644
--- a/platform/platform-api/src/com/intellij/openapi/application/ApplicationStarterEx.java
+++ b/platform/platform-api/src/com/intellij/openapi/application/ApplicationStarterEx.java
@@ -15,6 +15,8 @@
*/
package com.intellij.openapi.application;
+import org.jetbrains.annotations.Nullable;
+
/**
* Implementers of the interface declared via {@link com.intellij.ExtensionPoints#APPLICATION_STARTER}
* may be capable of processing an external command line within a running IntelliJ Platform instance.
@@ -28,5 +30,10 @@ public abstract class ApplicationStarterEx implements ApplicationStarter {
return false;
}
+ @Deprecated
public void processExternalCommandLine(String[] args) { }
+
+ public void processExternalCommandLine(String[] args, @Nullable String currentDirectory) {
+ processExternalCommandLine(args);
+ }
}
diff --git a/platform/platform-api/src/com/intellij/openapi/diagnostic/ErrorReportSubmitter.java b/platform/platform-api/src/com/intellij/openapi/diagnostic/ErrorReportSubmitter.java
index 9f1b8e06b39e..c68e45189a95 100644
--- a/platform/platform-api/src/com/intellij/openapi/diagnostic/ErrorReportSubmitter.java
+++ b/platform/platform-api/src/com/intellij/openapi/diagnostic/ErrorReportSubmitter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,6 +18,8 @@ package com.intellij.openapi.diagnostic;
import com.intellij.openapi.extensions.PluginAware;
import com.intellij.openapi.extensions.PluginDescriptor;
import com.intellij.util.Consumer;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.awt.*;
@@ -44,33 +46,43 @@ public abstract class ErrorReportSubmitter implements PluginAware {
}
/**
- * @return "Report to vendor" action text to be used in Error Reporter user interface. For example: "Report to JetBrains".
+ * @return an action text to be used in Error Reporter user interface, e.g. "Report to JetBrains".
*/
public abstract String getReportActionText();
/**
- * This method is called whenever fatal error (aka exception) in plugin code had happened and user decided to report this problem to
- * plugin vendor.
- * @param events sequence of the fatal error descriptors. Fatal errors that happened immediately one after another most probably caused
- * by first one that happened so it's a common practice to submit only first one. Array passed is guaranteed to have at least one element.
- * @param parentComponent one usually wants to show up a dialog asking user for additional details and probably authentication info.
- * parentComponent parameter is passed so dialog that would come up would be properly aligned with its parent dialog (IDE Fatal Errors).
- * @return submission result status.
+ * This method is called whenever an exception in a plugin code had happened and a user decided to report a problem to the plugin vendor.
+ *
+ * @param events a non-empty sequence of error descriptors.
+ * @param additionalInfo additional information provided by a user.
+ * @param parentComponent UI component to use as a parent in any UI activity from a submitter.
+ * @param consumer a callback to be called after sending is finished (or failed).
+ * @return {@code true} if reporting was started, {@code false} if a report can't be sent at the moment.
*/
- public abstract SubmittedReportInfo submit(IdeaLoggingEvent[] events, Component parentComponent);
-
- public void submitAsync(IdeaLoggingEvent[] events,
- String additionalInfo,
- Component parentComponent,
- Consumer<SubmittedReportInfo> consumer) {
- consumer.consume(submit(events, parentComponent));
+ @SuppressWarnings("deprecation")
+ public boolean submit(@NotNull IdeaLoggingEvent[] events,
+ @Nullable String additionalInfo,
+ @NotNull Component parentComponent,
+ @NotNull Consumer<SubmittedReportInfo> consumer) {
+ return trySubmitAsync(events, additionalInfo, parentComponent, consumer);
}
- public boolean trySubmitAsync(IdeaLoggingEvent[] events,
- String additionalInfo,
- Component parentComponent,
- Consumer<SubmittedReportInfo> consumer) {
- submitAsync(events, additionalInfo, parentComponent, consumer);
+ /** @deprecated implement {@link #submit(IdeaLoggingEvent[], String, Component, Consumer)} (to be removed in IDEA 16) */
+ @SuppressWarnings({"deprecation", "unused"})
+ public boolean trySubmitAsync(IdeaLoggingEvent[] events, String info, Component parent, Consumer<SubmittedReportInfo> consumer) {
+ submitAsync(events, info, parent, consumer);
return true;
}
+
+ /** @deprecated implement {@link #submit(IdeaLoggingEvent[], String, Component, Consumer)} (to be removed in IDEA 16) */
+ @SuppressWarnings({"deprecation", "unused"})
+ public void submitAsync(IdeaLoggingEvent[] events, String info, Component parent, Consumer<SubmittedReportInfo> consumer) {
+ consumer.consume(submit(events, parent));
+ }
+
+ /** @deprecated implement {@link #submit(IdeaLoggingEvent[], String, Component, Consumer)} (to be removed in IDEA 16) */
+ @SuppressWarnings({"deprecation", "unused"})
+ public SubmittedReportInfo submit(IdeaLoggingEvent[] events, Component parent) {
+ throw new UnsupportedOperationException("Deprecated API called");
+ }
}
diff --git a/platform/platform-api/src/com/intellij/openapi/diagnostic/SubmittedReportInfo.java b/platform/platform-api/src/com/intellij/openapi/diagnostic/SubmittedReportInfo.java
index 6bad8c45df93..8ead30567681 100644
--- a/platform/platform-api/src/com/intellij/openapi/diagnostic/SubmittedReportInfo.java
+++ b/platform/platform-api/src/com/intellij/openapi/diagnostic/SubmittedReportInfo.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,6 +15,9 @@
*/
package com.intellij.openapi.diagnostic;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
/**
* Simple bean representing error submission status.
*/
@@ -31,29 +34,27 @@ public class SubmittedReportInfo {
DUPLICATE,
/**
- * Submission failed. (For network connection reasons for example)
+ * Submission failed (e.g. because of network problem)
*/
FAILED
}
- private final String myURL;
+ private final String myUrl;
private final String myLinkText;
private final SubmissionStatus myStatus;
- /**
- * Create new submission status bean
- * @param URL url that points to newly created issue. Optional. Pass <code>null</code> value if N/A or failed
- * @param linkText short text that UI interface pointing to the issue should have.
- * @param status submission success/failure
- */
- public SubmittedReportInfo(final String URL, final String linkText, final SubmissionStatus status) {
- myURL = URL;
+ public SubmittedReportInfo(SubmissionStatus status) {
+ this(null, null, status);
+ }
+
+ public SubmittedReportInfo(@Nullable String url, @Nullable String linkText, @NotNull SubmissionStatus status) {
+ myUrl = url;
myLinkText = linkText;
myStatus = status;
}
public String getURL() {
- return myURL;
+ return myUrl;
}
public String getLinkText() {
diff --git a/platform/platform-api/src/com/intellij/openapi/fileChooser/FileChooser.java b/platform/platform-api/src/com/intellij/openapi/fileChooser/FileChooser.java
index 9e0bf738a7cf..fee268813d14 100644
--- a/platform/platform-api/src/com/intellij/openapi/fileChooser/FileChooser.java
+++ b/platform/platform-api/src/com/intellij/openapi/fileChooser/FileChooser.java
@@ -52,7 +52,7 @@ public class FileChooser {
@Nullable final Project project,
@Nullable final VirtualFile toSelect) {
final FileChooserDialog chooser = FileChooserFactory.getInstance().createFileChooser(descriptor, project, parent);
- return chooser.choose(toSelect, project);
+ return chooser.choose(project, toSelect);
}
@Nullable
diff --git a/platform/platform-api/src/com/intellij/openapi/fileChooser/FileChooserDialog.java b/platform/platform-api/src/com/intellij/openapi/fileChooser/FileChooserDialog.java
index c12ab422a942..324979dff228 100644
--- a/platform/platform-api/src/com/intellij/openapi/fileChooser/FileChooserDialog.java
+++ b/platform/platform-api/src/com/intellij/openapi/fileChooser/FileChooserDialog.java
@@ -23,7 +23,22 @@ import org.jetbrains.annotations.Nullable;
public interface FileChooserDialog {
DataKey<Boolean> PREFER_LAST_OVER_TO_SELECT = PathChooserDialog.PREFER_LAST_OVER_EXPLICIT;
-
+
+ /**
+ * @deprecated Please use {@link #choose(com.intellij.openapi.project.Project, com.intellij.openapi.vfs.VirtualFile...)} because
+ * it supports several selections
+ */
+ @Deprecated
@NotNull
VirtualFile[] choose(@Nullable VirtualFile toSelect, @Nullable Project project);
+
+ /**
+ * Choose one or more files
+ *
+ * @param project use this project (you may pass null if you already set project in ctor)
+ * @param toSelect files to be selected automatically.
+ * @return files chosen by user
+ */
+ @NotNull
+ VirtualFile[] choose(@Nullable Project project, @NotNull VirtualFile... toSelect);
} \ No newline at end of file
diff --git a/platform/platform-api/src/com/intellij/openapi/fileEditor/FileEditorManager.java b/platform/platform-api/src/com/intellij/openapi/fileEditor/FileEditorManager.java
index 86e719eef48d..dcb1327f1a10 100644
--- a/platform/platform-api/src/com/intellij/openapi/fileEditor/FileEditorManager.java
+++ b/platform/platform-api/src/com/intellij/openapi/fileEditor/FileEditorManager.java
@@ -197,5 +197,5 @@ public abstract class FileEditorManager {
* @param fileEditorProviderId the ID of the file editor to open; matches the return value of
* {@link com.intellij.openapi.fileEditor.FileEditorProvider#getEditorTypeId()}
*/
- public abstract void setSelectedEditor(@NotNull VirtualFile file, String fileEditorProviderId);
+ public abstract void setSelectedEditor(@NotNull VirtualFile file, @NotNull String fileEditorProviderId);
}
diff --git a/platform/platform-api/src/com/intellij/openapi/options/ConfigurableEP.java b/platform/platform-api/src/com/intellij/openapi/options/ConfigurableEP.java
index 78a4c1ece130..828907c13cfb 100644
--- a/platform/platform-api/src/com/intellij/openapi/options/ConfigurableEP.java
+++ b/platform/platform-api/src/com/intellij/openapi/options/ConfigurableEP.java
@@ -175,9 +175,25 @@ public class ConfigurableEP<T extends UnnamedConfigurable> extends AbstractExten
return getDisplayName();
}
+ public boolean canCreateConfigurable() {
+ if (providerClass == null) {
+ return implementationClass != null || instanceClass != null;
+ }
+ try {
+ ConfigurableProvider provider = instantiate(providerClass, myPicoContainer);
+ return provider.canCreateConfigurable(); // do not load heavy configurables
+ }
+ catch (Exception ignored) {
+ return true; // see InstanceFromProviderFactory#compute
+ }
+ }
+
private class InstanceFromProviderFactory extends AtomicNotNullLazyValue<ConfigurableProvider> implements NullableFactory<T> {
public T create() {
- return (T)getValue().createConfigurable();
+ ConfigurableProvider provider = getValue();
+ return provider.canCreateConfigurable()
+ ? (T)provider.createConfigurable()
+ : null;
}
@NotNull
diff --git a/platform/platform-api/src/com/intellij/openapi/options/ConfigurableProvider.java b/platform/platform-api/src/com/intellij/openapi/options/ConfigurableProvider.java
index 5a71ffa73050..cf2bc0390c5a 100644
--- a/platform/platform-api/src/com/intellij/openapi/options/ConfigurableProvider.java
+++ b/platform/platform-api/src/com/intellij/openapi/options/ConfigurableProvider.java
@@ -29,4 +29,15 @@ public abstract class ConfigurableProvider {
@Nullable
public abstract Configurable createConfigurable();
+ /**
+ * Defines whether this provider creates a configurable or not.
+ * Note that the {@code createConfigurable} method will be called
+ * if this method returns {@code true}.
+ *
+ * @return {@code true} if this provider creates configurable,
+ * {@code false} otherwise
+ */
+ public boolean canCreateConfigurable() {
+ return true;
+ }
}
diff --git a/platform/platform-api/src/com/intellij/openapi/options/CurrentUserHolder.java b/platform/platform-api/src/com/intellij/openapi/options/CurrentUserHolder.java
index 473dce3dda6c..2395fa27f4c1 100644
--- a/platform/platform-api/src/com/intellij/openapi/options/CurrentUserHolder.java
+++ b/platform/platform-api/src/com/intellij/openapi/options/CurrentUserHolder.java
@@ -15,6 +15,7 @@
*/
package com.intellij.openapi.options;
+@Deprecated
public interface CurrentUserHolder {
String getCurrentUserName();
}
diff --git a/platform/platform-api/src/com/intellij/openapi/options/SearchableConfigurable.java b/platform/platform-api/src/com/intellij/openapi/options/SearchableConfigurable.java
index e98bb05aba99..b426e35d77a8 100644
--- a/platform/platform-api/src/com/intellij/openapi/options/SearchableConfigurable.java
+++ b/platform/platform-api/src/com/intellij/openapi/options/SearchableConfigurable.java
@@ -34,6 +34,12 @@ public interface SearchableConfigurable extends Configurable {
interface Parent extends SearchableConfigurable, Composite {
boolean hasOwnContent();
+
+ /**
+ * @deprecated use {@link ConfigurableProvider#canCreateConfigurable()} instead
+ * to specify configurables which should not be visible
+ */
+ @Deprecated
boolean isVisible();
abstract class Abstract implements Parent {
diff --git a/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java b/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java
index 741f67dee2c4..a291ab32e950 100644
--- a/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java
+++ b/platform/platform-api/src/com/intellij/openapi/ui/DialogWrapper.java
@@ -2001,12 +2001,19 @@ public abstract class DialogWrapper {
*/
public interface DoNotAskOption {
+ /**
+ * @return default selection state of checkbox (false -> checkbox selected)
+ */
boolean isToBeShown();
- void setToBeShown(boolean value, int exitCode);
+ /**
+ * @param toBeShown - if dialog should be shown next time (checkbox selected -> false)
+ * @param exitCode of corresponding DialogWrapper
+ */
+ void setToBeShown(boolean toBeShown, int exitCode);
/**
- * Should be 'true' for checkbox to be visible.
+ * @return true if checkbox should be shown
*/
boolean canBeHidden();
diff --git a/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java b/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java
index a262ea0a3b85..547fa03e438d 100644
--- a/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java
+++ b/platform/platform-api/src/com/intellij/openapi/ui/MasterDetailsComponent.java
@@ -131,7 +131,7 @@ public abstract class MasterDetailsComponent implements Configurable, DetailsCom
protected MasterDetailsComponent(MasterDetailsState state) {
myState = state;
- mySplitter = Registry.is("ide.new.project.settings") ? new OnePixelSplitter(false, .2f) : new JBSplitter(false, .2f);
+ mySplitter = isNewProjectSettings() ? new OnePixelSplitter(false, .2f) : new JBSplitter(false, .2f);
mySplitter.setSplitterProportionKey("ProjectStructure.SecondLevelElements");
mySplitter.setHonorComponentsMinimumSize(true);
@@ -139,6 +139,20 @@ public abstract class MasterDetailsComponent implements Configurable, DetailsCom
reInitWholePanelIfNeeded();
}
+ private boolean isNewProjectSettings() {
+ if (!Registry.is("ide.new.project.settings")) {
+ return false;
+ }
+ try {
+ // assume that only project structure dialog uses the following base class for details:
+ String name = "com.intellij.openapi.roots.ui.configuration.projectRoot.BaseStructureConfigurable";
+ return Class.forName(name).isAssignableFrom(getClass());
+ }
+ catch (ClassNotFoundException ignored) {
+ return false;
+ }
+ }
+
protected void reInitWholePanelIfNeeded() {
if (!myToReInitWholePanel) return;
@@ -170,7 +184,7 @@ public abstract class MasterDetailsComponent implements Configurable, DetailsCom
}
};
- if (Registry.is("ide.new.project.settings")) {
+ if (isNewProjectSettings()) {
ToolbarDecorator decorator = ToolbarDecorator.createDecorator(myTree);
DefaultActionGroup group = createToolbarActionGroup();
if (group != null) {
@@ -281,7 +295,7 @@ public abstract class MasterDetailsComponent implements Configurable, DetailsCom
}
private void initToolbar() {
- if (Registry.is("ide.new.project.settings")) return;
+ if (isNewProjectSettings()) return;
DefaultActionGroup group = createToolbarActionGroup();
if (group != null) {
final JComponent component = ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, group, true).getComponent();
diff --git a/platform/platform-api/src/com/intellij/openapi/ui/Messages.java b/platform/platform-api/src/com/intellij/openapi/ui/Messages.java
index 1a07b33d696d..e963871cfd5f 100644
--- a/platform/platform-api/src/com/intellij/openapi/ui/Messages.java
+++ b/platform/platform-api/src/com/intellij/openapi/ui/Messages.java
@@ -377,6 +377,33 @@ public class Messages {
* @return {@link #YES} if user pressed "Yes" or {@link #NO} if user pressed "No" button.
*/
@YesNoResult
+ public static int showYesNoDialog(@Nullable Project project,
+ String message,
+ @NotNull String title,
+ @NotNull String yesText,
+ @NotNull String noText,
+ @Nullable Icon icon,
+ @Nullable DialogWrapper.DoNotAskOption doNotAskOption) {
+ try {
+ if (canShowMacSheetPanel()) {
+ return MacMessages.getInstance()
+ .showYesNoDialog(title, message, yesText, noText, WindowManager.getInstance().suggestParentWindow(project), doNotAskOption);
+ }
+ }
+ catch (Exception exception) {
+ LOG.error(exception);
+ }
+
+ int result = showDialog(project, message, title, new String[]{yesText, noText}, 0, icon, doNotAskOption) == 0 ? YES : NO;
+ //noinspection ConstantConditions
+ LOG.assertTrue(result == YES || result == NO, result);
+ return result;
+ }
+
+ /**
+ * @return {@link #YES} if user pressed "Yes" or {@link #NO} if user pressed "No" button.
+ */
+ @YesNoResult
public static int showYesNoDialog(@Nullable Project project, String message, @NotNull String title, @Nullable Icon icon) {
try {
if (canShowMacSheetPanel()) {
@@ -394,6 +421,31 @@ public class Messages {
return result;
}
+ /**
+ * @return {@link #YES} if user pressed "Yes" or {@link #NO} if user pressed "No" button.
+ */
+ @YesNoResult
+ public static int showYesNoDialog(@Nullable Project project,
+ String message,
+ @NotNull String title,
+ @Nullable Icon icon,
+ @Nullable DialogWrapper.DoNotAskOption doNotAskOption) {
+ try {
+ if (canShowMacSheetPanel()) {
+ return MacMessages.getInstance().showYesNoDialog(title, message, YES_BUTTON, NO_BUTTON,
+ WindowManager.getInstance().suggestParentWindow(project), doNotAskOption);
+ }
+ }
+ catch (Exception exception) {
+ LOG.error(exception);
+ }
+
+ int result = showYesNoDialog(project, message, title, YES_BUTTON, NO_BUTTON, icon, doNotAskOption);
+
+ LOG.assertTrue(result == YES || result == NO, result);
+ return result;
+ }
+
/**
* @return {@link #YES} if user pressed "Yes" or {@link #NO} if user pressed "No" button.
diff --git a/platform/platform-api/src/com/intellij/openapi/ui/popup/util/BaseListPopupStep.java b/platform/platform-api/src/com/intellij/openapi/ui/popup/util/BaseListPopupStep.java
index 2a55c3bd342a..3bb5302e7f2e 100644
--- a/platform/platform-api/src/com/intellij/openapi/ui/popup/util/BaseListPopupStep.java
+++ b/platform/platform-api/src/com/intellij/openapi/ui/popup/util/BaseListPopupStep.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2011 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,16 +32,16 @@ public class BaseListPopupStep<T> extends BaseStep<T> implements ListPopupStep<T
private List<Icon> myIcons;
private int myDefaultOptionIndex = -1;
- public BaseListPopupStep(@Nullable String aTitle, T[] aValues) {
- this(aTitle, aValues, new Icon[]{});
+ public BaseListPopupStep(@Nullable String title, T[] values) {
+ this(title, values, new Icon[]{});
}
- public BaseListPopupStep(@Nullable String aTitle, List<? extends T> aValues) {
- this(aTitle, aValues, new ArrayList<Icon>());
+ public BaseListPopupStep(@Nullable String title, List<? extends T> values) {
+ this(title, values, new ArrayList<Icon>());
}
- public BaseListPopupStep(@Nullable String aTitle, T[] aValues, Icon[] aIcons) {
- this(aTitle, Arrays.asList(aValues), Arrays.asList(aIcons));
+ public BaseListPopupStep(@Nullable String title, T[] values, Icon[] icons) {
+ this(title, Arrays.asList(values), Arrays.asList(icons));
}
public BaseListPopupStep(@Nullable String aTitle, @NotNull List<? extends T> aValues, Icon aSameIcon) {
@@ -53,16 +53,16 @@ public class BaseListPopupStep<T> extends BaseStep<T> implements ListPopupStep<T
init(aTitle, aValues, icons);
}
- public BaseListPopupStep(@Nullable String aTitle, @NotNull List<? extends T> aValues, List<Icon> aIcons) {
- init(aTitle, aValues, aIcons);
+ public BaseListPopupStep(@Nullable String title, @NotNull List<? extends T> values, List<Icon> icons) {
+ init(title, values, icons);
}
protected BaseListPopupStep() { }
- protected final void init(@Nullable String aTitle, @NotNull List<? extends T> aValues, @Nullable List<Icon> aIcons) {
- myTitle = aTitle;
- myValues = new ArrayList<T>(aValues);
- myIcons = aIcons;
+ protected final void init(@Nullable String title, @NotNull List<? extends T> values, @Nullable List<Icon> icons) {
+ myTitle = title;
+ myValues = new ArrayList<T>(values);
+ myIcons = icons;
}
@Nullable
@@ -79,8 +79,8 @@ public class BaseListPopupStep<T> extends BaseStep<T> implements ListPopupStep<T
return FINAL_CHOICE;
}
- public Icon getIconFor(T aValue) {
- int index = myValues.indexOf(aValue);
+ public Icon getIconFor(T value) {
+ int index = myValues.indexOf(value);
if (index != -1 && myIcons != null && index < myIcons.size()) {
return myIcons.get(index);
}
diff --git a/platform/platform-api/src/com/intellij/openapi/vfs/newvfs/FileAttribute.java b/platform/platform-api/src/com/intellij/openapi/vfs/newvfs/FileAttribute.java
index 965b3c0de9bf..3c775f5b2e8c 100644
--- a/platform/platform-api/src/com/intellij/openapi/vfs/newvfs/FileAttribute.java
+++ b/platform/platform-api/src/com/intellij/openapi/vfs/newvfs/FileAttribute.java
@@ -21,7 +21,6 @@ package com.intellij.openapi.vfs.newvfs;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.util.io.DataInputOutputUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -60,33 +59,12 @@ public class FileAttribute {
@Nullable
public DataInputStream readAttribute(@NotNull VirtualFile file) {
- DataInputStream stream = ManagingFS.getInstance().readAttribute(file, this);
- if (stream != null) {
- try {
- int actualVersion = DataInputOutputUtil.readINT(stream);
- if (actualVersion != myVersion) {
- stream.close();
- return null;
- }
- }
- catch (IOException e) {
- return null;
- }
- }
- return stream;
+ return ManagingFS.getInstance().readAttribute(file, this);
}
@NotNull
public DataOutputStream writeAttribute(@NotNull VirtualFile file) {
- final DataOutputStream stream = ManagingFS.getInstance().writeAttribute(file, this);
- try {
- DataInputOutputUtil.writeINT(stream, myVersion);
- }
- catch (IOException e) {
- throw new RuntimeException(e);
- }
-
- return stream;
+ return ManagingFS.getInstance().writeAttribute(file, this);
}
@Nullable
@@ -131,4 +109,8 @@ public class FileAttribute {
public FileAttribute newVersion(int newVersion) {
return new FileAttribute(newVersion, myFixedSize, myId);
}
+
+ public int getVersion() {
+ return myVersion;
+ }
}
diff --git a/platform/platform-api/src/com/intellij/ui/CollectionListModel.java b/platform/platform-api/src/com/intellij/ui/CollectionListModel.java
index c301aa3be252..d806eb2e06b8 100644
--- a/platform/platform-api/src/com/intellij/ui/CollectionListModel.java
+++ b/platform/platform-api/src/com/intellij/ui/CollectionListModel.java
@@ -103,6 +103,7 @@ public class CollectionListModel<T> extends AbstractListModel implements Editabl
Collections.sort(myItems, comparator);
}
+ @NotNull
public List<T> getItems() {
return Collections.unmodifiableList(myItems);
}
diff --git a/platform/platform-api/src/com/intellij/ui/SimpleColoredText.java b/platform/platform-api/src/com/intellij/ui/SimpleColoredText.java
index af851951e363..8c899f1a6b5c 100644
--- a/platform/platform-api/src/com/intellij/ui/SimpleColoredText.java
+++ b/platform/platform-api/src/com/intellij/ui/SimpleColoredText.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -45,6 +45,12 @@ public class SimpleColoredText implements ColoredTextContainer {
myAttributes.add(attributes);
}
+ public void insert(int index, @NotNull String fragment, @NotNull SimpleTextAttributes attributes) {
+ myTexts.add(index, fragment);
+ myCachedToString = null;
+ myAttributes.add(index, attributes);
+ }
+
@Override
public void append(@NotNull String fragment, @NotNull SimpleTextAttributes attributes, Object tag) {
append(fragment, attributes);
diff --git a/platform/platform-api/src/com/intellij/ui/components/labels/LinkLabel.java b/platform/platform-api/src/com/intellij/ui/components/labels/LinkLabel.java
index 129217ec7e4a..0416008d1d57 100644
--- a/platform/platform-api/src/com/intellij/ui/components/labels/LinkLabel.java
+++ b/platform/platform-api/src/com/intellij/ui/components/labels/LinkLabel.java
@@ -204,6 +204,8 @@ public class LinkLabel<T> extends JLabel {
}
private boolean isInClickableArea(Point pt) {
+ Insets insets = getInsets(); // border is set
+ pt.translate(-insets.left, -insets.top);
if (getIcon() != null) {
if (pt.getX() < getIcon().getIconWidth() && pt.getY() < getIcon().getIconHeight()) {
return true;
diff --git a/platform/platform-api/src/com/intellij/ui/table/JBTable.java b/platform/platform-api/src/com/intellij/ui/table/JBTable.java
index c1146be40aba..a65c209399bf 100644
--- a/platform/platform-api/src/com/intellij/ui/table/JBTable.java
+++ b/platform/platform-api/src/com/intellij/ui/table/JBTable.java
@@ -572,7 +572,7 @@ public class JBTable extends JTable implements ComponentWithEmptyText, Component
private final class MyMouseListener extends MouseAdapter {
@Override
public void mousePressed(@NotNull final MouseEvent e) {
- if (SwingUtilities.isRightMouseButton(e)) {
+ if (JBSwingUtilities.isRightMouseButton(e)) {
final int[] selectedRows = getSelectedRows();
if (selectedRows.length < 2) {
final int row = rowAtPoint(e.getPoint());
diff --git a/platform/platform-api/src/com/intellij/ui/treeStructure/Tree.java b/platform/platform-api/src/com/intellij/ui/treeStructure/Tree.java
index c8c50bc94680..30314135a543 100644
--- a/platform/platform-api/src/com/intellij/ui/treeStructure/Tree.java
+++ b/platform/platform-api/src/com/intellij/ui/treeStructure/Tree.java
@@ -20,14 +20,12 @@ import com.intellij.ide.util.treeView.*;
import com.intellij.openapi.ui.GraphicsConfig;
import com.intellij.openapi.ui.Queryable;
import com.intellij.openapi.util.Condition;
+import com.intellij.openapi.util.Conditions;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.ui.*;
import com.intellij.util.ReflectionUtil;
-import com.intellij.util.ui.AsyncProcessIcon;
-import com.intellij.util.ui.ComponentWithEmptyText;
-import com.intellij.util.ui.StatusText;
-import com.intellij.util.ui.UIUtil;
+import com.intellij.util.ui.*;
import com.intellij.util.ui.tree.WideSelectionTreeUI;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -143,7 +141,7 @@ public class Tree extends JTree implements ComponentWithEmptyText, ComponentWith
@SuppressWarnings("unchecked")
@NotNull
protected Condition<Integer> getWideSelectionBackgroundCondition() {
- return Condition.TRUE;
+ return Conditions.alwaysTrue();
}
@Override
@@ -673,8 +671,8 @@ public class Tree extends JTree implements ComponentWithEmptyText, ComponentWith
private class MyMouseListener extends MouseAdapter {
@Override
public void mousePressed(MouseEvent mouseevent) {
- if (!SwingUtilities.isLeftMouseButton(mouseevent) &&
- (SwingUtilities.isRightMouseButton(mouseevent) || SwingUtilities.isMiddleMouseButton(mouseevent))) {
+ if (!JBSwingUtilities.isLeftMouseButton(mouseevent) &&
+ (JBSwingUtilities.isRightMouseButton(mouseevent) || JBSwingUtilities.isMiddleMouseButton(mouseevent))) {
TreePath treepath = getPathForLocation(mouseevent.getX(), mouseevent.getY());
if (treepath != null) {
if (getSelectionModel().getSelectionMode() != TreeSelectionModel.SINGLE_TREE_SELECTION) {
@@ -842,7 +840,7 @@ public class Tree extends JTree implements ComponentWithEmptyText, ComponentWith
* @return the deepest visible component of the renderer
*/
@Nullable
- protected Component getDeepestRendererComponentAt(int x, int y) {
+ public Component getDeepestRendererComponentAt(int x, int y) {
int row = getRowForLocation(x, y);
if (row >= 0) {
TreeCellRenderer renderer = getCellRenderer();
diff --git a/platform/platform-api/src/com/intellij/util/concurrency/QueueProcessor.java b/platform/platform-api/src/com/intellij/util/concurrency/QueueProcessor.java
index 34238e57c635..ffcb0870dc3c 100644
--- a/platform/platform-api/src/com/intellij/util/concurrency/QueueProcessor.java
+++ b/platform/platform-api/src/com/intellij/util/concurrency/QueueProcessor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2010 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -75,7 +75,7 @@ public class QueueProcessor<T> {
* Constructs a QueueProcessor, which will autostart as soon as the first element is added to it.
*/
public QueueProcessor(@NotNull Consumer<T> processor) {
- this(processor, Condition.FALSE);
+ this(processor, Conditions.alwaysFalse());
}
/**
diff --git a/platform/platform-api/src/com/intellij/util/net/HttpConfigurable.java b/platform/platform-api/src/com/intellij/util/net/HttpConfigurable.java
index 0f9855001b63..757706127a38 100644
--- a/platform/platform-api/src/com/intellij/util/net/HttpConfigurable.java
+++ b/platform/platform-api/src/com/intellij/util/net/HttpConfigurable.java
@@ -61,7 +61,7 @@ import java.util.*;
@Storage(file = StoragePathMacros.APP_CONFIG + "/other.xml"),
@Storage(file = StoragePathMacros.APP_CONFIG + "/proxy.settings.xml")
},
- storageChooser = HttpConfigurable.StorageChooser.class
+ storageChooser = LastStorageChooserForWrite.class
)
public class HttpConfigurable implements PersistentStateComponent<HttpConfigurable>, ExportableApplicationComponent {
public static final int CONNECTION_TIMEOUT = SystemProperties.getIntProperty("idea.connection.timeout", 10000);
@@ -519,20 +519,6 @@ public class HttpConfigurable implements PersistentStateComponent<HttpConfigurab
return "Proxy Settings";
}
- public static class StorageChooser implements StateStorageChooser<HttpConfigurable> {
- @Override
- public Storage[] selectStorages(Storage[] storages, HttpConfigurable component, StateStorageOperation operation) {
- if (operation == StateStorageOperation.WRITE) {
- for (Storage storage : storages) {
- if (storage.file().equals(StoragePathMacros.APP_CONFIG + "/proxy.settings.xml")) {
- return new Storage[] {storage};
- }
- }
- }
- return storages;
- }
- }
-
public static class ProxyInfo {
public boolean myStore;
public String myUsername;
diff --git a/platform/platform-api/src/com/intellij/util/net/ssl/CertificateUtil.java b/platform/platform-api/src/com/intellij/util/net/ssl/CertificateUtil.java
index a1e36236c0e4..ff86990d7d16 100644
--- a/platform/platform-api/src/com/intellij/util/net/ssl/CertificateUtil.java
+++ b/platform/platform-api/src/com/intellij/util/net/ssl/CertificateUtil.java
@@ -1,8 +1,21 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package com.intellij.util.net.ssl;
import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.util.io.StreamUtil;
-import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -13,55 +26,46 @@ import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
/**
+ * Names in constants match
+ * <a href="http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html">Standard Algorithm Name Documentation</a>.
+ *
* @author Mikhail Golubev
*/
public class CertificateUtil {
- private static final Logger LOG = Logger.getInstance(CertificateUtil.class);
+ public static final String X509 = "X.509";
+ public static final String JKS = "JKS";
+ public static final String PKCS12 = "PKCS12";
+ public static final String PKIX = "PKIX";
+ public static final String TLS = "TLS";
private static final CertificateFactory ourFactory = createFactory();
private static CertificateFactory createFactory() {
try {
- return CertificateFactory.getInstance("X509");
+ return CertificateFactory.getInstance(X509);
}
catch (CertificateException e) {
- throw new AssertionError("Can't initialize X509 certificate factory");
+ throw new RuntimeException("Can't initialize X.509 certificate factory", e);
}
}
- // Standard Names
- // See complete reference at http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html
- // certificate format
- @Nls public static final String X509 = "X.509";
- // Java Key Store - standard type of keystores used by keytool utility
- @Nls public static final String JKS = "JKS";
- // another standard type of keystore
- @Nls public static final String PKCS12 = "PKCS12";
- // type of trust manager factory
- @Nls public static final String PKIX = "PKIX";
- @Nls public static final String TLS = "TLS";
-
- /**
- * Utility class
- */
- private CertificateUtil() {
- // empty
- }
+ private CertificateUtil() { }
@Nullable
public static X509Certificate loadX509Certificate(@NotNull String path) {
- InputStream stream = null;
try {
- stream = new FileInputStream(path);
- return (X509Certificate)ourFactory.generateCertificate(stream);
+ InputStream stream = new FileInputStream(path);
+ try {
+ return (X509Certificate)ourFactory.generateCertificate(stream);
+ }
+ finally {
+ stream.close();
+ }
}
catch (Exception e) {
- LOG.error("Can't add certificate for path: " + path, e);
+ Logger.getInstance(CertificateUtil.class).error("Can't add certificate for path: " + path, e);
return null;
}
- finally {
- StreamUtil.closeStream(stream);
- }
}
/**
diff --git a/platform/platform-api/src/com/intellij/util/ui/Animator.java b/platform/platform-api/src/com/intellij/util/ui/Animator.java
index 94da2b15ba7a..55578fe8d994 100644
--- a/platform/platform-api/src/com/intellij/util/ui/Animator.java
+++ b/platform/platform-api/src/com/intellij/util/ui/Animator.java
@@ -64,7 +64,7 @@ public abstract class Animator implements Disposable {
reset();
- if (ApplicationManager.getApplication() == null) {
+ if (noApplication()) {
animationDone();
}
}
@@ -133,8 +133,7 @@ public abstract class Animator implements Disposable {
}
public void resume() {
- final Application app = ApplicationManager.getApplication();
- if (app == null || app.isUnitTestMode()) {
+ if (noApplication()) {
animationDone();
return;
}
@@ -164,6 +163,11 @@ public abstract class Animator implements Disposable {
}
}
+ protected boolean noApplication() {
+ Application app = ApplicationManager.getApplication();
+ return app == null || app.isUnitTestMode();
+ }
+
public abstract void paintNow(int frame, int totalFrames, int cycle);
@Override
diff --git a/platform/platform-impl/platform-impl.iml b/platform/platform-impl/platform-impl.iml
index a0880c4ac95a..ab82f91384ff 100644
--- a/platform/platform-impl/platform-impl.iml
+++ b/platform/platform-impl/platform-impl.iml
@@ -16,7 +16,6 @@
<orderEntry type="library" exported="" name="commons-codec" level="project" />
<orderEntry type="library" name="OroMatcher" level="project" />
<orderEntry type="library" name="XmlRPC" level="project" />
- <orderEntry type="library" name="commons-net" level="project" />
<orderEntry type="library" name="asm" level="project" />
<orderEntry type="library" name="CGLIB" level="project" />
<orderEntry type="module" module-name="lvcs-api" exported="" />
diff --git a/platform/platform-impl/src/com/intellij/concurrency/JobLauncherImpl.java b/platform/platform-impl/src/com/intellij/concurrency/JobLauncherImpl.java
index b33611da8866..876474b9124b 100644
--- a/platform/platform-impl/src/com/intellij/concurrency/JobLauncherImpl.java
+++ b/platform/platform-impl/src/com/intellij/concurrency/JobLauncherImpl.java
@@ -146,19 +146,11 @@ public class JobLauncherImpl extends JobLauncher {
// This implementation is not really async
@NotNull
@Override
- public <T> AsyncFutureResult<Boolean> invokeConcurrentlyUnderProgressAsync(@NotNull List<? extends T> things,
+ public <T> AsyncFuture<Boolean> invokeConcurrentlyUnderProgressAsync(@NotNull List<? extends T> things,
ProgressIndicator progress,
boolean failFastOnAcquireReadAction,
@NotNull Processor<T> thingProcessor) {
- final AsyncFutureResult<Boolean> asyncFutureResult = AsyncFutureFactory.getInstance().createAsyncFutureResult();
- try {
- final boolean result = invokeConcurrentlyUnderProgress(things, progress, failFastOnAcquireReadAction, thingProcessor);
- asyncFutureResult.set(result);
- }
- catch (Throwable t) {
- asyncFutureResult.setException(t);
- }
- return asyncFutureResult;
+ return AsyncUtil.wrapBoolean(invokeConcurrentlyUnderProgress(things, progress, failFastOnAcquireReadAction, thingProcessor));
}
@NotNull
diff --git a/platform/platform-impl/src/com/intellij/designer/DesignerEditorPanelFacade.java b/platform/platform-impl/src/com/intellij/designer/DesignerEditorPanelFacade.java
new file mode 100644
index 000000000000..fa9ecf8610ac
--- /dev/null
+++ b/platform/platform-impl/src/com/intellij/designer/DesignerEditorPanelFacade.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.designer;
+
+import com.intellij.openapi.ui.ThreeComponentsSplitter;
+
+/**
+ * @author Alexander Lobas
+ */
+public interface DesignerEditorPanelFacade {
+ Object getClientProperty(Object key);
+
+ void putClientProperty(Object key, Object value);
+
+ ThreeComponentsSplitter getContentSplitter();
+} \ No newline at end of file
diff --git a/platform/platform-impl/src/com/intellij/designer/LightFillLayout.java b/platform/platform-impl/src/com/intellij/designer/LightFillLayout.java
new file mode 100644
index 000000000000..af0ca87f1e05
--- /dev/null
+++ b/platform/platform-impl/src/com/intellij/designer/LightFillLayout.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.designer;
+
+import com.intellij.util.Function;
+
+import javax.swing.*;
+import java.awt.*;
+
+/**
+ * @author Alexander Lobas
+ */
+public class LightFillLayout implements LayoutManager2 {
+ @Override
+ public void addLayoutComponent(Component comp, Object constraints) {
+ }
+
+ @Override
+ public float getLayoutAlignmentX(Container target) {
+ return 0.5f;
+ }
+
+ @Override
+ public float getLayoutAlignmentY(Container target) {
+ return 0.5f;
+ }
+
+ @Override
+ public void invalidateLayout(Container target) {
+ }
+
+ @Override
+ public void addLayoutComponent(String name, Component comp) {
+ }
+
+ @Override
+ public void removeLayoutComponent(Component comp) {
+ }
+
+ @Override
+ public Dimension maximumLayoutSize(Container target) {
+ return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
+ }
+
+ @Override
+ public Dimension preferredLayoutSize(Container parent) {
+ return layoutSize(parent, new Function<Component, Dimension>() {
+ @Override
+ public Dimension fun(Component component) {
+ return component.getPreferredSize();
+ }
+ });
+ }
+
+ @Override
+ public Dimension minimumLayoutSize(Container parent) {
+ return layoutSize(parent, new Function<Component, Dimension>() {
+ @Override
+ public Dimension fun(Component component) {
+ return component.getMinimumSize();
+ }
+ });
+ }
+
+ private static Dimension layoutSize(Container parent, Function<Component, Dimension> getSize) {
+ Component toolbar = parent.getComponent(0);
+ Dimension toolbarSize = toolbar.isVisible() ? getSize.fun(toolbar) : new Dimension();
+ Dimension contentSize = getSize.fun(parent.getComponent(1));
+ int extraWidth = 0;
+ JComponent jParent = (JComponent)parent;
+ if (jParent.getClientProperty(LightToolWindow.LEFT_MIN_KEY) != null) {
+ extraWidth += LightToolWindow.MINIMIZE_WIDTH;
+ }
+ if (jParent.getClientProperty(LightToolWindow.RIGHT_MIN_KEY) != null) {
+ extraWidth += LightToolWindow.MINIMIZE_WIDTH;
+ }
+ return new Dimension(Math.max(toolbarSize.width, contentSize.width + extraWidth), toolbarSize.height + contentSize.height);
+ }
+
+ @Override
+ public void layoutContainer(Container parent) {
+ int leftWidth = 0;
+ int rightWidth = 0;
+ JComponent jParent = (JComponent)parent;
+ JComponent left = (JComponent)jParent.getClientProperty(LightToolWindow.LEFT_MIN_KEY);
+ if (left != null) {
+ leftWidth = LightToolWindow.MINIMIZE_WIDTH;
+ }
+ JComponent right = (JComponent)jParent.getClientProperty(LightToolWindow.RIGHT_MIN_KEY);
+ if (right != null) {
+ rightWidth = LightToolWindow.MINIMIZE_WIDTH;
+ }
+ int extraWidth = leftWidth + rightWidth;
+
+ int width = parent.getWidth() - extraWidth;
+ int height = parent.getHeight();
+ Component toolbar = parent.getComponent(0);
+ Dimension toolbarSize = toolbar.isVisible() ? toolbar.getPreferredSize() : new Dimension();
+ toolbar.setBounds(leftWidth, 0, width, toolbarSize.height);
+ parent.getComponent(1).setBounds(leftWidth, toolbarSize.height, width, height - toolbarSize.height);
+
+ if (left != null) {
+ left.setBounds(0, 0, leftWidth, height);
+ }
+ if (right != null) {
+ right.setBounds(width + leftWidth, 0, rightWidth, height);
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/ui-designer-core/src/com/intellij/designer/LightToolWindow.java b/platform/platform-impl/src/com/intellij/designer/LightToolWindow.java
index 4bbccfa84934..ce3cb33deb90 100644
--- a/plugins/ui-designer-core/src/com/intellij/designer/LightToolWindow.java
+++ b/platform/platform-impl/src/com/intellij/designer/LightToolWindow.java
@@ -35,6 +35,8 @@ import com.intellij.ui.components.panels.Wrapper;
import com.intellij.ui.tabs.TabsUtil;
import com.intellij.util.ui.EmptyIcon;
import com.intellij.util.ui.UIUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
@@ -47,6 +49,7 @@ import java.awt.image.BufferedImage;
public class LightToolWindow extends JPanel {
public static final String LEFT_MIN_KEY = "left";
public static final String RIGHT_MIN_KEY = "right";
+ public static final int MINIMIZE_WIDTH = 25;
private static final String IGNORE_WIDTH_KEY = "ignore_width";
private final LightToolWindowContent myContent;
@@ -54,7 +57,7 @@ public class LightToolWindow extends JPanel {
private final ThreeComponentsSplitter myContentSplitter;
private ToolWindowAnchor myAnchor;
private final Project myProject;
- private final AbstractToolWindowManager myManager;
+ private final LightToolWindowManager myManager;
private final PropertiesComponent myPropertiesComponent;
private boolean myShowContent;
private final String myShowStateKey;
@@ -79,19 +82,19 @@ public class LightToolWindow extends JPanel {
}
};
- public LightToolWindow(LightToolWindowContent content,
- String title,
- Icon icon,
- JComponent component,
- JComponent focusedComponent,
- ThreeComponentsSplitter contentSplitter,
- ToolWindowAnchor anchor,
- AbstractToolWindowManager manager,
- Project project,
- PropertiesComponent propertiesComponent,
- String key,
+ public LightToolWindow(@NotNull LightToolWindowContent content,
+ @NotNull String title,
+ @NotNull Icon icon,
+ @NotNull JComponent component,
+ @NotNull JComponent focusedComponent,
+ @NotNull ThreeComponentsSplitter contentSplitter,
+ @Nullable ToolWindowAnchor anchor,
+ @NotNull LightToolWindowManager manager,
+ @NotNull Project project,
+ @NotNull PropertiesComponent propertiesComponent,
+ @NotNull String key,
int defaultWidth,
- AnAction[] actions) {
+ @Nullable AnAction[] actions) {
super(new BorderLayout());
myContent = content;
myFocusedComponent = focusedComponent;
@@ -101,8 +104,8 @@ public class LightToolWindow extends JPanel {
myManager = manager;
myPropertiesComponent = propertiesComponent;
- myShowStateKey = AbstractToolWindowManager.EDITOR_MODE + key + ".SHOW";
- myWidthKey = AbstractToolWindowManager.EDITOR_MODE + key + ".WIDTH";
+ myShowStateKey = LightToolWindowManager.EDITOR_MODE + key + ".SHOW";
+ myWidthKey = LightToolWindowManager.EDITOR_MODE + key + ".WIDTH";
HeaderPanel header = new HeaderPanel();
header.setLayout(new BorderLayout());
diff --git a/plugins/ui-designer-core/src/com/intellij/designer/LightToolWindowContent.java b/platform/platform-impl/src/com/intellij/designer/LightToolWindowContent.java
index c3e00f7236f5..c3e00f7236f5 100644
--- a/plugins/ui-designer-core/src/com/intellij/designer/LightToolWindowContent.java
+++ b/platform/platform-impl/src/com/intellij/designer/LightToolWindowContent.java
diff --git a/platform/platform-impl/src/com/intellij/designer/LightToolWindowManager.java b/platform/platform-impl/src/com/intellij/designer/LightToolWindowManager.java
new file mode 100644
index 000000000000..0bfb083dec94
--- /dev/null
+++ b/platform/platform-impl/src/com/intellij/designer/LightToolWindowManager.java
@@ -0,0 +1,323 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.designer;
+
+import com.intellij.ide.util.PropertiesComponent;
+import com.intellij.openapi.actionSystem.ActionGroup;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.DefaultActionGroup;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.components.ProjectComponent;
+import com.intellij.openapi.fileEditor.FileEditor;
+import com.intellij.openapi.fileEditor.FileEditorManager;
+import com.intellij.openapi.fileEditor.FileEditorManagerEvent;
+import com.intellij.openapi.fileEditor.FileEditorManagerListener;
+import com.intellij.openapi.project.DumbAwareRunnable;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.startup.StartupManager;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.openapi.wm.ToolWindow;
+import com.intellij.openapi.wm.ToolWindowAnchor;
+import com.intellij.openapi.wm.ex.ToolWindowEx;
+import com.intellij.util.ParameterizedRunnable;
+import com.intellij.util.messages.MessageBusConnection;
+import com.intellij.util.ui.update.MergingUpdateQueue;
+import com.intellij.util.ui.update.Update;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+
+/**
+ * @author Alexander Lobas
+ */
+public abstract class LightToolWindowManager implements ProjectComponent {
+ public static final String EDITOR_MODE = "UI_DESIGNER_EDITOR_MODE.";
+
+ private final MergingUpdateQueue myWindowQueue = new MergingUpdateQueue(getComponentName(), 200, true, null);
+ protected final Project myProject;
+ protected final FileEditorManager myFileEditorManager;
+ protected volatile ToolWindow myToolWindow;
+ private volatile boolean myToolWindowDisposed;
+
+ private final PropertiesComponent myPropertiesComponent;
+ public final String myEditorModeKey;
+ private ToggleEditorModeAction myLeftEditorModeAction;
+ private ToggleEditorModeAction myRightEditorModeAction;
+
+ private MessageBusConnection myConnection;
+ private final FileEditorManagerListener myListener = new FileEditorManagerListener() {
+ @Override
+ public void fileOpened(@NotNull FileEditorManager source, @NotNull VirtualFile file) {
+ bindToDesigner(getActiveDesigner());
+ }
+
+ @Override
+ public void fileClosed(@NotNull FileEditorManager source, @NotNull VirtualFile file) {
+ ApplicationManager.getApplication().invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ bindToDesigner(getActiveDesigner());
+ }
+ });
+ }
+
+ @Override
+ public void selectionChanged(@NotNull FileEditorManagerEvent event) {
+ bindToDesigner(getDesigner(event.getNewEditor()));
+ }
+ };
+
+ //////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // ToolWindow
+ //
+ //////////////////////////////////////////////////////////////////////////////////////////
+
+ protected LightToolWindowManager(Project project, FileEditorManager fileEditorManager) {
+ myProject = project;
+ myFileEditorManager = fileEditorManager;
+ myPropertiesComponent = PropertiesComponent.getInstance(myProject);
+ myEditorModeKey = EDITOR_MODE + getComponentName() + ".STATE";
+ }
+
+ @Override
+ public void projectOpened() {
+ initToolWindow();
+
+ StartupManager.getInstance(myProject).runWhenProjectIsInitialized(new DumbAwareRunnable() {
+ public void run() {
+ if (getEditorMode() == null) {
+ initListeners();
+ bindToDesigner(getActiveDesigner());
+ }
+ }
+ });
+ }
+
+ @Override
+ public void projectClosed() {
+ if (!myToolWindowDisposed) {
+ disposeComponent();
+ myToolWindowDisposed = true;
+ myToolWindow = null;
+ }
+ }
+
+ private void initListeners() {
+ myConnection = myProject.getMessageBus().connect(myProject);
+ myConnection.subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, myListener);
+ }
+
+ private void removeListeners() {
+ myConnection.disconnect();
+ myConnection = null;
+ }
+
+ @Nullable
+ protected abstract DesignerEditorPanelFacade getDesigner(FileEditor editor);
+
+ @Nullable
+ public DesignerEditorPanelFacade getActiveDesigner() {
+ for (FileEditor editor : myFileEditorManager.getSelectedEditors()) {
+ DesignerEditorPanelFacade designer = getDesigner(editor);
+ if (designer != null) {
+ return designer;
+ }
+ }
+
+ return null;
+ }
+
+ private void bindToDesigner(final DesignerEditorPanelFacade designer) {
+ myWindowQueue.cancelAllUpdates();
+ myWindowQueue.queue(new Update("update") {
+ @Override
+ public void run() {
+ if (myToolWindowDisposed) {
+ return;
+ }
+ if (myToolWindow == null) {
+ if (designer == null) {
+ return;
+ }
+ initToolWindow();
+ }
+ updateToolWindow(designer);
+ }
+ });
+ }
+
+ protected abstract void initToolWindow();
+
+ protected abstract void updateToolWindow(@Nullable DesignerEditorPanelFacade designer);
+
+ protected final void initGearActions() {
+ ToolWindowEx toolWindow = (ToolWindowEx)myToolWindow;
+ toolWindow.setAdditionalGearActions(new DefaultActionGroup(createGearActions()));
+ }
+
+ protected abstract ToolWindowAnchor getAnchor();
+
+ @Override
+ public void initComponent() {
+ }
+
+ @Override
+ public void disposeComponent() {
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // LightToolWindow
+ //
+ //////////////////////////////////////////////////////////////////////////////////////////
+
+ public final ActionGroup createGearActions() {
+ DefaultActionGroup group = new DefaultActionGroup("In Editor Mode", true);
+
+ if (myLeftEditorModeAction == null) {
+ myLeftEditorModeAction = createToggleAction(ToolWindowAnchor.LEFT);
+ }
+ group.add(myLeftEditorModeAction);
+
+ if (myRightEditorModeAction == null) {
+ myRightEditorModeAction = createToggleAction(ToolWindowAnchor.RIGHT);
+ }
+ group.add(myRightEditorModeAction);
+
+ return group;
+ }
+
+ protected abstract ToggleEditorModeAction createToggleAction(ToolWindowAnchor anchor);
+
+ public final void bind(@NotNull DesignerEditorPanelFacade designer) {
+ if (isEditorMode()) {
+ myCreateAction.run(designer);
+ }
+ }
+
+ public final void dispose(@NotNull DesignerEditorPanelFacade designer) {
+ if (isEditorMode()) {
+ disposeContent(designer);
+ }
+ }
+
+ protected final Object getContent(@NotNull DesignerEditorPanelFacade designer) {
+ LightToolWindow toolWindow = (LightToolWindow)designer.getClientProperty(getComponentName());
+ return toolWindow.getContent();
+ }
+
+ protected abstract LightToolWindow createContent(@NotNull DesignerEditorPanelFacade designer);
+
+ protected final LightToolWindow createContent(@NotNull DesignerEditorPanelFacade designer,
+ @NotNull LightToolWindowContent content,
+ @NotNull String title,
+ @NotNull Icon icon,
+ @NotNull JComponent component,
+ @NotNull JComponent focusedComponent,
+ int defaultWidth,
+ @Nullable AnAction[] actions) {
+ return new LightToolWindow(content,
+ title,
+ icon,
+ component,
+ focusedComponent,
+ designer.getContentSplitter(),
+ getEditorMode(),
+ this,
+ myProject,
+ myPropertiesComponent,
+ getComponentName(),
+ defaultWidth,
+ actions);
+ }
+
+ protected final void disposeContent(DesignerEditorPanelFacade designer) {
+ String key = getComponentName();
+ LightToolWindow toolWindow = (LightToolWindow)designer.getClientProperty(key);
+ designer.putClientProperty(key, null);
+ toolWindow.dispose();
+ }
+
+ private final ParameterizedRunnable<DesignerEditorPanelFacade> myCreateAction = new ParameterizedRunnable<DesignerEditorPanelFacade>() {
+ @Override
+ public void run(DesignerEditorPanelFacade designer) {
+ designer.putClientProperty(getComponentName(), createContent(designer));
+ }
+ };
+
+ private final ParameterizedRunnable<DesignerEditorPanelFacade> myUpdateAnchorAction =
+ new ParameterizedRunnable<DesignerEditorPanelFacade>() {
+ @Override
+ public void run(DesignerEditorPanelFacade designer) {
+ LightToolWindow toolWindow = (LightToolWindow)designer.getClientProperty(getComponentName());
+ toolWindow.updateAnchor(getEditorMode());
+ }
+ };
+
+ private final ParameterizedRunnable<DesignerEditorPanelFacade> myDisposeAction = new ParameterizedRunnable<DesignerEditorPanelFacade>() {
+ @Override
+ public void run(DesignerEditorPanelFacade designer) {
+ disposeContent(designer);
+ }
+ };
+
+ private void runUpdateContent(ParameterizedRunnable<DesignerEditorPanelFacade> action) {
+ for (FileEditor editor : myFileEditorManager.getAllEditors()) {
+ DesignerEditorPanelFacade designer = getDesigner(editor);
+ if (designer != null) {
+ action.run(designer);
+ }
+ }
+ }
+
+ protected final boolean isEditorMode() {
+ return getEditorMode() != null;
+ }
+
+ @Nullable
+ final ToolWindowAnchor getEditorMode() {
+ String value = myPropertiesComponent.getValue(myEditorModeKey);
+ if (value == null) {
+ return getAnchor();
+ }
+ return value.equals("ToolWindow") ? null : ToolWindowAnchor.fromText(value);
+ }
+
+ final void setEditorMode(@Nullable ToolWindowAnchor newState) {
+ ToolWindowAnchor oldState = getEditorMode();
+ myPropertiesComponent.setValue(myEditorModeKey, newState == null ? "ToolWindow" : newState.toString());
+
+ if (oldState != null && newState != null) {
+ runUpdateContent(myUpdateAnchorAction);
+ }
+ else if (newState != null) {
+ removeListeners();
+ updateToolWindow(null);
+ runUpdateContent(myCreateAction);
+ }
+ else {
+ runUpdateContent(myDisposeAction);
+ initListeners();
+ bindToDesigner(getActiveDesigner());
+ }
+ }
+
+ final ToolWindow getToolWindow() {
+ return myToolWindow;
+ }
+} \ No newline at end of file
diff --git a/plugins/ui-designer-core/src/com/intellij/designer/ToggleEditorModeAction.java b/platform/platform-impl/src/com/intellij/designer/ToggleEditorModeAction.java
index 238de681c4b2..668a0405f4b2 100644
--- a/plugins/ui-designer-core/src/com/intellij/designer/ToggleEditorModeAction.java
+++ b/platform/platform-impl/src/com/intellij/designer/ToggleEditorModeAction.java
@@ -15,7 +15,6 @@
*/
package com.intellij.designer;
-import com.intellij.designer.palette.PaletteToolWindowManager;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.ToggleAction;
import com.intellij.openapi.project.Project;
@@ -25,12 +24,12 @@ import com.intellij.openapi.wm.ToolWindowAnchor;
/**
* @author Alexander Lobas
*/
-public class ToggleEditorModeAction extends ToggleAction {
- private final AbstractToolWindowManager myManager;
- private final Project myProject;
+public abstract class ToggleEditorModeAction extends ToggleAction {
+ protected final LightToolWindowManager myManager;
+ protected final Project myProject;
private final ToolWindowAnchor myAnchor;
- public ToggleEditorModeAction(AbstractToolWindowManager manager, Project project, ToolWindowAnchor anchor) {
+ public ToggleEditorModeAction(LightToolWindowManager manager, Project project, ToolWindowAnchor anchor) {
super(StringUtil.capitalize(anchor.toString()), "Pin/unpin tool window to " + anchor + " side UI Designer Editor", null);
myManager = manager;
myProject = project;
@@ -47,7 +46,7 @@ public class ToggleEditorModeAction extends ToggleAction {
if (state) {
myManager.setEditorMode(myAnchor);
- AbstractToolWindowManager manager = getOppositeManager();
+ LightToolWindowManager manager = getOppositeManager();
if (manager.getEditorMode() == myAnchor) {
manager.setEditorMode(myAnchor == ToolWindowAnchor.LEFT ? ToolWindowAnchor.RIGHT : ToolWindowAnchor.LEFT);
}
@@ -57,9 +56,5 @@ public class ToggleEditorModeAction extends ToggleAction {
}
}
- private AbstractToolWindowManager getOppositeManager() {
- AbstractToolWindowManager designerManager = DesignerToolWindowManager.getInstance(myProject);
- AbstractToolWindowManager paletteManager = PaletteToolWindowManager.getInstance(myProject);
- return myManager == designerManager ? paletteManager : designerManager;
- }
+ protected abstract LightToolWindowManager getOppositeManager();
} \ No newline at end of file
diff --git a/platform/platform-impl/src/com/intellij/diagnostic/ITNReporter.java b/platform/platform-impl/src/com/intellij/diagnostic/ITNReporter.java
index e430f9fdb513..b951b59ed9dd 100644
--- a/platform/platform-impl/src/com/intellij/diagnostic/ITNReporter.java
+++ b/platform/platform-impl/src/com/intellij/diagnostic/ITNReporter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,11 +16,11 @@
package com.intellij.diagnostic;
import com.intellij.CommonBundle;
-import com.intellij.errorreport.ErrorReportSender;
import com.intellij.errorreport.bean.ErrorBean;
import com.intellij.errorreport.error.InternalEAPException;
import com.intellij.errorreport.error.NoSuchEAPUserException;
import com.intellij.errorreport.error.UpdateAvailableException;
+import com.intellij.errorreport.itn.ITNProxy;
import com.intellij.ide.DataManager;
import com.intellij.ide.plugins.IdeaPluginDescriptor;
import com.intellij.ide.plugins.PluginManager;
@@ -32,6 +32,7 @@ import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.ErrorReportSubmitter;
import com.intellij.openapi.diagnostic.IdeaLoggingEvent;
+import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.diagnostic.SubmittedReportInfo;
import com.intellij.openapi.extensions.PluginId;
import com.intellij.openapi.project.Project;
@@ -39,7 +40,7 @@ import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.Consumer;
import com.intellij.xml.util.XmlStringUtil;
-import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.*;
@@ -49,60 +50,39 @@ import java.awt.*;
*/
public class ITNReporter extends ErrorReportSubmitter {
private static int previousExceptionThreadId = 0;
- private static boolean wasException = false;
- @NonNls private static final String URL_HEADER = "http://www.intellij.net/tracker/idea/viewSCR?publicId=";
+ @Override
public String getReportActionText() {
return DiagnosticBundle.message("error.report.to.jetbrains.action");
}
- public SubmittedReportInfo submit(IdeaLoggingEvent[] events, Component parentComponent) {
- // obsolete API
- return new SubmittedReportInfo(null, "0", SubmittedReportInfo.SubmissionStatus.FAILED);
- }
-
@Override
- public boolean trySubmitAsync(IdeaLoggingEvent[] events,
- String additionalInfo,
- Component parentComponent,
- Consumer<SubmittedReportInfo> consumer) {
- return sendError(events[0], additionalInfo, parentComponent, consumer);
+ public boolean submit(@NotNull IdeaLoggingEvent[] events,
+ String additionalInfo,
+ @NotNull Component parentComponent,
+ @NotNull Consumer<SubmittedReportInfo> consumer) {
+ ErrorBean errorBean = new ErrorBean(events[0].getThrowable(), IdeaLogger.ourLastActionId);
+ return doSubmit(events[0], parentComponent, consumer, errorBean, additionalInfo);
}
/**
- * Could be used to enable error reporting even in release versions from non-internal mode.
- * @return false by default.
+ * Used to enable error reporting even in release versions.
*/
- @SuppressWarnings({"MethodMayBeStatic", "UnusedParameters"})
public boolean showErrorInRelease(IdeaLoggingEvent event) {
return false;
}
- /**
- * @noinspection ThrowablePrintStackTrace
- */
- private static boolean sendError(IdeaLoggingEvent event,
- String additionalInfo,
- final Component parentComponent,
- final Consumer<SubmittedReportInfo> callback) {
- ErrorBean errorBean = new ErrorBean(event.getThrowable(), IdeaLogger.ourLastActionId);
-
- return doSubmit(event, parentComponent, callback, errorBean, additionalInfo);
- }
-
private static boolean doSubmit(final IdeaLoggingEvent event,
- final Component parentComponent,
- final Consumer<SubmittedReportInfo> callback,
- final ErrorBean errorBean,
- final String description) {
+ final Component parentComponent,
+ final Consumer<SubmittedReportInfo> callback,
+ final ErrorBean errorBean,
+ final String description) {
final DataContext dataContext = DataManager.getInstance().getDataContext(parentComponent);
final Project project = CommonDataKeys.PROJECT.getData(dataContext);
- final ErrorReportConfigurable errorReportConfigurable = ErrorReportConfigurable.getInstance();
- if (!errorReportConfigurable.KEEP_ITN_PASSWORD &&
- !StringUtil.isEmpty(errorReportConfigurable.ITN_LOGIN) &&
- StringUtil.isEmpty(errorReportConfigurable.getPlainItnPassword())) {
- final JetBrainsAccountDialog dlg = new JetBrainsAccountDialog(parentComponent);
+ ErrorReportConfigurable settings = ErrorReportConfigurable.getInstance();
+ if (!settings.KEEP_ITN_PASSWORD && !StringUtil.isEmpty(settings.ITN_LOGIN) && StringUtil.isEmpty(settings.getPlainItnPassword())) {
+ JetBrainsAccountDialog dlg = new JetBrainsAccountDialog(parentComponent);
dlg.show();
if (!dlg.isOK()) {
return false;
@@ -129,55 +109,46 @@ public class ITNReporter extends ErrorReportSubmitter {
}
Object data = event.getData();
-
if (data instanceof AbstractMessage) {
errorBean.setAssigneeId(((AbstractMessage)data).getAssigneeId());
}
-
if (data instanceof LogMessageEx) {
errorBean.setAttachments(((LogMessageEx)data).getAttachments());
}
- @NonNls String login = errorReportConfigurable.ITN_LOGIN;
- @NonNls String password = errorReportConfigurable.getPlainItnPassword();
- if (login.trim().length() == 0 && password.trim().length() == 0) {
+ String login = settings.ITN_LOGIN;
+ String password = settings.getPlainItnPassword();
+ if (StringUtil.isEmptyOrSpaces(login) && StringUtil.isEmptyOrSpaces(password)) {
login = "idea_anonymous";
password = "guest";
}
- ErrorReportSender.sendError(project, login, password, errorBean, new Consumer<Integer>() {
- @SuppressWarnings({"AssignmentToStaticFieldFromInstanceMethod"})
+ ITNProxy.sendError(project, login, password, errorBean, new Consumer<Integer>() {
@Override
public void consume(Integer threadId) {
- previousExceptionThreadId = threadId;
- wasException = true;
- final SubmittedReportInfo reportInfo = new SubmittedReportInfo(URL_HEADER + threadId, String.valueOf(threadId),
- SubmittedReportInfo.SubmissionStatus.NEW_ISSUE);
+ updatePreviousThreadId(threadId);
+ String url = ITNProxy.getBrowseUrl(threadId);
+ String linkText = String.valueOf(threadId);
+ final SubmittedReportInfo reportInfo = new SubmittedReportInfo(url, linkText, SubmittedReportInfo.SubmissionStatus.NEW_ISSUE);
callback.consume(reportInfo);
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
StringBuilder text = new StringBuilder();
- final String url = IdeErrorsDialog.getUrl(reportInfo, true);
- IdeErrorsDialog.appendSubmissionInformation(reportInfo, text, url);
- text.append(".");
- if (reportInfo.getStatus() != SubmittedReportInfo.SubmissionStatus.FAILED) {
- text.append("<br/>").append(DiagnosticBundle.message("error.report.gratitude"));
- }
-
- NotificationType type = reportInfo.getStatus() == SubmittedReportInfo.SubmissionStatus.FAILED
- ? NotificationType.ERROR
- : NotificationType.INFORMATION;
- NotificationListener listener = url != null ? new NotificationListener.UrlOpeningListener(true) : null;
- ReportMessages.GROUP.createNotification(ReportMessages.ERROR_REPORT,
- XmlStringUtil.wrapInHtml(text),
- type, listener).setImportant(false).notify(project);
+ IdeErrorsDialog.appendSubmissionInformation(reportInfo, text);
+ text.append('.').append("<br/>").append(DiagnosticBundle.message("error.report.gratitude"));
+ String content = XmlStringUtil.wrapInHtml(text);
+ ReportMessages.GROUP
+ .createNotification(ReportMessages.ERROR_REPORT, content, NotificationType.INFORMATION, NotificationListener.URL_OPENING_LISTENER)
+ .setImportant(false)
+ .notify(project);
}
});
}
}, new Consumer<Exception>() {
@Override
public void consume(final Exception e) {
+ Logger.getInstance(ITNReporter.class).info("reporting failed: " + e);
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
@@ -192,13 +163,12 @@ public class ITNReporter extends ErrorReportSubmitter {
msg = DiagnosticBundle.message("error.report.sending.failure");
}
if (e instanceof UpdateAvailableException) {
- String message = DiagnosticBundle.message(
- "error.report.new.eap.build.message", e.getMessage());
- showMessageDialog(parentComponent, project, message, CommonBundle.getWarningTitle(), Messages.getWarningIcon());
- callback.consume(new SubmittedReportInfo(null, "0", SubmittedReportInfo.SubmissionStatus.FAILED));
+ String message = DiagnosticBundle.message("error.report.new.eap.build.message", e.getMessage());
+ showMessageDialog(parentComponent, project, message, CommonBundle.getWarningTitle(), Messages.getWarningIcon());
+ callback.consume(new SubmittedReportInfo(SubmittedReportInfo.SubmissionStatus.FAILED));
}
else if (showYesNoDialog(parentComponent, project, msg, ReportMessages.ERROR_REPORT, Messages.getErrorIcon()) != Messages.YES) {
- callback.consume(new SubmittedReportInfo(null, "0", SubmittedReportInfo.SubmissionStatus.FAILED));
+ callback.consume(new SubmittedReportInfo(SubmittedReportInfo.SubmissionStatus.FAILED));
}
else {
if (e instanceof NoSuchEAPUserException) {
@@ -225,10 +195,15 @@ public class ITNReporter extends ErrorReportSubmitter {
return true;
}
+ private static void updatePreviousThreadId(Integer threadId) {
+ previousExceptionThreadId = threadId;
+ }
+
private static void showMessageDialog(Component parentComponent, Project project, String message, String title, Icon icon) {
if (parentComponent.isShowing()) {
Messages.showMessageDialog(parentComponent, message, title, icon);
- } else {
+ }
+ else {
Messages.showMessageDialog(project, message, title, icon);
}
}
@@ -237,7 +212,8 @@ public class ITNReporter extends ErrorReportSubmitter {
private static int showYesNoDialog(Component parentComponent, Project project, String message, String title, Icon icon) {
if (parentComponent.isShowing()) {
return Messages.showYesNoDialog(parentComponent, message, title, icon);
- } else {
+ }
+ else {
return Messages.showYesNoDialog(project, message, title, icon);
}
}
diff --git a/platform/platform-impl/src/com/intellij/diagnostic/IdeErrorsDialog.java b/platform/platform-impl/src/com/intellij/diagnostic/IdeErrorsDialog.java
index ac296d677232..a0e96c5d674e 100644
--- a/platform/platform-impl/src/com/intellij/diagnostic/IdeErrorsDialog.java
+++ b/platform/platform-impl/src/com/intellij/diagnostic/IdeErrorsDialog.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -563,9 +563,9 @@ public class IdeErrorsDialog extends DialogWrapper implements MessagePoolListene
String url = null;
if (message.isSubmitted()) {
- final SubmittedReportInfo info = message.getSubmissionInfo();
- url = getUrl(info, getSubmitter(throwable) instanceof ITNReporter);
- appendSubmissionInformation(info, text, url);
+ SubmittedReportInfo info = message.getSubmissionInfo();
+ url = info.getURL();
+ appendSubmissionInformation(info, text);
text.append(". ");
}
else if (message.isSubmitting()) {
@@ -578,33 +578,18 @@ public class IdeErrorsDialog extends DialogWrapper implements MessagePoolListene
myInfoLabel.setHyperlinkTarget(url);
}
- public static void appendSubmissionInformation(SubmittedReportInfo info, StringBuilder out, @Nullable String url) {
+ public static void appendSubmissionInformation(SubmittedReportInfo info, StringBuilder out) {
if (info.getStatus() == SubmittedReportInfo.SubmissionStatus.FAILED) {
out.append(" ").append(DiagnosticBundle.message("error.list.message.submission.failed"));
}
- else {
- if (info.getLinkText() != null) {
- out.append(" ").append(DiagnosticBundle.message("error.list.message.submitted.as.link", url, info.getLinkText()));
- if (info.getStatus() == SubmittedReportInfo.SubmissionStatus.DUPLICATE) {
- out.append(" ").append(DiagnosticBundle.message("error.list.message.duplicate"));
- }
- }
- else {
- out.append(DiagnosticBundle.message("error.list.message.submitted"));
+ else if (info.getURL() != null && info.getLinkText() != null) {
+ out.append(" ").append(DiagnosticBundle.message("error.list.message.submitted.as.link", info.getURL(), info.getLinkText()));
+ if (info.getStatus() == SubmittedReportInfo.SubmissionStatus.DUPLICATE) {
+ out.append(" ").append(DiagnosticBundle.message("error.list.message.duplicate"));
}
}
- }
-
- @Nullable
- public static String getUrl(SubmittedReportInfo info, boolean reportedToJetbrains) {
- if (info.getStatus() == SubmittedReportInfo.SubmissionStatus.FAILED || info.getLinkText() == null) {
- return null;
- }
- if (reportedToJetbrains) {
- return "http://ea.jetbrains.com/browser/ea_reports/" + info.getLinkText();
- }
else {
- return info.getURL();
+ out.append(DiagnosticBundle.message("error.list.message.submitted"));
}
}
@@ -919,38 +904,37 @@ public class IdeErrorsDialog extends DialogWrapper implements MessagePoolListene
private boolean reportMessage(final AbstractMessage logMessage, final boolean dialogClosed) {
final ErrorReportSubmitter submitter = getSubmitter(logMessage.getThrowable());
+ if (submitter == null) return false;
- if (submitter != null) {
- logMessage.setSubmitting(true);
- if (!dialogClosed) {
- updateControls();
- }
- Container parentComponent;
- if (dialogClosed) {
- IdeFrame ideFrame = UIUtil.getParentOfType(IdeFrame.class, getContentPane());
- parentComponent = ideFrame.getComponent();
- }
- else {
- parentComponent = getContentPane();
- }
- return submitter.trySubmitAsync(getEvents(logMessage), logMessage.getAdditionalInfo(), parentComponent,
- new Consumer<SubmittedReportInfo>() {
- @Override
- public void consume(final SubmittedReportInfo submittedReportInfo) {
- logMessage.setSubmitting(false);
- logMessage.setSubmitted(submittedReportInfo);
- ApplicationManager.getApplication().invokeLater(new Runnable() {
- @Override
- public void run() {
- if (!dialogClosed) {
- updateOnSubmit();
- }
- }
- });
- }
- });
+ logMessage.setSubmitting(true);
+ if (!dialogClosed) {
+ updateControls();
}
- return false;
+ Container parentComponent;
+ if (dialogClosed) {
+ IdeFrame ideFrame = UIUtil.getParentOfType(IdeFrame.class, getContentPane());
+ parentComponent = ideFrame.getComponent();
+ }
+ else {
+ parentComponent = getContentPane();
+ }
+
+ return submitter.submit(
+ getEvents(logMessage), logMessage.getAdditionalInfo(), parentComponent, new Consumer<SubmittedReportInfo>() {
+ @Override
+ public void consume(final SubmittedReportInfo submittedReportInfo) {
+ logMessage.setSubmitting(false);
+ logMessage.setSubmitted(submittedReportInfo);
+ ApplicationManager.getApplication().invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ if (!dialogClosed) {
+ updateOnSubmit();
+ }
+ }
+ });
+ }
+ });
}
private IdeaLoggingEvent[] getEvents(final AbstractMessage logMessage) {
diff --git a/platform/platform-impl/src/com/intellij/diagnostic/SubmitPerformanceReportAction.java b/platform/platform-impl/src/com/intellij/diagnostic/SubmitPerformanceReportAction.java
deleted file mode 100644
index 88798381f8a8..000000000000
--- a/platform/platform-impl/src/com/intellij/diagnostic/SubmitPerformanceReportAction.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright 2000-2013 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.intellij.diagnostic;
-
-import com.intellij.openapi.actionSystem.AnAction;
-import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.actionSystem.CommonDataKeys;
-import com.intellij.openapi.application.ApplicationInfo;
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.application.PathManager;
-import com.intellij.openapi.progress.ProgressIndicator;
-import com.intellij.openapi.progress.ProgressManager;
-import com.intellij.openapi.progress.Task;
-import com.intellij.openapi.project.DumbAware;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.ui.Messages;
-import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.util.SystemProperties;
-import com.intellij.util.io.ZipUtil;
-import org.apache.commons.net.ftp.FTPClient;
-import org.apache.commons.net.ftp.FTPReply;
-import org.jetbrains.annotations.NonNls;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.io.*;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.zip.ZipOutputStream;
-
-/**
- * @author yole
- */
-public class SubmitPerformanceReportAction extends AnAction implements DumbAware {
- private final DateFormat myDateFormat = new SimpleDateFormat("yyyyMMdd-HHmmss");
-
- private static final String MESSAGE_TITLE = "Submit Performance Report";
-
- public void actionPerformed(final AnActionEvent e) {
- String reportFileName = "perf_" + ApplicationInfo.getInstance().getBuild().asString() + "_" +
- SystemProperties.getUserName() + "_" + myDateFormat.format(new Date()) + ".zip";
- final File reportPath = new File(SystemProperties.getUserHome(), reportFileName);
- final File logDir = new File(PathManager.getLogPath());
- final Project project = e.getData(CommonDataKeys.PROJECT);
-
- final boolean[] archiveCreated = new boolean[1];
- final boolean completed = ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
- public void run() {
- try {
- ZipOutputStream zip = new ZipOutputStream(new FileOutputStream(reportPath));
- ZipUtil.addDirToZipRecursively(zip, reportPath, logDir, "", new FileFilter() {
- public boolean accept(final File pathname) {
- ProgressManager.checkCanceled();
-
- if (logDir.equals(pathname.getParentFile())) {
- return pathname.getPath().contains("threadDumps");
- }
- return true;
- }
- }, null);
- zip.close();
- archiveCreated[0] = true;
- }
- catch (final IOException ex) {
- ApplicationManager.getApplication().invokeLater(new Runnable() {
- public void run() {
- Messages.showErrorDialog(project, "Failed to create performance report archive: " + ex.getMessage(), MESSAGE_TITLE);
- }
- });
- }
- }
- }, "Collecting Performance Report data", true, project);
-
- if (!completed ||
- !archiveCreated[0]) {
- return;
- }
-
- int rc = Messages.showYesNoDialog(project, "The performance report has been saved to\n" + reportPath +
- "\n\nWould you like to submit it to JetBrains?", MESSAGE_TITLE,
- Messages.getQuestionIcon());
- if (rc == Messages.YES) {
- ProgressManager.getInstance().run(new Task.Backgroundable(project, "Uploading Performance Report") {
- public void run(@NotNull final ProgressIndicator indicator) {
- final String error = uploadFileToFTP(reportPath, "ftp.intellij.net", ".uploads", indicator);
- if (error != null) {
- ApplicationManager.getApplication().invokeLater(new Runnable() {
- public void run() {
- Messages.showErrorDialog(error, MESSAGE_TITLE);
- }
- });
- }
- }
- });
- }
- }
-
- @Nullable
- private static String uploadFileToFTP(final File reportPath, @NonNls final String ftpSite, @NonNls final String directory,
- final ProgressIndicator indicator) {
- FTPClient ftp = new FTPClient();
- ftp.setConnectTimeout(30 * 1000);
- try {
- indicator.setText("Connecting to server...");
- ftp.connect(ftpSite);
- indicator.setText("Connected to server");
-
- if (!ftp.login("anonymous", "anonymous@jetbrains.com")) {
- return "Failed to login";
- }
- indicator.setText("Logged in");
-
- // After connection attempt, you should check the reply code to verify
- // success.
- int reply = ftp.getReplyCode();
-
- if (!FTPReply.isPositiveCompletion(reply)) {
- ftp.disconnect();
- return "FTP server refused connection: " + reply;
- }
- if (!ftp.changeWorkingDirectory(directory)) {
- return "Failed to change directory";
- }
-
- // else won't work behind FW
- ftp.enterLocalPassiveMode();
-
- if (!ftp.setFileType(FTPClient.BINARY_FILE_TYPE)) {
- return "Failed to switch to binary mode";
- }
-
- indicator.setText("Transferring (" + StringUtil.formatFileSize(reportPath.length()) + ")");
- FileInputStream readStream = new FileInputStream(reportPath);
- try {
- if (!ftp.storeFile(reportPath.getName(), readStream)) {
- return "Failed to upload file";
- }
- } catch (IOException e) {
- return "Error during transfer: " + e.getMessage();
- }
- finally {
- readStream.close();
- }
- ftp.logout();
- return null;
- }
- catch (IOException e) {
- return "Failed to upload: " + e.getMessage();
- }
- finally {
- if (ftp.isConnected()) {
- try {
- ftp.disconnect();
- }
- catch (IOException ioe) {
- // do nothing
- }
- }
- }
- }
-}
diff --git a/platform/platform-impl/src/com/intellij/errorreport/ErrorReportSender.java b/platform/platform-impl/src/com/intellij/errorreport/ErrorReportSender.java
deleted file mode 100644
index 7cce2895fd85..000000000000
--- a/platform/platform-impl/src/com/intellij/errorreport/ErrorReportSender.java
+++ /dev/null
@@ -1,98 +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.errorreport;
-
-import com.intellij.diagnostic.DiagnosticBundle;
-import com.intellij.errorreport.bean.ErrorBean;
-import com.intellij.errorreport.itn.ITNProxy;
-import com.intellij.idea.IdeaLogger;
-import com.intellij.openapi.progress.EmptyProgressIndicator;
-import com.intellij.openapi.progress.ProgressIndicator;
-import com.intellij.openapi.progress.ProgressManager;
-import com.intellij.openapi.progress.Task;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.util.Consumer;
-import com.intellij.util.net.HttpConfigurable;
-import org.jetbrains.annotations.NonNls;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * Created by IntelliJ IDEA.
- * User: stathik
- * Date: May 22, 2003
- * Time: 8:57:19 PM
- * To change this template use Options | File Templates.
- */
-public class ErrorReportSender {
- @NonNls public static final String PREPARE_URL = "http://www.intellij.net/";
-
- private ErrorReportSender() {
- }
-
- static class SendTask {
- private final Project myProject;
- private String myLogin;
- private String myPassword;
- private ErrorBean errorBean;
-
- public SendTask(final Project project, ErrorBean errorBean) {
- myProject = project;
- this.errorBean = errorBean;
- }
-
- public void setCredentials(String login, String password) {
- myLogin = login;
- myPassword = password;
- }
-
- public void sendReport(final Consumer<Integer> callback, final Consumer<Exception> errback) {
- Task.Backgroundable task = new Task.Backgroundable(myProject, DiagnosticBundle.message("title.submitting.error.report")) {
- @Override
- public void run(@NotNull ProgressIndicator indicator) {
- try {
- HttpConfigurable.getInstance().prepareURL(PREPARE_URL);
-
- if (!StringUtil.isEmpty(myLogin)) {
- int threadId = ITNProxy.postNewThread(
- myLogin,
- myPassword,
- errorBean,
- IdeaLogger.getOurCompilationTimestamp());
- callback.consume(threadId);
- }
- }
- catch (Exception ex) {
- errback.consume(ex);
- }
- }
- };
- if (myProject == null) {
- task.run(new EmptyProgressIndicator());
- }
- else {
- ProgressManager.getInstance().run(task);
- }
- }
- }
-
- public static void sendError(Project project, String login, String password, ErrorBean error,
- Consumer<Integer> callback, Consumer<Exception> errback) {
- SendTask sendTask = new SendTask(project, error);
- sendTask.setCredentials(login, password);
- sendTask.sendReport(callback, errback);
- }
-}
diff --git a/platform/platform-impl/src/com/intellij/errorreport/bean/ErrorBean.java b/platform/platform-impl/src/com/intellij/errorreport/bean/ErrorBean.java
index 89832a8b7864..d4c17f7a89d7 100644
--- a/platform/platform-impl/src/com/intellij/errorreport/bean/ErrorBean.java
+++ b/platform/platform-impl/src/com/intellij/errorreport/bean/ErrorBean.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,10 +16,9 @@
package com.intellij.errorreport.bean;
import com.intellij.openapi.diagnostic.Attachment;
+import com.intellij.util.ExceptionUtil;
import org.jetbrains.annotations.NonNls;
-import java.io.ByteArrayOutputStream;
-import java.io.PrintStream;
import java.util.Collections;
import java.util.List;
@@ -41,11 +40,7 @@ public class ErrorBean {
public ErrorBean(Throwable throwable, String lastAction) {
if (throwable != null) {
message = throwable.getMessage();
-
- ByteArrayOutputStream stream = new ByteArrayOutputStream();
- //noinspection IOResourceOpenedButNotSafelyClosed
- throwable.printStackTrace(new PrintStream(stream, true));
- stackTrace = stream.toString();
+ stackTrace = ExceptionUtil.getThrowableText(throwable);
}
this.lastAction = lastAction;
}
diff --git a/platform/platform-impl/src/com/intellij/errorreport/itn/ITNProxy.java b/platform/platform-impl/src/com/intellij/errorreport/itn/ITNProxy.java
index ec112437520b..4339b36cbf22 100644
--- a/platform/platform-impl/src/com/intellij/errorreport/itn/ITNProxy.java
+++ b/platform/platform-impl/src/com/intellij/errorreport/itn/ITNProxy.java
@@ -20,202 +20,292 @@ import com.intellij.errorreport.bean.ErrorBean;
import com.intellij.errorreport.error.InternalEAPException;
import com.intellij.errorreport.error.NoSuchEAPUserException;
import com.intellij.errorreport.error.UpdateAvailableException;
+import com.intellij.idea.IdeaLogger;
import com.intellij.openapi.application.Application;
-import com.intellij.openapi.application.ApplicationInfo;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ApplicationNamesInfo;
import com.intellij.openapi.application.ex.ApplicationInfoEx;
import com.intellij.openapi.diagnostic.Attachment;
+import com.intellij.openapi.progress.EmptyProgressIndicator;
+import com.intellij.openapi.progress.ProgressIndicator;
+import com.intellij.openapi.progress.ProgressManager;
+import com.intellij.openapi.progress.Task;
+import com.intellij.openapi.project.Project;
import com.intellij.openapi.updateSettings.impl.UpdateSettings;
-import com.intellij.openapi.util.Couple;
+import com.intellij.openapi.util.SystemInfo;
+import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.util.Consumer;
import com.intellij.util.SystemProperties;
-import com.intellij.util.net.HttpConfigurable;
-import org.jetbrains.annotations.NonNls;
+import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.net.ssl.CertificateUtil;
+import org.jetbrains.annotations.NotNull;
+import javax.net.ssl.*;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
-import java.util.ArrayList;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
import java.util.Calendar;
-import java.util.Iterator;
-import java.util.List;
+import java.util.Map;
+import java.util.Set;
/**
- * Created by IntelliJ IDEA.
- * User: stathik
- * Date: Aug 4, 2003
- * Time: 8:12:00 PM
- * To change this template use Options | File Templates.
+ * @author stathik
+ * @since Aug 4, 2003
*/
public class ITNProxy {
- @NonNls public static final String ENCODING = "UTF8";
- public static final String POST_DELIMITER = "&";
+ private static final String NEW_THREAD_VIEW_URL = "https://ea.jetbrains.com/browser/ea_reports/";
+ private static final String NEW_THREAD_POST_URL = "https://ea-report.jetbrains.com/trackerRpc/idea/createScr";
+ private static final String ENCODING = "UTF8";
+
+ public static void sendError(Project project,
+ final String login,
+ final String password,
+ final ErrorBean error,
+ final Consumer<Integer> callback,
+ final Consumer<Exception> errback) {
+ if (StringUtil.isEmpty(login)) {
+ return;
+ }
- @NonNls public static final String NEW_THREAD_URL = "http://www.intellij.net/trackerRpc/idea/createScr";
+ Task.Backgroundable task = new Task.Backgroundable(project, DiagnosticBundle.message("title.submitting.error.report")) {
+ @Override
+ public void run(@NotNull ProgressIndicator indicator) {
+ try {
+ int threadId = postNewThread(login, password, error);
+ callback.consume(threadId);
+ }
+ catch (Exception ex) {
+ errback.consume(ex);
+ }
+ }
+ };
+
+ if (project == null) {
+ task.run(new EmptyProgressIndicator());
+ }
+ else {
+ ProgressManager.getInstance().run(task);
+ }
+ }
- @NonNls private static final String HTTP_CONTENT_LENGTH = "Content-Length";
- @NonNls private static final String HTTP_CONTENT_TYPE = "Content-Type";
- @NonNls private static final String HTTP_WWW_FORM = "application/x-www-form-urlencoded";
- @NonNls private static final String HTTP_POST = "POST";
+ public static String getBrowseUrl(int threadId) {
+ return NEW_THREAD_VIEW_URL + threadId;
+ }
- public static int postNewThread (String login, String password, ErrorBean error, String compilationTimestamp)
- throws IOException, NoSuchEAPUserException, InternalEAPException, UpdateAvailableException {
+ private static SSLContext ourSslContext;
- @NonNls List<Couple<String>> params = createParametersFor(login,
- password,
- error,
- compilationTimestamp,
- ApplicationManager.getApplication(),
- (ApplicationInfoEx) ApplicationInfo.getInstance(),
- ApplicationNamesInfo.getInstance(),
- UpdateSettings.getInstance());
+ private static int postNewThread(String login, String password, ErrorBean error) throws Exception {
+ if (ourSslContext == null) {
+ ourSslContext = initContext();
+ }
- HttpURLConnection connection = post(new URL(NEW_THREAD_URL), join(params));
+ Map<String, String> params = createParameters(login, password, error);
+ HttpURLConnection connection = post(new URL(NEW_THREAD_POST_URL), join(params));
int responseCode = connection.getResponseCode();
-
if (responseCode != HttpURLConnection.HTTP_OK) {
throw new InternalEAPException(DiagnosticBundle.message("error.http.result.code", responseCode));
}
- String reply;
-
- InputStream is = new BufferedInputStream(connection.getInputStream());
+ String response;
+ InputStream is = connection.getInputStream();
try {
- reply = readFrom(is);
- } finally {
+ byte[] bytes = FileUtil.loadBytes(is);
+ response = new String(bytes, ENCODING);
+ }
+ finally {
is.close();
}
- if ("unauthorized".equals(reply)) {
+ if ("unauthorized".equals(response)) {
throw new NoSuchEAPUserException(login);
}
-
- if (reply.startsWith("update ")) {
- throw new UpdateAvailableException(reply.substring(7));
+ if (response.startsWith("update ")) {
+ throw new UpdateAvailableException(response.substring(7));
}
-
- if (reply.startsWith("message ")) {
- throw new InternalEAPException(reply.substring(8));
+ if (response.startsWith("message ")) {
+ throw new InternalEAPException(response.substring(8));
}
try {
- return Integer.valueOf(reply.trim()).intValue();
- } catch (NumberFormatException ex) {
- // Tibor!!!! :-E
+ return Integer.valueOf(response.trim()).intValue();
+ }
+ catch (NumberFormatException ex) {
throw new InternalEAPException(DiagnosticBundle.message("error.itn.returns.wrong.data"));
}
}
- private static List<Couple<String>> createParametersFor(String login,
- String password,
- ErrorBean error,
- String compilationTimestamp, Application application, ApplicationInfoEx appInfo,
- ApplicationNamesInfo namesInfo,
- UpdateSettings updateSettings) {
- @NonNls List<Couple<String>> params = new ArrayList<Couple<String>>();
-
- params.add(Couple.of("protocol.version", "1"));
+ private static Map<String, String> createParameters(String login, String password, ErrorBean error) {
+ Map<String, String> params = ContainerUtil.newLinkedHashMap(40);
- params.add(Couple.of("user.login", login));
- params.add(Couple.of("user.password", password));
+ params.put("protocol.version", "1");
- params.add(Couple.of("os.name", SystemProperties.getOsName()));
+ params.put("user.login", login);
+ params.put("user.password", password);
- params.add(Couple.of("java.version", SystemProperties.getJavaVersion()));
- params.add(Couple.of("java.vm.vendor", SystemProperties.getJavaVmVendor()));
+ params.put("os.name", SystemProperties.getOsName());
+ params.put("java.version", SystemProperties.getJavaVersion());
+ params.put("java.vm.vendor", SystemProperties.getJavaVmVendor());
- params.add(Couple.of("app.name", namesInfo.getProductName()));
- params.add(Couple.of("app.name.full", namesInfo.getFullProductName()));
- params.add(Couple.of("app.name.version", appInfo.getVersionName()));
- params.add(Couple.of("app.eap", Boolean.toString(appInfo.isEAP())));
- params.add(Couple.of("app.internal", Boolean.toString(application.isInternal())));
- params.add(Couple.of("app.build", appInfo.getBuild().asString()));
- params.add(Couple.of("app.version.major", appInfo.getMajorVersion()));
- params.add(Couple.of("app.version.minor", appInfo.getMinorVersion()));
- params.add(Couple.of("app.build.date", format(appInfo.getBuildDate())));
- params.add(Couple.of("app.build.date.release", format(appInfo.getMajorReleaseBuildDate())));
- params.add(Couple.of("app.compilation.timestamp", compilationTimestamp));
+ ApplicationInfoEx appInfo = ApplicationInfoEx.getInstanceEx();
+ ApplicationNamesInfo namesInfo = ApplicationNamesInfo.getInstance();
+ Application application = ApplicationManager.getApplication();
+ params.put("app.name", namesInfo.getProductName());
+ params.put("app.name.full", namesInfo.getFullProductName());
+ params.put("app.name.version", appInfo.getVersionName());
+ params.put("app.eap", Boolean.toString(appInfo.isEAP()));
+ params.put("app.internal", Boolean.toString(application.isInternal()));
+ params.put("app.build", appInfo.getBuild().asString());
+ params.put("app.version.major", appInfo.getMajorVersion());
+ params.put("app.version.minor", appInfo.getMinorVersion());
+ params.put("app.build.date", format(appInfo.getBuildDate()));
+ params.put("app.build.date.release", format(appInfo.getMajorReleaseBuildDate()));
+ params.put("app.compilation.timestamp", IdeaLogger.getOurCompilationTimestamp());
- params.add(Couple.of("update.channel.status", updateSettings.getSelectedChannelStatus().getCode()));
- params.add(Couple.of("update.ignored.builds", StringUtil.join(updateSettings.getIgnoredBuildNumbers(), ",")));
+ UpdateSettings updateSettings = UpdateSettings.getInstance();
+ params.put("update.channel.status", updateSettings.getSelectedChannelStatus().getCode());
+ params.put("update.ignored.builds", StringUtil.join(updateSettings.getIgnoredBuildNumbers(), ","));
- params.add(Couple.of("plugin.name", error.getPluginName()));
- params.add(Couple.of("plugin.version", error.getPluginVersion()));
+ params.put("plugin.name", error.getPluginName());
+ params.put("plugin.version", error.getPluginVersion());
- params.add(Couple.of("last.action", error.getLastAction()));
- params.add(Couple.of("previous.exception",
- error.getPreviousException() == null ? null : Integer.toString(error.getPreviousException())));
+ params.put("last.action", error.getLastAction());
+ params.put("previous.exception", error.getPreviousException() == null ? null : Integer.toString(error.getPreviousException()));
- params.add(Couple.of("error.message", error.getMessage()));
- params.add(Couple.of("error.stacktrace", error.getStackTrace()));
+ params.put("error.message", error.getMessage());
+ params.put("error.stacktrace", error.getStackTrace());
+ params.put("error.description", error.getDescription());
- params.add(Couple.of("error.description", error.getDescription()));
-
- params.add(Couple.of("assignee.id", error.getAssigneeId() == null ? null : Integer.toString(error.getAssigneeId())));
+ params.put("assignee.id", error.getAssigneeId() == null ? null : Integer.toString(error.getAssigneeId()));
for (Attachment attachment : error.getAttachments()) {
- params.add(Couple.of("attachment.name", attachment.getName()));
- params.add(Couple.of("attachment.value", attachment.getEncodedBytes()));
+ params.put("attachment.name", attachment.getName());
+ params.put("attachment.value", attachment.getEncodedBytes());
}
return params;
}
- private static String readFrom(InputStream is) throws IOException {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- int c;
- while ((c = is.read()) != -1) {
- out.write(c);
- }
- String s = out.toString();
- out.close();
- return s;
- }
-
private static String format(Calendar calendar) {
return calendar == null ? null : Long.toString(calendar.getTime().getTime());
}
+ private static byte[] join(Map<String, String> params) throws UnsupportedEncodingException {
+ StringBuilder builder = new StringBuilder();
+ for (Map.Entry<String, String> param : params.entrySet()) {
+ if (StringUtil.isEmpty(param.getKey())) {
+ throw new IllegalArgumentException(param.toString());
+ }
+ if (builder.length() > 0) {
+ builder.append('&');
+ }
+ if (StringUtil.isNotEmpty(param.getValue())) {
+ builder.append(param.getKey()).append('=').append(URLEncoder.encode(param.getValue(), ENCODING));
+ }
+ }
+ return builder.toString().getBytes(ENCODING);
+ }
+
private static HttpURLConnection post(URL url, byte[] bytes) throws IOException {
- HttpURLConnection connection = (HttpURLConnection)HttpConfigurable.getInstance().openConnection(url.toString());
+ HttpsURLConnection connection = (HttpsURLConnection)url.openConnection();
+
+ connection.setSSLSocketFactory(ourSslContext.getSocketFactory());
+ if (!SystemInfo.isJavaVersionAtLeast("1.7") || !SystemProperties.getBooleanProperty("jsse.enableSNIExtension", true)) {
+ connection.setHostnameVerifier(new EaHostnameVerifier(url.getHost(), "ftp.intellij.net"));
+ }
- connection.setRequestMethod(HTTP_POST);
+ connection.setRequestMethod("POST");
connection.setDoInput(true);
connection.setDoOutput(true);
- connection.setRequestProperty(HTTP_CONTENT_TYPE, String.format("%s; charset=%s", HTTP_WWW_FORM, ENCODING));
- connection.setRequestProperty(HTTP_CONTENT_LENGTH, Integer.toString(bytes.length));
+ connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=" + ENCODING);
+ connection.setRequestProperty("Content-Length", Integer.toString(bytes.length));
- OutputStream out = new BufferedOutputStream(connection.getOutputStream());
+ OutputStream out = connection.getOutputStream();
try {
out.write(bytes);
- out.flush();
- } finally {
+ }
+ finally {
out.close();
}
return connection;
}
- private static byte[] join(List<Couple<String>> params) throws UnsupportedEncodingException {
- StringBuilder builder = new StringBuilder();
-
- Iterator<Couple<String>> it = params.iterator();
-
- while (it.hasNext()) {
- Couple<String> param = it.next();
-
- if (StringUtil.isEmpty(param.first))
- throw new IllegalArgumentException(param.toString());
+ private synchronized static SSLContext initContext() throws GeneralSecurityException, IOException {
+ CertificateFactory cf = CertificateFactory.getInstance(CertificateUtil.X509);
+ Certificate ca = cf.generateCertificate(new ByteArrayInputStream(JB_CA_CERT.getBytes(ENCODING)));
+ KeyStore ks = KeyStore.getInstance(CertificateUtil.JKS);
+ ks.load(null, null);
+ ks.setCertificateEntry("JetBrains CA", ca);
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(CertificateUtil.X509);
+ tmf.init(ks);
+ SSLContext ctx = SSLContext.getInstance("TLS");
+ ctx.init(null, tmf.getTrustManagers(), null);
+ return ctx;
+ }
- if (StringUtil.isNotEmpty(param.second))
- builder.append(param.first).append("=").append(URLEncoder.encode(param.second, ENCODING));
+ private static class EaHostnameVerifier implements HostnameVerifier {
+ private final Set<String> myAllowedHosts;
- if (it.hasNext())
- builder.append(POST_DELIMITER);
+ public EaHostnameVerifier(@NotNull String... allowedHosts) {
+ myAllowedHosts = ContainerUtil.newHashSet(allowedHosts);
}
- return builder.toString().getBytes();
+ @Override
+ public boolean verify(String hostname, SSLSession session) {
+ try {
+ Certificate[] certificates = session.getPeerCertificates();
+ if (certificates.length > 0) {
+ Certificate certificate = certificates[0];
+ if (certificate instanceof X509Certificate) {
+ String cn = CertificateUtil.getCommonName((X509Certificate)certificate);
+ return myAllowedHosts.contains(cn);
+ }
+ }
+ }
+ catch (SSLPeerUnverifiedException ignored) { }
+ return false;
+ }
}
+
+ @SuppressWarnings("SpellCheckingInspection") private static final String JB_CA_CERT =
+ "-----BEGIN CERTIFICATE-----\n" +
+ "MIIFvjCCA6agAwIBAgIQMYHnK1dpIZVCoitWqBwhXjANBgkqhkiG9w0BAQsFADBn\n" +
+ "MRMwEQYKCZImiZPyLGQBGRYDTmV0MRgwFgYKCZImiZPyLGQBGRYISW50ZWxsaUox\n" +
+ "FDASBgoJkiaJk/IsZAEZFgRMYWJzMSAwHgYDVQQDExdKZXRCcmFpbnMgRW50ZXJw\n" +
+ "cmlzZSBDQTAeFw0xMjEyMjkxMDEyMzJaFw0zMjEyMjkxMDIyMzBaMGcxEzARBgoJ\n" +
+ "kiaJk/IsZAEZFgNOZXQxGDAWBgoJkiaJk/IsZAEZFghJbnRlbGxpSjEUMBIGCgmS\n" +
+ "JomT8ixkARkWBExhYnMxIDAeBgNVBAMTF0pldEJyYWlucyBFbnRlcnByaXNlIENB\n" +
+ "MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAzPCE2gPgKECo5CB3BTAw\n" +
+ "4XrrNpg+YwTMzeNNDYs4VdPzBq0snWsbm5qP6z1GBGUTr4agERQUxc4//gZMR0UJ\n" +
+ "89GWVNYPbZ/MrkfyaOiem8xosuZ+7WoFu4nYnKbBBMBA7S2idrPSmPv2wYiHJCY7\n" +
+ "eN2AdViiFSAUeGw/7pIgou92/4Bbm6SSzRBKBYfRIfwq0ZgETSIjhNR5o3XJB5i2\n" +
+ "CkSjMk7kNiMWBaq+Alv+Um/xMFnl5jiq9H7YAALgH/mZHr8ANniSyBwkj4r/7GQ3\n" +
+ "UIYwoLrGxSOSEY9UhEpdqQkRbSSjQiFYMlhYEAtLERK4KZObTuUgdiE6Wk38EOKZ\n" +
+ "wy1eE/EIh8vWBHFSH5opPSK4dyamxj9o5c2g1hJ07ZBUCV/nsrKb+ruMkwBfI286\n" +
+ "+HPTMUmoKuUfSfHZ5TiuF5EvcSD7Df2ZCFpRugPs26FRGvtsiBMEmu4u6fu5RNkh\n" +
+ "s7Ueq6ISblt6dj/youywiAZnyrtNKJVyK0m051g9b2IokHjrk9XTswTqBHDjZKYr\n" +
+ "YG/5jDSSzvR/ptR9YIrHF0a9A6LQLZ6ews4FUO6O/RhiYXV8FggD7ZUg019OBUx3\n" +
+ "rF1L3GBYA8YhYP/N18r8DqOaFgUiRDyeRMbka9OXZ2KJT6iL+mOfg/svSW8lc4Ly\n" +
+ "EgcyJ9sk7MRwrhlp3Kc0W7UCAwEAAaNmMGQwEwYJKwYBBAGCNxQCBAYeBABDAEEw\n" +
+ "CwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFB/HK/yYoWW9\n" +
+ "vr2XAyhcMmV3gSfGMBAGCSsGAQQBgjcVAQQDAgEAMA0GCSqGSIb3DQEBCwUAA4IC\n" +
+ "AQBnYu49dZRBK9W3voy6bgzz64sZfX51/RIA6aaoHAH3U1bC8EepChqWeRgijGCD\n" +
+ "CBvLTk7bk/7fgXPPvL+8RwYaxEewCi7t1RQKqPmNvUnEnw28OLvYLBEO7a4yeN5Y\n" +
+ "YaZwdfVH+0qMvTqMQku5p5Xx3dY+DAm4EqXEFD0svfeMJmOA+R1CIqRz1CXnN2FY\n" +
+ "A+86m7WLmGZ8oWlRUJDa1etqrE3ZxXHH/IunVJOGOfaQVkid3u3ageyUOnMw/iME\n" +
+ "7vi0UNVYVsCjXYZxrzCDLCxtguZaV4rMYvLRt1oUxZ+VnmdVa3aW0W//GQ70sqh2\n" +
+ "KQDtIF6Iumf8ya4vA0+K+AAowOSR/k4jQzlWQdZvJNMHP/Jc0OyJyHEegjtWssrS\n" +
+ "NoRtI6V4j277ugWF1Xpt1x0YxYyGSZTI4rqGLqVT8x6Llr24YaHCdp56rKWC/5ob\n" +
+ "IFZ7tJys7oQqof11ANDExrnHv/FEE39VDlfEIUVGyCpsyKbzO7MPfdOce2bIaQOS\n" +
+ "dQ76TpYClrnezikJgp9MSQmd3+ozs9w1upGynHNGNmVhzZ5sex9voWcGoyjmOFhs\n" +
+ "wg13S9Hjy3VYq8y0krRYLEGLctd4vnxWGzJzUNSnqezwHZRl4v4Ejp3dQUZP+5sY\n" +
+ "1F81Vj1G264YnZAcWp5x3GTI4K6+k9Xx3pwUPcKOYdlpZQ==\n" +
+ "-----END CERTIFICATE-----\n";
}
diff --git a/platform/platform-impl/src/com/intellij/featureStatistics/FeatureUsageTrackerImpl.java b/platform/platform-impl/src/com/intellij/featureStatistics/FeatureUsageTrackerImpl.java
index 21a44f1c6718..78b13aa63940 100644
--- a/platform/platform-impl/src/com/intellij/featureStatistics/FeatureUsageTrackerImpl.java
+++ b/platform/platform-impl/src/com/intellij/featureStatistics/FeatureUsageTrackerImpl.java
@@ -15,10 +15,7 @@
*/
package com.intellij.featureStatistics;
-import com.intellij.openapi.components.PersistentStateComponent;
-import com.intellij.openapi.components.State;
-import com.intellij.openapi.components.Storage;
-import com.intellij.openapi.components.StoragePathMacros;
+import com.intellij.openapi.components.*;
import com.intellij.openapi.project.Project;
import com.intellij.util.xmlb.XmlSerializer;
import org.jdom.Element;
@@ -30,9 +27,9 @@ import java.util.Set;
@SuppressWarnings({"NonPrivateFieldAccessedInSynchronizedContext"})
@State(
- name = "FeatureUsageStatistics",
- storages = {@Storage(
- file = StoragePathMacros.APP_CONFIG + "/feature.usage.statistics.xml")})
+ name = "FeatureUsageStatistics",
+ storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/feature.usage.statistics.xml", roamingType = RoamingType.DISABLED)}
+)
public class FeatureUsageTrackerImpl extends FeatureUsageTracker implements PersistentStateComponent<Element> {
private static final int HOUR = 1000 * 60 * 60;
private static final long DAY = HOUR * 24;
@@ -94,7 +91,7 @@ public class FeatureUsageTrackerImpl extends FeatureUsageTracker implements Pers
if (descriptor != null && System.currentTimeMillis() - descriptor.getLastTimeUsed() > 10 * DAY) {
return true;
}
-
+
return isToBeShown(featureId, project, HOUR);
}
diff --git a/platform/platform-impl/src/com/intellij/ide/ApplicationLoadListener.java b/platform/platform-impl/src/com/intellij/ide/ApplicationLoadListener.java
index f1d11ff938d9..b1432f87e10d 100644
--- a/platform/platform-impl/src/com/intellij/ide/ApplicationLoadListener.java
+++ b/platform/platform-impl/src/com/intellij/ide/ApplicationLoadListener.java
@@ -17,9 +17,10 @@ package com.intellij.ide;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.extensions.ExtensionPointName;
+import org.jetbrains.annotations.NotNull;
public interface ApplicationLoadListener {
ExtensionPointName<ApplicationLoadListener> EP_NAME = ExtensionPointName.create("com.intellij.ApplicationLoadListener");
- void beforeApplicationLoaded(Application application);
+ void beforeApplicationLoaded(@NotNull Application application);
}
diff --git a/platform/platform-impl/src/com/intellij/ide/CommandLineProcessor.java b/platform/platform-impl/src/com/intellij/ide/CommandLineProcessor.java
index c288150bd7ab..293c4a55eeae 100644
--- a/platform/platform-impl/src/com/intellij/ide/CommandLineProcessor.java
+++ b/platform/platform-impl/src/com/intellij/ide/CommandLineProcessor.java
@@ -141,7 +141,7 @@ public class CommandLineProcessor {
starter instanceof ApplicationStarterEx &&
((ApplicationStarterEx)starter).canProcessExternalCommandLine()) {
LOG.info("Processing command with " + starter);
- ((ApplicationStarterEx) starter).processExternalCommandLine(ArrayUtil.toStringArray(args));
+ ((ApplicationStarterEx) starter).processExternalCommandLine(ArrayUtil.toStringArray(args), currentDirectory);
return null;
}
}
diff --git a/platform/platform-impl/src/com/intellij/ide/RecentDirectoryProjectsManager.java b/platform/platform-impl/src/com/intellij/ide/RecentDirectoryProjectsManager.java
index 4189b6adf98b..59b115a43105 100644
--- a/platform/platform-impl/src/com/intellij/ide/RecentDirectoryProjectsManager.java
+++ b/platform/platform-impl/src/com/intellij/ide/RecentDirectoryProjectsManager.java
@@ -34,17 +34,14 @@ import org.jetbrains.annotations.Nullable;
*/
@State(
name = "RecentDirectoryProjectsManager",
- roamingType = RoamingType.DISABLED,
- storages = {
- @Storage(
- file = StoragePathMacros.APP_CONFIG + "/other.xml"
- )}
+ storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/other.xml", roamingType = RoamingType.DISABLED)}
)
public class RecentDirectoryProjectsManager extends RecentProjectsManagerBase {
public RecentDirectoryProjectsManager(MessageBus messageBus) {
super(messageBus);
}
+ @Override
@Nullable
protected String getProjectPath(@NotNull Project project) {
final ProjectBaseDirectory baseDir = ProjectBaseDirectory.getInstance(project);
@@ -52,6 +49,7 @@ public class RecentDirectoryProjectsManager extends RecentProjectsManagerBase {
return baseDirVFile != null ? FileUtil.toSystemDependentName(baseDirVFile.getPath()) : null;
}
+ @Override
protected void doOpenProject(@NotNull String projectPath, Project projectToClose, boolean forceOpenInNewFrame) {
final VirtualFile projectDir = LocalFileSystem.getInstance().findFileByPath(FileUtil.toSystemIndependentName(projectPath));
if (projectDir != null) {
diff --git a/platform/platform-impl/src/com/intellij/ide/RecentProjectsManagerBase.java b/platform/platform-impl/src/com/intellij/ide/RecentProjectsManagerBase.java
index 1a6bffbcd297..7991c3af0104 100644
--- a/platform/platform-impl/src/com/intellij/ide/RecentProjectsManagerBase.java
+++ b/platform/platform-impl/src/com/intellij/ide/RecentProjectsManagerBase.java
@@ -86,6 +86,7 @@ public abstract class RecentProjectsManagerBase implements ProjectManagerListene
messageBus.connect().subscribe(AppLifecycleListener.TOPIC, new MyAppLifecycleListener());
}
+ @Override
public State getState() {
synchronized (myStateLock) {
myState.validateRecentProjects();
@@ -93,6 +94,7 @@ public abstract class RecentProjectsManagerBase implements ProjectManagerListene
}
}
+ @Override
public void loadState(final State state) {
synchronized (myStateLock) {
myState = state;
@@ -212,7 +214,7 @@ public abstract class RecentProjectsManagerBase implements ProjectManagerListene
if (addClearListItem) {
AnAction clearListAction = new DumbAwareAction(IdeBundle.message("action.clear.list")) {
@Override
- public void actionPerformed(AnActionEvent e) {
+ public void actionPerformed(@NotNull AnActionEvent e) {
String message = IdeBundle.message("action.clear.list.message");
String title = IdeBundle.message("action.clear.list.title");
if (Messages.showOkCancelDialog(e.getProject(), message, title, Messages.getQuestionIcon()) == Messages.OK) {
@@ -249,6 +251,7 @@ public abstract class RecentProjectsManagerBase implements ProjectManagerListene
return file.exists() && (!file.isDirectory() || new File(file, Project.DIRECTORY_STORE_FOLDER).exists());
}
+ @Override
public void projectOpened(final Project project) {
String path = getProjectPath(project);
if (path != null) {
@@ -269,6 +272,7 @@ public abstract class RecentProjectsManagerBase implements ProjectManagerListene
}
}
+ @Override
public void projectClosed(final Project project) {
Project[] openProjects = ProjectManager.getInstance().getOpenProjects();
if (openProjects.length > 0) {
@@ -347,6 +351,7 @@ public abstract class RecentProjectsManagerBase implements ProjectManagerListene
}
private class MyAppLifecycleListener extends AppLifecycleListener.Adapter {
+ @Override
public void appFrameCreated(final String[] commandLineArgs, @NotNull final Ref<Boolean> willOpenProject) {
if (!ApplicationManager.getApplication().isHeadlessEnvironment()) {
ProjectManager.getInstance().addProjectManagerListener(RecentProjectsManagerBase.this);
@@ -356,19 +361,23 @@ public abstract class RecentProjectsManagerBase implements ProjectManagerListene
}
}
+ @Override
public void appStarting(Project projectFromCommandLine) {
if (projectFromCommandLine != null) return;
doReopenLastProject();
}
+ @Override
public void projectFrameClosed() {
updateLastProjectPath();
}
+ @Override
public void projectOpenFailed() {
updateLastProjectPath();
}
+ @Override
public void appClosing() {
updateLastProjectPath();
}
diff --git a/platform/platform-impl/src/com/intellij/ide/actions/AboutAction.java b/platform/platform-impl/src/com/intellij/ide/actions/AboutAction.java
index e0c9373bbf2b..43cc4d0be9d8 100644
--- a/platform/platform-impl/src/com/intellij/ide/actions/AboutAction.java
+++ b/platform/platform-impl/src/com/intellij/ide/actions/AboutAction.java
@@ -16,6 +16,7 @@
package com.intellij.ide.actions;
import com.intellij.ide.DataManager;
+import com.intellij.openapi.actionSystem.ActionPlaces;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
@@ -31,7 +32,7 @@ import java.awt.*;
public class AboutAction extends AnAction implements DumbAware {
@Override
public void update(AnActionEvent e) {
- e.getPresentation().setVisible(!SystemInfo.isMacSystemMenu);
+ e.getPresentation().setVisible(!SystemInfo.isMacSystemMenu || !ActionPlaces.MAIN_MENU.equals(e.getPlace()));
e.getPresentation().setDescription("Show information about " + ApplicationNamesInfo.getInstance().getFullProductName());
}
diff --git a/platform/platform-impl/src/com/intellij/ide/actions/AssociateFileType.java b/platform/platform-impl/src/com/intellij/ide/actions/AssociateFileType.java
index 77544ae1d14c..8b1375d9f933 100644
--- a/platform/platform-impl/src/com/intellij/ide/actions/AssociateFileType.java
+++ b/platform/platform-impl/src/com/intellij/ide/actions/AssociateFileType.java
@@ -41,7 +41,7 @@ public class AssociateFileType extends AnAction {
// the action should also be available for files which have been auto-detected as text or as a particular language (IDEA-79574)
haveSmthToDo = FileTypeManager.getInstance().getFileTypeByFileName(file.getName()) == FileTypes.UNKNOWN;
}
- presentation.setVisible(haveSmthToDo || ActionPlaces.MAIN_MENU.equals(e.getPlace()));
+ presentation.setVisible(haveSmthToDo || ActionPlaces.isMainMenuOrActionSearch(e.getPlace()));
presentation.setEnabled(haveSmthToDo);
}
diff --git a/platform/platform-impl/src/com/intellij/ide/actions/BaseShowRecentFilesAction.java b/platform/platform-impl/src/com/intellij/ide/actions/BaseShowRecentFilesAction.java
index 442d09b8b3bd..505d0f5eef3d 100644
--- a/platform/platform-impl/src/com/intellij/ide/actions/BaseShowRecentFilesAction.java
+++ b/platform/platform-impl/src/com/intellij/ide/actions/BaseShowRecentFilesAction.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -39,6 +39,7 @@ import com.intellij.ui.components.JBList;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Function;
import com.intellij.util.IconUtil;
+import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
@@ -53,11 +54,11 @@ import java.io.File;
public abstract class BaseShowRecentFilesAction extends AnAction implements DumbAware {
private static final Color BORDER_COLOR = Gray._135;
- public void actionPerformed(AnActionEvent e) {
+ public void actionPerformed(@NotNull AnActionEvent e) {
show(CommonDataKeys.PROJECT.getData(e.getDataContext()));
}
- public void update(AnActionEvent event){
+ public void update(@NotNull AnActionEvent event){
Presentation presentation = event.getPresentation();
Project project = CommonDataKeys.PROJECT.getData(event.getDataContext());
presentation.setEnabled(project != null);
@@ -93,7 +94,7 @@ public abstract class BaseShowRecentFilesAction extends AnAction implements Dumb
final JList list = new JBList(model);
list.addKeyListener(
new KeyAdapter() {
- public void keyPressed(KeyEvent e) {
+ public void keyPressed(@NotNull KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_DELETE) {
int index = list.getSelectedIndex();
if (index == -1 || index >= list.getModel().getSize()){
@@ -150,7 +151,7 @@ public abstract class BaseShowRecentFilesAction extends AnAction implements Dumb
JPanel footerPanel = new JPanel(new BorderLayout()) {
@Override
- protected void paintComponent(Graphics g) {
+ protected void paintComponent(@NotNull Graphics g) {
super.paintComponent(g);
g.setColor(BORDER_COLOR);
g.drawLine(0, 0, getWidth(), 0);
@@ -237,7 +238,7 @@ public abstract class BaseShowRecentFilesAction extends AnAction implements Dumb
}
@Override
- public void actionPerformed(ActionEvent e) {
+ public void actionPerformed(@NotNull ActionEvent e) {
if (myPopup != null) {
myPopup.cancel();
}
@@ -272,7 +273,7 @@ public abstract class BaseShowRecentFilesAction extends AnAction implements Dumb
return fullText;
}
- public void valueChanged(final ListSelectionEvent e) {
+ public void valueChanged(@NotNull final ListSelectionEvent e) {
//noinspection SSBasedInspection
SwingUtilities.invokeLater(new Runnable() {
public void run() {
diff --git a/platform/platform-impl/src/com/intellij/ide/actions/CreateLauncherScriptAction.java b/platform/platform-impl/src/com/intellij/ide/actions/CreateLauncherScriptAction.java
index 411f2d9d93bb..0b696c8f4496 100644
--- a/platform/platform-impl/src/com/intellij/ide/actions/CreateLauncherScriptAction.java
+++ b/platform/platform-impl/src/com/intellij/ide/actions/CreateLauncherScriptAction.java
@@ -134,12 +134,12 @@ public class CreateLauncherScriptAction extends DumbAwareAction {
private static File createLauncherScriptFile() throws IOException, ExecutionException {
String runPath = PathManager.getHomePath();
+ final String productName = ApplicationNamesInfo.getInstance().getProductName().toLowerCase();
if (!SystemInfo.isMac) {
// for Macs just use "*.app"
- final String productName = ApplicationNamesInfo.getInstance().getProductName().toLowerCase();
runPath += "/bin/" + productName + ".sh";
} else if (runPath.endsWith(CONTENTS)) {
- runPath = runPath.substring(0, runPath.length() - CONTENTS.length());
+ runPath += "/MacOS/" + productName;
}
String launcherContents = ExecUtil.loadTemplate(CreateLauncherScriptAction.class.getClassLoader(), "launcher.py",
newHashMap(asList("$CONFIG_PATH$", "$RUN_PATH$"),
diff --git a/platform/platform-impl/src/com/intellij/ide/actions/ExitAction.java b/platform/platform-impl/src/com/intellij/ide/actions/ExitAction.java
index 52487a57f9f2..3017b8624828 100644
--- a/platform/platform-impl/src/com/intellij/ide/actions/ExitAction.java
+++ b/platform/platform-impl/src/com/intellij/ide/actions/ExitAction.java
@@ -16,6 +16,7 @@
*/
package com.intellij.ide.actions;
+import com.intellij.openapi.actionSystem.ActionPlaces;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.application.ex.ApplicationManagerEx;
@@ -24,7 +25,7 @@ import com.intellij.openapi.util.SystemInfo;
public class ExitAction extends AnAction implements DumbAware {
public void update(AnActionEvent e) {
- e.getPresentation().setVisible(!SystemInfo.isMacSystemMenu);
+ e.getPresentation().setVisible(!SystemInfo.isMacSystemMenu || !ActionPlaces.MAIN_MENU.equals(e.getPlace()));
}
public void actionPerformed(AnActionEvent e) {
diff --git a/platform/platform-impl/src/com/intellij/ide/actions/OccurenceNavigatorActionBase.java b/platform/platform-impl/src/com/intellij/ide/actions/OccurenceNavigatorActionBase.java
index f2314a728913..c7ae78f0cd59 100644
--- a/platform/platform-impl/src/com/intellij/ide/actions/OccurenceNavigatorActionBase.java
+++ b/platform/platform-impl/src/com/intellij/ide/actions/OccurenceNavigatorActionBase.java
@@ -68,14 +68,14 @@ abstract class OccurenceNavigatorActionBase extends AnAction implements DumbAwar
if (project == null) {
presentation.setEnabled(false);
// make it invisible only in main menu to avoid initial invisibility in toolbars
- presentation.setVisible(!ActionPlaces.MAIN_MENU.equals(event.getPlace()));
+ presentation.setVisible(!ActionPlaces.isMainMenuOrActionSearch(event.getPlace()));
return;
}
OccurenceNavigator navigator = getNavigator(event.getDataContext());
if (navigator == null) {
presentation.setEnabled(false);
// make it invisible only in main menu to avoid initial invisibility in toolbars
- presentation.setVisible(!ActionPlaces.MAIN_MENU.equals(event.getPlace()));
+ presentation.setVisible(!ActionPlaces.isMainMenuOrActionSearch(event.getPlace()));
return;
}
presentation.setVisible(true);
diff --git a/platform/platform-impl/src/com/intellij/ide/actions/PinActiveTabAction.java b/platform/platform-impl/src/com/intellij/ide/actions/PinActiveTabAction.java
index ddfc1a3989aa..560082bf9e64 100644
--- a/platform/platform-impl/src/com/intellij/ide/actions/PinActiveTabAction.java
+++ b/platform/platform-impl/src/com/intellij/ide/actions/PinActiveTabAction.java
@@ -116,12 +116,17 @@ public class PinActiveTabAction extends ToggleAction implements DumbAware {
super.update(e);
Presentation presentation = e.getPresentation();
DataContext context = e.getDataContext();
- if (getFile(context) != null) {
- presentation.setEnabledAndVisible(true);
- }
- else {
- Content content = getContent(context);
- presentation.setEnabledAndVisible(content != null && content.isPinnable());
+ EditorWindow window = getEditorWindow(context);
+ if (window == null || window.getOwner().isPreview()) {
+ presentation.setEnabledAndVisible(false);
+ } else {
+ if (getFile(context) != null) {
+ presentation.setEnabledAndVisible(true);
+ }
+ else {
+ Content content = getContent(context);
+ presentation.setEnabledAndVisible(content != null && content.isPinnable());
+ }
}
if (ActionPlaces.EDITOR_TAB_POPUP.equals(e.getPlace()) ||
ViewContext.CELL_POPUP_PLACE.equals(e.getPlace())) {
diff --git a/platform/platform-impl/src/com/intellij/ide/actions/ShowRecentFilesAction.java b/platform/platform-impl/src/com/intellij/ide/actions/ShowRecentFilesAction.java
index 59ac567af38a..abd875af728f 100644
--- a/platform/platform-impl/src/com/intellij/ide/actions/ShowRecentFilesAction.java
+++ b/platform/platform-impl/src/com/intellij/ide/actions/ShowRecentFilesAction.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,13 +25,14 @@ import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
+import org.jetbrains.annotations.NotNull;
/**
* @author Konstantin Bulenkov
*/
public class ShowRecentFilesAction extends DumbAwareAction {
@Override
- public void actionPerformed(AnActionEvent e) {
+ public void actionPerformed(@NotNull AnActionEvent e) {
final Project project = e.getData(CommonDataKeys.PROJECT);
if (project != null) {
FeatureUsageTracker.getInstance().triggerFeatureUsed("navigation.recent.files");
diff --git a/platform/platform-impl/src/com/intellij/ide/actions/ShowSettingsAction.java b/platform/platform-impl/src/com/intellij/ide/actions/ShowSettingsAction.java
index eda6ec9f2d7c..5ced3f0db498 100644
--- a/platform/platform-impl/src/com/intellij/ide/actions/ShowSettingsAction.java
+++ b/platform/platform-impl/src/com/intellij/ide/actions/ShowSettingsAction.java
@@ -34,7 +34,7 @@ public class ShowSettingsAction extends AnAction implements DumbAware {
@Override
public void update(AnActionEvent e) {
- if (SystemInfo.isMac && e.getPlace().equals(ActionPlaces.MAIN_MENU)) {
+ if (SystemInfo.isMac && ActionPlaces.isMainMenuOrActionSearch(e.getPlace())) {
// It's called from Preferences in App menu.
e.getPresentation().setVisible(false);
}
diff --git a/platform/platform-impl/src/com/intellij/ide/actions/ShowSettingsUtilImpl.java b/platform/platform-impl/src/com/intellij/ide/actions/ShowSettingsUtilImpl.java
index 2c5cc5b02282..8d6f806802c2 100644
--- a/platform/platform-impl/src/com/intellij/ide/actions/ShowSettingsUtilImpl.java
+++ b/platform/platform-impl/src/com/intellij/ide/actions/ShowSettingsUtilImpl.java
@@ -75,7 +75,7 @@ public class ShowSettingsUtilImpl extends ShowSettingsUtil {
new IdeConfigurablesGroup()};
return Registry.is("ide.new.settings.dialog")
- ? MixedConfigurableGroup.getGroups(getConfigurables(groups, true))
+ ? new ConfigurableGroup[]{new SortedConfigurableGroup(getConfigurables(groups, true))}
: groups;
}
diff --git a/platform/platform-impl/src/com/intellij/ide/actions/SplitAction.java b/platform/platform-impl/src/com/intellij/ide/actions/SplitAction.java
index fb55f3649484..9e9a349bb3fd 100644
--- a/platform/platform-impl/src/com/intellij/ide/actions/SplitAction.java
+++ b/platform/platform-impl/src/com/intellij/ide/actions/SplitAction.java
@@ -60,7 +60,8 @@ public abstract class SplitAction extends AnAction implements DumbAware {
final int minimum = myCloseSource ? 2 : 1;
final boolean enabled = project != null
&& window != null
- && window.getTabCount() >= minimum;
+ && window.getTabCount() >= minimum
+ && !window.getOwner().isPreview();
event.getPresentation().setEnabled(enabled);
}
}
diff --git a/platform/platform-impl/src/com/intellij/ide/actions/Switcher.java b/platform/platform-impl/src/com/intellij/ide/actions/Switcher.java
index cb35b5a504f9..cecf0f60a803 100644
--- a/platform/platform-impl/src/com/intellij/ide/actions/Switcher.java
+++ b/platform/platform-impl/src/com/intellij/ide/actions/Switcher.java
@@ -94,7 +94,7 @@ public class Switcher extends AnAction implements DumbAware {
public void run() {
synchronized (Switcher.class) {
if (SWITCHER != null) {
- SWITCHER.navigate();
+ SWITCHER.navigate(false);
}
}
}
@@ -135,7 +135,7 @@ public class Switcher extends AnAction implements DumbAware {
@NonNls private static final String SWITCHER_TITLE = "Switcher";
- public void actionPerformed(AnActionEvent e) {
+ public void actionPerformed(@NotNull AnActionEvent e) {
final Project project = CommonDataKeys.PROJECT.getData(e.getDataContext());
if (project == null) return;
@@ -200,7 +200,7 @@ public class Switcher extends AnAction implements DumbAware {
jList.setSelectedIndex(jList.getAnchorSelectionIndex());
}
if (jList.getSelectedIndex() != -1) {
- navigate();
+ navigate(false);
}
}
return true;
@@ -226,7 +226,7 @@ public class Switcher extends AnAction implements DumbAware {
descriptions = new JPanel(new BorderLayout()) {
@Override
- protected void paintComponent(Graphics g) {
+ protected void paintComponent(@NotNull Graphics g) {
super.paintComponent(g);
g.setColor(UIUtil.isUnderDarcula() ? SEPARATOR_COLOR : BORDER_COLOR);
g.drawLine(0, 0, getWidth(), 0);
@@ -249,7 +249,7 @@ public class Switcher extends AnAction implements DumbAware {
final Map<ToolWindow, String> map = ContainerUtil.reverseMap(twShortcuts);
Collections.sort(windows, new Comparator<ToolWindow>() {
@Override
- public int compare(ToolWindow o1, ToolWindow o2) {
+ public int compare(@NotNull ToolWindow o1, @NotNull ToolWindow o2) {
return StringUtil.compare(map.get(o1), map.get(o2), false);
}
});
@@ -297,7 +297,7 @@ public class Switcher extends AnAction implements DumbAware {
toolWindows.addMouseMotionListener(this);
myClickListener.installOn(toolWindows);
toolWindows.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
- public void valueChanged(ListSelectionEvent e) {
+ public void valueChanged(@NotNull ListSelectionEvent e) {
if (!toolWindows.isSelectionEmpty() && !files.isSelectionEmpty()) {
files.clearSelection();
}
@@ -306,7 +306,7 @@ public class Switcher extends AnAction implements DumbAware {
separator = new JPanel() {
@Override
- protected void paintComponent(Graphics g) {
+ protected void paintComponent(@NotNull Graphics g) {
super.paintComponent(g);
g.setColor(SEPARATOR_COLOR);
g.drawLine(0, 0, 0, getHeight());
@@ -374,7 +374,7 @@ public class Switcher extends AnAction implements DumbAware {
JPanel myPanel = new JPanel(new BorderLayout());
JLabel myLabel = new JLabel() {
@Override
- protected void paintComponent(Graphics g) {
+ protected void paintComponent(@NotNull Graphics g) {
GraphicsConfig config = new GraphicsConfig(g);
((Graphics2D)g).setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f));
super.paintComponent(g);
@@ -425,7 +425,7 @@ public class Switcher extends AnAction implements DumbAware {
return fullText;
}
- public void valueChanged(final ListSelectionEvent e) {
+ public void valueChanged(@NotNull final ListSelectionEvent e) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
public void run() {
updatePathLabel();
@@ -466,7 +466,7 @@ public class Switcher extends AnAction implements DumbAware {
files.setSelectionMode(pinned ? ListSelectionModel.MULTIPLE_INTERVAL_SELECTION : ListSelectionModel.SINGLE_SELECTION);
files.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
- public void valueChanged(ListSelectionEvent e) {
+ public void valueChanged(@NotNull ListSelectionEvent e) {
if (!files.isSelectionEmpty() && !toolWindows.isSelectionEmpty()) {
toolWindows.getSelectionModel().clearSelection();
}
@@ -526,21 +526,21 @@ public class Switcher extends AnAction implements DumbAware {
if (isPinnedMode()) {
new AnAction(null ,null ,null) {
@Override
- public void actionPerformed(AnActionEvent e) {
+ public void actionPerformed(@NotNull AnActionEvent e) {
changeSelection();
}
}.registerCustomShortcutSet(CustomShortcutSet.fromString("TAB"), this, myPopup);
new AnAction(null, null, null) {
@Override
- public void actionPerformed(AnActionEvent e) {
+ public void actionPerformed(@NotNull AnActionEvent e) {
//suppress all actions to activate a toolwindow : IDEA-71277
}
}.registerCustomShortcutSet(TW_SHORTCUT, this, myPopup);
new AnAction(null, null, null) {
@Override
- public void actionPerformed(AnActionEvent e) {
+ public void actionPerformed(@NotNull AnActionEvent e) {
if (mySpeedSearch != null && mySpeedSearch.isPopupActive()) {
mySpeedSearch.hidePopup();
} else {
@@ -590,24 +590,24 @@ public class Switcher extends AnAction implements DumbAware {
return ((KeyboardShortcut)shortcutSet.getShortcuts()[0]).getFirstKeyStroke().getModifiers();
}
- public void keyTyped(KeyEvent e) {
+ public void keyTyped(@NotNull KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
- if ((e.getKeyCode() == CTRL_KEY && isAutoHide())
- || e.getKeyCode() == VK_ENTER) {
- navigate();
- } else
- if (e.getKeyCode() == VK_LEFT) {
+ if (e.getKeyCode() == CTRL_KEY && isAutoHide() || e.getKeyCode() == VK_ENTER) {
+ navigate(e.isShiftDown());
+ }
+ else if (e.getKeyCode() == VK_LEFT) {
goLeft();
- } else if (e.getKeyCode() == VK_RIGHT) {
+ }
+ else if (e.getKeyCode() == VK_RIGHT) {
goRight();
}
}
KeyEvent lastEvent;
- public void keyPressed(KeyEvent e) {
- if ((mySpeedSearch != null && mySpeedSearch.isPopupActive()) || lastEvent == e) return;
+ public void keyPressed(@NotNull KeyEvent e) {
+ if (mySpeedSearch != null && mySpeedSearch.isPopupActive() || lastEvent == e) return;
lastEvent = e;
switch (e.getKeyCode()) {
case VK_UP:
@@ -668,7 +668,7 @@ public class Switcher extends AnAction implements DumbAware {
if (value instanceof FileInfo) {
final FileInfo info = (FileInfo)value;
final VirtualFile virtualFile = info.first;
- final FileEditorManagerImpl editorManager = ((FileEditorManagerImpl)FileEditorManager.getInstance(project));
+ final FileEditorManagerImpl editorManager = (FileEditorManagerImpl)FileEditorManager.getInstance(project);
final JList jList = getSelectedList();
final EditorWindow wnd = findAppropriateWindow(info);
if (wnd == null) {
@@ -836,7 +836,7 @@ public class Switcher extends AnAction implements DumbAware {
}
}
- void navigate() {
+ void navigate(final boolean openInNewWindow) {
final Object[] values = getSelectedList().getSelectedValues();
myPopup.closeOk(null);
if (values.length > 0 && values[0] instanceof ToolWindow) {
@@ -850,14 +850,19 @@ public class Switcher extends AnAction implements DumbAware {
if (value instanceof FileInfo) {
final FileInfo info = (FileInfo)value;
- if (info.second != null) {
+ VirtualFile file = info.first;
+ if (openInNewWindow) {
+ manager.openFileInNewWindow(file);
+ }
+ else if (info.second != null) {
EditorWindow wnd = findAppropriateWindow(info);
if (wnd != null) {
- manager.openFileImpl2(wnd, info.first, true);
- manager.addSelectionRecord(info.first, wnd);
+ manager.openFileImpl2(wnd, file, true);
+ manager.addSelectionRecord(file, wnd);
}
- } else {
- manager.openFile(info.first, true, true);
+ }
+ else {
+ manager.openFile(file, true, true);
}
}
}
@@ -873,13 +878,13 @@ public class Switcher extends AnAction implements DumbAware {
return ArrayUtil.contains(info.second, windows) ? info.second : windows.length > 0 ? windows[0] : null;
}
- public void mouseClicked(MouseEvent e) {
+ public void mouseClicked(@NotNull MouseEvent e) {
}
private boolean mouseMovedFirstTime = true;
private JList mouseMoveSrc = null;
private int mouseMoveListIndex = -1;
- public void mouseMoved(MouseEvent e) {
+ public void mouseMoved(@NotNull MouseEvent e) {
if (mouseMovedFirstTime) {
mouseMovedFirstTime = false;
return;
@@ -907,15 +912,15 @@ public class Switcher extends AnAction implements DumbAware {
files.repaint();
}
- public void mousePressed(MouseEvent e) {}
- public void mouseReleased(MouseEvent e) {}
- public void mouseEntered(MouseEvent e) {}
- public void mouseExited(MouseEvent e) {
+ public void mousePressed(@NotNull MouseEvent e) {}
+ public void mouseReleased(@NotNull MouseEvent e) {}
+ public void mouseEntered(@NotNull MouseEvent e) {}
+ public void mouseExited(@NotNull MouseEvent e) {
mouseMoveSrc = null;
mouseMoveListIndex = -1;
repaintLists();
}
- public void mouseDragged(MouseEvent e) {}
+ public void mouseDragged(@NotNull MouseEvent e) {}
private class SwitcherSpeedSearch extends SpeedSearchBase<SwitcherPanel> implements PropertyChangeListener {
private Object[] myElements;
@@ -1031,7 +1036,7 @@ public class Switcher extends AnAction implements DumbAware {
}
@Override
- public void propertyChange(PropertyChangeEvent evt) {
+ public void propertyChange(@NotNull PropertyChangeEvent evt) {
final MyList list = getSelectedList();
final Object value = list.getSelectedValue();
if (project.isDisposed()) {
@@ -1068,7 +1073,7 @@ public class Switcher extends AnAction implements DumbAware {
private Rectangle dBounds;
@Override
- public void layoutContainer(Container target) {
+ public void layoutContainer(@NotNull Container target) {
final JScrollPane scrollPane = UIUtil.getParentOfType(JScrollPane.class, files);
JComponent filesPane = scrollPane != null ? scrollPane : files;
if (sBounds == null || !target.isShowing()) {
@@ -1142,7 +1147,7 @@ public class Switcher extends AnAction implements DumbAware {
}
@Override
- public void processKeyEvent(KeyEvent e) {
+ public void processKeyEvent(@NotNull KeyEvent e) {
super.processKeyEvent(e);
}
}
diff --git a/platform/platform-impl/src/com/intellij/ide/customize/CustomizeIDEWizardDialog.java b/platform/platform-impl/src/com/intellij/ide/customize/CustomizeIDEWizardDialog.java
index af3c193ca9d9..04beaa0f370e 100644
--- a/platform/platform-impl/src/com/intellij/ide/customize/CustomizeIDEWizardDialog.java
+++ b/platform/platform-impl/src/com/intellij/ide/customize/CustomizeIDEWizardDialog.java
@@ -182,9 +182,21 @@ public class CustomizeIDEWizardDialog extends DialogWrapper implements ActionLis
}
@Override
+ public void doCancelAction() {
+ doOKAction();
+ }
+
+ @Override
protected void doOKAction() {
for (AbstractCustomizeWizardStep step : mySteps) {
- if (!step.beforeOkAction()) return;
+ if (!step.beforeOkAction()) {
+ int index = mySteps.indexOf(step);
+ if (myIndex != index) {
+ myIndex = index;
+ initCurrentStep(true);
+ }
+ return;
+ }
}
super.doOKAction();
}
diff --git a/platform/platform-impl/src/com/intellij/ide/dnd/aware/DnDAwareTree.java b/platform/platform-impl/src/com/intellij/ide/dnd/aware/DnDAwareTree.java
index e871ff1872c2..7411c70e5984 100644
--- a/platform/platform-impl/src/com/intellij/ide/dnd/aware/DnDAwareTree.java
+++ b/platform/platform-impl/src/com/intellij/ide/dnd/aware/DnDAwareTree.java
@@ -19,6 +19,7 @@ import com.intellij.ide.dnd.DnDAware;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.ui.treeStructure.Tree;
+import com.intellij.util.ui.JBSwingUtilities;
import com.intellij.util.ui.UIUtil;
import com.intellij.util.ui.tree.TreeUtil;
import com.intellij.util.ui.tree.WideSelectionTreeUI;
@@ -54,7 +55,7 @@ public class DnDAwareTree extends Tree implements DnDAware {
@Override
protected void processMouseMotionEvent(MouseEvent e) {
- if (SystemInfo.isMac && SwingUtilities.isRightMouseButton(e) && e.getID() == MouseEvent.MOUSE_DRAGGED) return;
+ if (SystemInfo.isMac && JBSwingUtilities.isRightMouseButton(e) && e.getID() == MouseEvent.MOUSE_DRAGGED) return;
super.processMouseMotionEvent(e);
}
diff --git a/platform/platform-impl/src/com/intellij/ide/passwordSafe/impl/providers/masterKey/MasterKeyPasswordSafe.java b/platform/platform-impl/src/com/intellij/ide/passwordSafe/impl/providers/masterKey/MasterKeyPasswordSafe.java
index de5d67b5e2d8..4d3a502c253e 100644
--- a/platform/platform-impl/src/com/intellij/ide/passwordSafe/impl/providers/masterKey/MasterKeyPasswordSafe.java
+++ b/platform/platform-impl/src/com/intellij/ide/passwordSafe/impl/providers/masterKey/MasterKeyPasswordSafe.java
@@ -193,7 +193,7 @@ public class MasterKeyPasswordSafe extends BasePasswordSafeProvider {
}
return myKey.get().get();
}
- }, project == null ? Condition.FALSE : project.getDisposed());
+ }, project == null ? Conditions.alwaysFalse() : project.getDisposed());
if (key instanceof byte[]) return (byte[])key;
if (key instanceof PasswordSafeException) throw (PasswordSafeException)key;
diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/PluginManager.java b/platform/platform-impl/src/com/intellij/ide/plugins/PluginManager.java
index 57329fb8fe9d..e88a17416fc1 100644
--- a/platform/platform-impl/src/com/intellij/ide/plugins/PluginManager.java
+++ b/platform/platform-impl/src/com/intellij/ide/plugins/PluginManager.java
@@ -183,6 +183,7 @@ public class PluginManager extends PluginManagerCore {
}
else if (myPlugins2Enable != null && ENABLE.equals(description)) {
disabledPlugins.removeAll(myPlugins2Enable);
+ PluginManagerMain.notifyPluginsWereUpdated("Changes were applied", null);
}
try {
diff --git a/platform/platform-impl/src/com/intellij/ide/ui/AppearanceConfigurable.java b/platform/platform-impl/src/com/intellij/ide/ui/AppearanceConfigurable.java
index cc6e16aba6c2..9accbc5bc6c8 100644
--- a/platform/platform-impl/src/com/intellij/ide/ui/AppearanceConfigurable.java
+++ b/platform/platform-impl/src/com/intellij/ide/ui/AppearanceConfigurable.java
@@ -174,6 +174,9 @@ public class AppearanceConfigurable extends BaseConfigurable implements Searchab
update |= settings.SHOW_EDITOR_TOOLTIP != myComponent.myEditorTooltipCheckBox.isSelected();
settings.SHOW_EDITOR_TOOLTIP = myComponent.myEditorTooltipCheckBox.isSelected();
+ update |= settings.NAVIGATE_TO_PREVIEW != myComponent.myNavigateToPreviewCheckBox.isSelected();
+ settings.NAVIGATE_TO_PREVIEW = myComponent.myNavigateToPreviewCheckBox.isSelected();
+
update |= settings.DISABLE_MNEMONICS_IN_CONTROLS != myComponent.myDisableMnemonicInControlsCheckBox.isSelected();
settings.DISABLE_MNEMONICS_IN_CONTROLS = myComponent.myDisableMnemonicInControlsCheckBox.isSelected();
@@ -280,6 +283,7 @@ public class AppearanceConfigurable extends BaseConfigurable implements Searchab
myComponent.myLeftLayoutCheckBox.setSelected(settings.LEFT_HORIZONTAL_SPLIT);
myComponent.myRightLayoutCheckBox.setSelected(settings.RIGHT_HORIZONTAL_SPLIT);
myComponent.myEditorTooltipCheckBox.setSelected(settings.SHOW_EDITOR_TOOLTIP);
+ myComponent.myNavigateToPreviewCheckBox.setSelected(settings.NAVIGATE_TO_PREVIEW);
myComponent.myDisableMnemonicInControlsCheckBox.setSelected(settings.DISABLE_MNEMONICS_IN_CONTROLS);
boolean alphaModeEnabled = WindowManagerEx.getInstanceEx().isAlphaModeSupported();
@@ -325,6 +329,7 @@ public class AppearanceConfigurable extends BaseConfigurable implements Searchab
isModified |= myComponent.myLeftLayoutCheckBox.isSelected() != settings.LEFT_HORIZONTAL_SPLIT;
isModified |= myComponent.myRightLayoutCheckBox.isSelected() != settings.RIGHT_HORIZONTAL_SPLIT;
isModified |= myComponent.myEditorTooltipCheckBox.isSelected() != settings.SHOW_EDITOR_TOOLTIP;
+ isModified |= myComponent.myNavigateToPreviewCheckBox.isSelected() != settings.NAVIGATE_TO_PREVIEW;
isModified |= myComponent.myHideIconsInQuickNavigation.isSelected() != settings.SHOW_ICONS_IN_QUICK_NAVIGATION;
@@ -397,6 +402,7 @@ public class AppearanceConfigurable extends BaseConfigurable implements Searchab
private JSlider myInitialTooltipDelaySlider;
private ComboBox myPresentationModeFontSize;
private JCheckBox myEditorTooltipCheckBox;
+ private JCheckBox myNavigateToPreviewCheckBox;
private JCheckBox myAllowStatusBar;
private JCheckBox myAllowLineNumbers;
private JCheckBox myAllowAnnotations;
diff --git a/platform/platform-impl/src/com/intellij/ide/ui/AppearancePanel.form b/platform/platform-impl/src/com/intellij/ide/ui/AppearancePanel.form
index 550e8e2482e1..7590feba2ad8 100644
--- a/platform/platform-impl/src/com/intellij/ide/ui/AppearancePanel.form
+++ b/platform/platform-impl/src/com/intellij/ide/ui/AppearancePanel.form
@@ -401,6 +401,14 @@
<text resource-bundle="messages/IdeBundle" key="checkbox.show.editor.preview.popup"/>
</properties>
</component>
+ <component id="3e39" class="javax.swing.JCheckBox" binding="myNavigateToPreviewCheckBox" default-binding="true">
+ <constraints>
+ <grid row="6" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <text resource-bundle="messages/IdeBundle" key="checkbox.use.preview.window"/>
+ </properties>
+ </component>
</children>
</grid>
<grid id="e3cc0" layout-manager="GridLayoutManager" row-count="2" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/LafManagerImpl.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/LafManagerImpl.java
index 1036307e97d7..7e00dc3a9841 100644
--- a/platform/platform-impl/src/com/intellij/ide/ui/laf/LafManagerImpl.java
+++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/LafManagerImpl.java
@@ -87,9 +87,8 @@ import java.util.List;
*/
@State(
name = "LafManager",
- roamingType = RoamingType.PER_PLATFORM,
- storages = {@Storage(
- file = StoragePathMacros.APP_CONFIG + "/options.xml")})
+ storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/options.xml", roamingType = RoamingType.PER_PLATFORM)}
+)
public final class LafManagerImpl extends LafManager implements ApplicationComponent, PersistentStateComponent<Element> {
private static final Logger LOG = Logger.getInstance("#com.intellij.ide.ui.LafManager");
diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.properties b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.properties
index f721abfdb92b..ef0a4214db11 100644
--- a/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.properties
+++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/intellijlaf.properties
@@ -118,6 +118,7 @@ CheckBox.darcula.focused.backgroundColor2.selected=3B98FB
ComboBoxUI=com.intellij.ide.ui.laf.darcula.ui.DarculaComboBoxUI
ComboBox.disabledBackground=e8e8e8
+ComboBox.disabledForeground=777777
ComboBox.squareButton=false
ComboBox.darcula.arrowFillColor=6e9bd5
ComboBox.darcula.arrowFocusedFillColor=2d82ed
diff --git a/platform/platform-impl/src/com/intellij/ide/ui/search/SearchUtil.java b/platform/platform-impl/src/com/intellij/ide/ui/search/SearchUtil.java
index 8febc9ad392a..a0df30abae1c 100644
--- a/platform/platform-impl/src/com/intellij/ide/ui/search/SearchUtil.java
+++ b/platform/platform-impl/src/com/intellij/ide/ui/search/SearchUtil.java
@@ -41,8 +41,6 @@ import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.TitledBorder;
import java.awt.*;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.*;
@@ -314,18 +312,6 @@ public class SearchUtil {
}
}
- public static Runnable lightOptions(final SearchableConfigurable configurable,
- final JComponent component,
- final String option,
- final GlassPanel glassPanel,
- final boolean forceSelect) {
- return new Runnable() {
- public void run() {
- traverseComponentsTree(configurable, glassPanel, component, option, forceSelect);
- }
- };
- }
-
public static String markup(@NonNls @NotNull String textToMarkup, @Nullable String filter) {
if (filter == null || filter.length() == 0) {
return textToMarkup;
@@ -575,80 +561,6 @@ public class SearchUtil {
return null;
}
- public static void showHintPopup(final ConfigurableSearchTextField searchField,
- final JBPopup[] activePopup,
- final Alarm showHintAlarm,
- final Consumer<String> selectConfigurable,
- final Project project) {
- for (JBPopup aPopup : activePopup) {
- if (aPopup != null) {
- aPopup.cancel();
- }
- }
-
- final JBPopup popup = createPopup(searchField, activePopup, showHintAlarm, selectConfigurable, project, 0); //no selection
- if (popup != null) {
- popup.showUnderneathOf(searchField);
- searchField.requestFocusInWindow();
- }
-
- activePopup[0] = popup;
- activePopup[1] = null;
- }
-
-
- public static void registerKeyboardNavigation(final ConfigurableSearchTextField searchField,
- final JBPopup[] activePopup,
- final Alarm showHintAlarm,
- final Consumer<String> selectConfigurable,
- final Project project) {
- final Consumer<Integer> shower = new Consumer<Integer>() {
- public void consume(final Integer direction) {
- if (activePopup[0] != null) {
- activePopup[0].cancel();
- }
-
- if (activePopup[1] != null && activePopup[1].isVisible()) {
- return;
- }
-
- final JBPopup popup = createPopup(searchField, activePopup, showHintAlarm, selectConfigurable, project, direction.intValue());
- if (popup != null) {
- popup.showUnderneathOf(searchField);
- }
- activePopup[0] = null;
- activePopup[1] = popup;
- }
- };
- searchField.registerKeyboardAction(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- shower.consume(1);
- }
- }, KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), JComponent.WHEN_IN_FOCUSED_WINDOW);
- searchField.registerKeyboardAction(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- shower.consume(-1);
- }
- }, KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), JComponent.WHEN_IN_FOCUSED_WINDOW);
-
- searchField.addKeyboardListener(new KeyAdapter() {
- public void keyPressed(KeyEvent e) {
- if (e.getKeyCode() == KeyEvent.VK_ESCAPE && searchField.getText().length() > 0) {
- e.consume();
- if (cancelPopups(activePopup)) return;
- searchField.setText("");
- }
- else if (e.getKeyCode() == KeyEvent.VK_ENTER) {
- searchField.addCurrentTextToHistory();
- cancelPopups(activePopup);
- if (e.getModifiers() == 0) {
- e.consume();
- }
- }
- }
- });
- }
-
private static boolean cancelPopups(final JBPopup[] activePopup) {
for (JBPopup popup : activePopup) {
if (popup != null && popup.isVisible()) {
diff --git a/platform/platform-impl/src/com/intellij/ide/util/ProjectPropertiesComponentImpl.java b/platform/platform-impl/src/com/intellij/ide/util/ProjectPropertiesComponentImpl.java
index e44921e6d5df..4b11b44b2bc9 100644
--- a/platform/platform-impl/src/com/intellij/ide/util/ProjectPropertiesComponentImpl.java
+++ b/platform/platform-impl/src/com/intellij/ide/util/ProjectPropertiesComponentImpl.java
@@ -15,15 +15,13 @@
*/
package com.intellij.ide.util;
-import com.intellij.openapi.components.RoamingType;
import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
import com.intellij.openapi.components.StoragePathMacros;
@State(
- name = "PropertiesComponent",
- roamingType = RoamingType.DISABLED,
- storages = {@Storage(
- file = StoragePathMacros.WORKSPACE_FILE)})
+ name = "PropertiesComponent",
+ storages = {@Storage(file = StoragePathMacros.WORKSPACE_FILE)}
+)
public class ProjectPropertiesComponentImpl extends PropertiesComponentImpl {
}
diff --git a/platform/platform-impl/src/com/intellij/internal/statistic/UsageTrigger.java b/platform/platform-impl/src/com/intellij/internal/statistic/UsageTrigger.java
index 40282a89eded..99e62b9da292 100644
--- a/platform/platform-impl/src/com/intellij/internal/statistic/UsageTrigger.java
+++ b/platform/platform-impl/src/com/intellij/internal/statistic/UsageTrigger.java
@@ -34,7 +34,10 @@ import java.util.Set;
/**
* User: ksafonov
*/
-@State(name = "UsageTrigger", roamingType = RoamingType.DISABLED, storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/statistics.application.usages.xml")})
+@State(
+ name = "UsageTrigger",
+ storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/statistics.application.usages.xml", roamingType = RoamingType.DISABLED)}
+)
public class UsageTrigger implements PersistentStateComponent<UsageTrigger.State> {
public static class State {
@@ -72,7 +75,7 @@ public class UsageTrigger implements PersistentStateComponent<UsageTrigger.State
myState = state;
}
-
+
public static class MyCollector extends UsagesCollector {
private static final GroupDescriptor GROUP = GroupDescriptor.create("features counts", GroupDescriptor.HIGHER_PRIORITY);
@@ -92,5 +95,5 @@ public class UsageTrigger implements PersistentStateComponent<UsageTrigger.State
return GROUP;
}
}
-
+
}
diff --git a/platform/platform-impl/src/com/intellij/internal/statistic/persistence/ApplicationStatisticsPersistenceComponent.java b/platform/platform-impl/src/com/intellij/internal/statistic/persistence/ApplicationStatisticsPersistenceComponent.java
index becc1d3699a0..3acca5fffe96 100644
--- a/platform/platform-impl/src/com/intellij/internal/statistic/persistence/ApplicationStatisticsPersistenceComponent.java
+++ b/platform/platform-impl/src/com/intellij/internal/statistic/persistence/ApplicationStatisticsPersistenceComponent.java
@@ -43,11 +43,7 @@ import java.util.Set;
@State(
name = "StatisticsApplicationUsages",
- roamingType = RoamingType.DISABLED,
- storages = {
- @Storage(
- file = StoragePathMacros.APP_CONFIG + "/statistics.application.usages.xml"
- )}
+ storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/statistics.application.usages.xml", roamingType = RoamingType.DISABLED)}
)
public class ApplicationStatisticsPersistenceComponent extends ApplicationStatisticsPersistence
implements ApplicationComponent, PersistentStateComponent<Element> {
diff --git a/platform/platform-impl/src/com/intellij/internal/statistic/persistence/UsageStatisticsPersistenceComponent.java b/platform/platform-impl/src/com/intellij/internal/statistic/persistence/UsageStatisticsPersistenceComponent.java
index 65298387a902..d60be232c9ea 100644
--- a/platform/platform-impl/src/com/intellij/internal/statistic/persistence/UsageStatisticsPersistenceComponent.java
+++ b/platform/platform-impl/src/com/intellij/internal/statistic/persistence/UsageStatisticsPersistenceComponent.java
@@ -35,11 +35,7 @@ import java.util.Set;
@State(
name = "UsagesStatistic",
- roamingType = RoamingType.DISABLED,
- storages = {
- @Storage(
- file = StoragePathMacros.APP_CONFIG + "/usage.statistics.xml"
- )}
+ storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/usage.statistics.xml", roamingType = RoamingType.DISABLED)}
)
public class UsageStatisticsPersistenceComponent extends BasicSentUsagesPersistenceComponent
implements NamedComponent, PersistentStateComponent<Element> {
diff --git a/platform/platform-impl/src/com/intellij/notification/impl/ui/NotificationsConfigurablePanel.java b/platform/platform-impl/src/com/intellij/notification/impl/ui/NotificationsConfigurablePanel.java
index 2d6a768a92c2..50ca0941f621 100644
--- a/platform/platform-impl/src/com/intellij/notification/impl/ui/NotificationsConfigurablePanel.java
+++ b/platform/platform-impl/src/com/intellij/notification/impl/ui/NotificationsConfigurablePanel.java
@@ -125,6 +125,7 @@ public class NotificationsConfigurablePanel extends JPanel implements Disposable
public NotificationsTable() {
super(new NotificationsTableModel());
+ setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
final TableColumn idColumn = getColumnModel().getColumn(ID_COLUMN);
idColumn.setPreferredWidth(200);
@@ -151,7 +152,7 @@ public class NotificationsConfigurablePanel extends JPanel implements Disposable
displayTypeColumn.setCellRenderer(new ComboBoxTableRenderer<NotificationDisplayType>(NotificationDisplayType.values()) {
@Override
protected void customizeComponent(NotificationDisplayType value, JTable table, boolean isSelected) {
- super.customizeComponent(value, table, isSelected);
+ super.customizeComponent(myDisplayBalloons.isSelected() ? value : NotificationDisplayType.NONE, table, isSelected);
if (!myDisplayBalloons.isSelected() && !isSelected) {
setBackground(UIUtil.getComboBoxDisabledBackground());
setForeground(UIUtil.getComboBoxDisabledForeground());
diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/ComputableActionGroup.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/ComputableActionGroup.java
index b5027fd9df81..3b0e247180b2 100644
--- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/ComputableActionGroup.java
+++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/ComputableActionGroup.java
@@ -55,6 +55,13 @@ public abstract class ComputableActionGroup extends ActionGroup implements DumbA
protected abstract CachedValueProvider<AnAction[]> createChildrenProvider(@NotNull ActionManager actionManager);
public abstract static class Simple extends ComputableActionGroup {
+ protected Simple() {
+ }
+
+ protected Simple(boolean popup) {
+ super(popup);
+ }
+
@NotNull
@Override
protected final CachedValueProvider<AnAction[]> createChildrenProvider(@NotNull final ActionManager actionManager) {
diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/ex/QuickListsManager.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/ex/QuickListsManager.java
index bf7c79695c94..eb9436481767 100644
--- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/ex/QuickListsManager.java
+++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/ex/QuickListsManager.java
@@ -70,10 +70,10 @@ public class QuickListsManager implements ExportableApplicationComponent, NamedJ
return loadListFromDocument(schemeContent);
}
- public Document writeScheme(@NotNull final QuickList scheme) throws WriteExternalException {
+ public Element writeScheme(@NotNull final QuickList scheme) throws WriteExternalException {
Element element = new Element(LIST_TAG);
scheme.writeExternal(element);
- return new Document(element);
+ return element;
}
public boolean shouldBeSaved(@NotNull final QuickList scheme) {
diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/AbbreviationManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/AbbreviationManagerImpl.java
index 0d116c7a927f..fd96e54fc98e 100644
--- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/AbbreviationManagerImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/AbbreviationManagerImpl.java
@@ -31,11 +31,7 @@ import java.util.*;
*/
@State(
name = "AbbreviationManager",
- roamingType = RoamingType.PER_PLATFORM,
- storages = {
- @Storage(
- file = StoragePathMacros.APP_CONFIG + "/abbreviations.xml"
- )}
+ storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/abbreviations.xml", roamingType = RoamingType.PER_PLATFORM)}
)
public class AbbreviationManagerImpl extends AbbreviationManager implements
ExportableComponent, PersistentStateComponent<Element> {
diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionManagerImpl.java
index c5a9b01c4d21..32e823bd9758 100644
--- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionManagerImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ActionManagerImpl.java
@@ -70,6 +70,7 @@ import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.util.List;
+import java.util.concurrent.Future;
public final class ActionManagerImpl extends ActionManagerEx implements ApplicationComponent {
@NonNls public static final String ACTION_ELEMENT_NAME = "action";
@@ -360,7 +361,7 @@ public final class ActionManagerImpl extends ActionManagerEx implements Applicat
}
private static void assertActionIsGroupOrStub(final AnAction action) {
- if (!(action instanceof ActionGroup || action instanceof ActionStub)) {
+ if (!(action instanceof ActionGroup || action instanceof ActionStub || action instanceof ChameleonAction)) {
LOG.error("Action : " + action + "; class: " + action.getClass());
}
}
@@ -520,11 +521,9 @@ public final class ActionManagerImpl extends ActionManagerEx implements Applicat
LOG.assertTrue(action.equals(stub));
AnAction anAction = convertStub(stub);
-
- addToMap(stub.getId(), anAction, stub.getPluginId(), stub.getProjectType() == null ? null : new ProjectType(stub.getProjectType()));
myAction2Id.put(anAction, stub.getId());
- return anAction;
+ return addToMap(stub.getId(), anAction, stub.getPluginId(), stub.getProjectType());
}
@Override
@@ -653,7 +652,7 @@ public final class ActionManagerImpl extends ActionManagerEx implements Applicat
}
}
else {
- registerAction(id, action, pluginId);
+ registerAction(id, action, pluginId, element.getAttributeValue(PROJECT_TYPE));
}
}
}
@@ -991,8 +990,12 @@ public final class ActionManagerImpl extends ActionManagerEx implements Applicat
@Override
public void registerAction(@NotNull String actionId, @NotNull AnAction action, @Nullable PluginId pluginId) {
+ registerAction(actionId, action, pluginId, null);
+ }
+
+ public void registerAction(@NotNull String actionId, @NotNull AnAction action, @Nullable PluginId pluginId, @Nullable String projectType) {
synchronized (myLock) {
- if (!addToMap(actionId, action, pluginId, null)) return;
+ if (addToMap(actionId, action, pluginId, projectType) == null) return;
if (myAction2Id.containsKey(action)) {
reportActionError(pluginId, "action was already registered for another ID. ID is " + myAction2Id.get(action) +
getPluginInfo(pluginId));
@@ -1012,31 +1015,42 @@ public final class ActionManagerImpl extends ActionManagerEx implements Applicat
}
}
- public boolean addToMap(String actionId, AnAction action, PluginId pluginId, ProjectType projectType) {
- if (myId2Action.containsKey(actionId)) {
- // make sure id+projectType is unique
- AnAction o = myId2Action.get(actionId);
- ChameleonAction chameleonAction;
- if (o instanceof ChameleonAction) {
- chameleonAction = (ChameleonAction)o;
- }
- else {
- chameleonAction = new ChameleonAction(o, projectType);
- myId2Action.put(actionId, chameleonAction);
- }
- AnAction old = chameleonAction.addAction(action, projectType);
- if (old != null) {
- reportActionError(pluginId,
- "action with the ID \"" + actionId + "\" was already registered. Action being registered is " + action +
- "; Registered action is " +
- myId2Action.get(actionId) + getPluginInfo(pluginId));
- return false;
- }
+ private AnAction addToMap(String actionId, AnAction action, PluginId pluginId, String projectType) {
+ if (projectType != null || myId2Action.containsKey(actionId)) {
+ return registerChameleon(actionId, action, pluginId, projectType);
}
else {
myId2Action.put(actionId, action);
+ return action;
}
- return true;
+ }
+
+ private AnAction registerChameleon(String actionId, AnAction action, PluginId pluginId, String projectType) {
+ ProjectType type = projectType == null ? null : new ProjectType(projectType);
+ // make sure id+projectType is unique
+ AnAction o = myId2Action.get(actionId);
+ ChameleonAction chameleonAction;
+ if (o == null) {
+ chameleonAction = new ChameleonAction(action, type);
+ myId2Action.put(actionId, chameleonAction);
+ return chameleonAction;
+ }
+ if (o instanceof ChameleonAction) {
+ chameleonAction = (ChameleonAction)o;
+ }
+ else {
+ chameleonAction = new ChameleonAction(o, type);
+ myId2Action.put(actionId, chameleonAction);
+ }
+ AnAction old = chameleonAction.addAction(action, type);
+ if (old != null) {
+ reportActionError(pluginId,
+ "action with the ID \"" + actionId + "\" was already registered. Action being registered is " + action +
+ "; Registered action is " +
+ myId2Action.get(actionId) + getPluginInfo(pluginId));
+ return null;
+ }
+ return chameleonAction;
}
@Override
@@ -1053,7 +1067,7 @@ public final class ActionManagerImpl extends ActionManagerEx implements Applicat
return;
}
}
- AnAction oldValue = (AnAction)myId2Action.remove(actionId);
+ AnAction oldValue = myId2Action.remove(actionId);
myAction2Id.remove(oldValue);
myId2Index.remove(actionId);
for (PluginId pluginName : myPlugin2Id.keySet()) {
@@ -1251,7 +1265,7 @@ public final class ActionManagerImpl extends ActionManagerEx implements Applicat
}
}
- public void preloadActions() {
+ public Future<?> preloadActions() {
if (myPreloadActionsRunnable == null) {
myPreloadActionsRunnable = new Runnable() {
@Override
@@ -1262,8 +1276,9 @@ public final class ActionManagerImpl extends ActionManagerEx implements Applicat
}
}
};
- ApplicationManager.getApplication().executeOnPooledThread(myPreloadActionsRunnable);
+ return ApplicationManager.getApplication().executeOnPooledThread(myPreloadActionsRunnable);
}
+ return null;
}
private void doPreloadActions() {
diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ChameleonAction.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ChameleonAction.java
index 4b46dc191c0c..f4e92f7eae02 100644
--- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ChameleonAction.java
+++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/ChameleonAction.java
@@ -15,14 +15,13 @@
*/
package com.intellij.openapi.actionSystem.impl;
-import com.intellij.openapi.actionSystem.ActionStub;
-import com.intellij.openapi.actionSystem.AnAction;
-import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.actionSystem.CommonDataKeys;
+import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectType;
import com.intellij.openapi.project.ProjectTypeService;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.TestOnly;
import java.util.HashMap;
import java.util.Map;
@@ -36,6 +35,7 @@ public class ChameleonAction extends AnAction {
public ChameleonAction(@NotNull AnAction first, ProjectType projectType) {
addAction(first, projectType);
+ copyFrom(myActions.values().iterator().next());
}
public AnAction addAction(AnAction action, ProjectType projectType) {
@@ -48,21 +48,35 @@ public class ChameleonAction extends AnAction {
}
@Override
- public void actionPerformed(AnActionEvent e) {
- getAction(e).actionPerformed(e);
+ public void actionPerformed(@NotNull AnActionEvent e) {
+ AnAction action = getAction(e);
+ assert action != null;
+ action.actionPerformed(e);
}
@Override
- public void update(AnActionEvent e) {
- super.update(e);
+ public void update(@NotNull AnActionEvent e) {
+ AnAction action = getAction(e);
+ if (action != null) {
+ e.getPresentation().setVisible(true);
+ action.update(e);
+ }
+ else {
+ e.getPresentation().setVisible(false);
+ }
}
+ @Nullable
private AnAction getAction(AnActionEvent e) {
Project project = CommonDataKeys.PROJECT.getData(e.getDataContext());
ProjectType projectType = ProjectTypeService.getProjectType(project);
AnAction action = myActions.get(projectType);
if (action == null) action = myActions.get(null);
- if (action == null) action = myActions.values().iterator().next();
return action;
}
+
+ @TestOnly
+ public Map<ProjectType, AnAction> getActions() {
+ return myActions;
+ }
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/Utils.java b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/Utils.java
index 85c0555f9bc6..9af1d30c28bf 100644
--- a/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/Utils.java
+++ b/platform/platform-impl/src/com/intellij/openapi/actionSystem/impl/Utils.java
@@ -26,6 +26,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.ActionCallback;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.registry.Registry;
+import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NonNls;
@@ -164,7 +165,7 @@ public class Utils{
}
}
else if (child instanceof Separator) {
- if (!list.isEmpty() && !(list.get(list.size() - 1) instanceof Separator)) {
+ if (!StringUtil.isEmpty(((Separator)child).getText()) || (!list.isEmpty() && !(list.get(list.size() - 1) instanceof Separator))) {
list.add(child);
}
}
@@ -284,8 +285,10 @@ public class Utils{
for (int i = 0, size = list.size(); i < size; i++) {
final AnAction action = list.get(i);
if (action instanceof Separator) {
- if (i > 0 && i < size - 1) {
+ final String text = ((Separator)action).getText();
+ if (!StringUtil.isEmpty(text) || (i > 0 && i < size - 1)) {
component.add(new JPopupMenu.Separator() {
+ private final JMenuItem myMenu = !StringUtil.isEmpty(text) ? new JMenuItem(text) : null;
@Override
public Insets getInsets() {
final Insets insets = super.getInsets();
@@ -296,12 +299,29 @@ public class Utils{
}
@Override
+ public void doLayout() {
+ super.doLayout();
+ if (myMenu != null) {
+ myMenu.setBounds(getBounds());
+ }
+ }
+
+ @Override
protected void paintComponent(Graphics g) {
if (UIUtil.isUnderWindowsClassicLookAndFeel() || UIUtil.isUnderDarcula() || UIUtil.isUnderWindowsLookAndFeel()) {
g.setColor(component.getBackground());
g.fillRect(0, 0, getWidth(), getHeight());
}
- super.paintComponent(g);
+ if (myMenu != null) {
+ myMenu.paint(g);
+ } else {
+ super.paintComponent(g);
+ }
+ }
+
+ @Override
+ public Dimension getPreferredSize() {
+ return myMenu != null ? myMenu.getPreferredSize() : super.getPreferredSize();
}
});
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/application/PluginPathManager.java b/platform/platform-impl/src/com/intellij/openapi/application/PluginPathManager.java
index 1ab050053e28..9bad9d2d3774 100644
--- a/platform/platform-impl/src/com/intellij/openapi/application/PluginPathManager.java
+++ b/platform/platform-impl/src/com/intellij/openapi/application/PluginPathManager.java
@@ -16,8 +16,10 @@
package com.intellij.openapi.application;
import com.intellij.openapi.util.io.FileUtil;
+import org.jetbrains.annotations.NotNull;
import java.io.File;
+import java.io.FileFilter;
import java.util.*;
/**
@@ -32,26 +34,38 @@ public class PluginPathManager {
private static List<File> findSubrepos() {
List<File> result = new ArrayList<File>();
- File[] subdirs = new File(PathManager.getHomePath()).listFiles();
- if (subdirs == null) return result;
- Arrays.sort(subdirs, new Comparator<File>() {
+ File[] gitRoots = getSortedGitRoots(new File(PathManager.getHomePath()));
+ for (File subdir : gitRoots) {
+ File pluginsDir = new File(subdir, "plugins");
+ if (pluginsDir.exists()) {
+ result.add(pluginsDir);
+ }
+ else {
+ result.add(subdir);
+ }
+ result.addAll(Arrays.asList(getSortedGitRoots(subdir)));
+ }
+ return result;
+ }
+
+ @NotNull
+ private static File[] getSortedGitRoots(@NotNull File dir) {
+ File[] gitRoots = dir.listFiles(new FileFilter() {
+ @Override
+ public boolean accept(File child) {
+ return child.isDirectory() && new File(child, ".git").exists();
+ }
+ });
+ if (gitRoots == null) {
+ return new File[0];
+ }
+ Arrays.sort(gitRoots, new Comparator<File>() {
@Override
public int compare(File file, File file2) {
return FileUtil.compareFiles(file, file2);
}
});
- for (File subdir : subdirs) {
- if (new File(subdir, ".git").exists()) {
- File pluginsDir = new File(subdir, "plugins");
- if (pluginsDir.exists()) {
- result.add(pluginsDir);
- }
- else {
- result.add(subdir);
- }
- }
- }
- return result;
+ return gitRoots;
}
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java
index e3a36a2e59ab..a8eca00b505e 100644
--- a/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/application/impl/ApplicationImpl.java
@@ -531,10 +531,10 @@ public class ApplicationImpl extends PlatformComponentManagerImpl implements App
@Override
public void load(@Nullable String optionsPath) throws IOException {
- load(PathManager.getConfigPath(), optionsPath);
+ load(PathManager.getConfigPath(), optionsPath == null ? PathManager.getOptionsPath() : optionsPath);
}
- public void load(@NotNull String configPath, @Nullable String optionsPath) throws IOException {
+ public void load(@NotNull String configPath, @NotNull String optionsPath) throws IOException {
getStateStore().setOptionsPath(optionsPath);
getStateStore().setConfigPath(configPath);
diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ApplicationStoreImpl.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ApplicationStoreImpl.java
index a00533d3244b..bf03cb11f1d6 100644
--- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ApplicationStoreImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ApplicationStoreImpl.java
@@ -36,7 +36,6 @@ class ApplicationStoreImpl extends ComponentStoreImpl implements IApplicationSto
private static final String XML_EXTENSION = ".xml";
private static final String DEFAULT_STORAGE_SPEC = StoragePathMacros.APP_CONFIG + "/" + PathManager.DEFAULT_OPTIONS_FILE_NAME + XML_EXTENSION;
- private static final String OPTIONS_MACRO = "OPTIONS";
private static final String ROOT_ELEMENT_NAME = "application";
private final ApplicationImpl myApplication;
@@ -93,14 +92,13 @@ class ApplicationStoreImpl extends ComponentStoreImpl implements IApplicationSto
}
@Override
- public void setOptionsPath(final String path) {
- myStateStorageManager.addMacro(StoragePathMacros.getMacroName(StoragePathMacros.APP_CONFIG), path);
- myStateStorageManager.addMacro(OPTIONS_MACRO, path);
+ public void setOptionsPath(@NotNull String path) {
+ myStateStorageManager.addMacro(StoragePathMacros.APP_CONFIG, path);
}
@Override
public void setConfigPath(@NotNull final String configPath) {
- myStateStorageManager.addMacro(StoragePathMacros.getMacroName(StoragePathMacros.ROOT_CONFIG), configPath);
+ myStateStorageManager.addMacro(StoragePathMacros.ROOT_CONFIG, configPath);
myConfigPath = configPath;
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/BaseFileConfigurableStoreImpl.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/BaseFileConfigurableStoreImpl.java
index 25dd8a05cab3..dc07fee151e2 100644
--- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/BaseFileConfigurableStoreImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/BaseFileConfigurableStoreImpl.java
@@ -59,8 +59,8 @@ abstract class BaseFileConfigurableStoreImpl extends ComponentStoreImpl {
}
@Override
- public void load(@NotNull final Element rootElement) throws IOException {
- super.load(rootElement);
+ public void load(@NotNull Element rootElement, @Nullable PathMacroSubstitutor pathMacroSubstitutor, boolean intern) {
+ super.load(rootElement, pathMacroSubstitutor, intern);
final String v = rootElement.getAttributeValue(VERSION_OPTION);
if (v != null) {
@@ -74,7 +74,11 @@ abstract class BaseFileConfigurableStoreImpl extends ComponentStoreImpl {
@Override
@NotNull
protected Element save() {
- final Element root = super.save();
+ Element root = super.save();
+ if (root == null) {
+ root = new Element(myRootElementName);
+ }
+
root.setAttribute(VERSION_OPTION, Integer.toString(myVersion));
return root;
}
@@ -113,7 +117,7 @@ abstract class BaseFileConfigurableStoreImpl extends ComponentStoreImpl {
}
public BaseStorageData getMainStorageData() throws StateStorageException {
- return (BaseStorageData) getMainStorage().getStorageData(false);
+ return (BaseStorageData)getMainStorage().getStorageData();
}
@Nullable
diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ComponentStoreImpl.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ComponentStoreImpl.java
index fc2017b57a4a..ed63bf12d4c4 100644
--- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ComponentStoreImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ComponentStoreImpl.java
@@ -29,12 +29,12 @@ import com.intellij.openapi.util.*;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ReflectionUtil;
-import com.intellij.util.io.fs.IFile;
import gnu.trove.THashMap;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import java.io.File;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.*;
@@ -46,12 +46,6 @@ public abstract class ComponentStoreImpl implements IComponentStore {
private final List<SettingsSavingComponent> mySettingsSavingComponents = Collections.synchronizedList(new ArrayList<SettingsSavingComponent>());
@Nullable private SaveSessionImpl mySession;
- @Deprecated
- @Nullable
- private StateStorage getStateStorage(@NotNull final Storage storageSpec) throws StateStorageException {
- return getStateStorageManager().getStateStorage(storageSpec);
- }
-
@Nullable
protected abstract StateStorage getDefaultsStorage();
@@ -255,9 +249,10 @@ public abstract class ComponentStoreImpl implements IComponentStore {
Storage[] storageSpecs = getComponentStorageSpecs(component, StateStorageOperation.READ);
for (Storage storageSpec : storageSpecs) {
- StateStorage stateStorage = getStateStorage(storageSpec);
- if (stateStorage == null || !stateStorage.hasState(component, name, stateClass, reloadData)) continue;
- state = stateStorage.getState(component, name, stateClass, state);
+ StateStorage stateStorage = getStateStorageManager().getStateStorage(storageSpec);
+ if (stateStorage != null && stateStorage.hasState(component, name, stateClass, reloadData)) {
+ state = stateStorage.getState(component, name, stateClass, state);
+ }
}
if (state != null) {
@@ -320,17 +315,15 @@ public abstract class ComponentStoreImpl implements IComponentStore {
}
assert storages.length > 0;
- final Class<StorageAnnotationsDefaultValues.NullStateStorageChooser> defaultClass =
- StorageAnnotationsDefaultValues.NullStateStorageChooser.class;
-
final Class<? extends StateStorageChooser> storageChooserClass = stateSpec.storageChooser();
- final StateStorageChooser<PersistentStateComponent<?>> defaultStateStorageChooser = getDefaultStateStorageChooser();
- assert storageChooserClass != defaultClass || defaultStateStorageChooser != null : "State chooser not specified for: " +
- persistentStateComponent.getClass();
-
- if (storageChooserClass == defaultClass) {
+ if (storageChooserClass == StateStorageChooser.class) {
+ StateStorageChooser<PersistentStateComponent<?>> defaultStateStorageChooser = getDefaultStateStorageChooser();
+ assert defaultStateStorageChooser != null : "State chooser not specified for: " + persistentStateComponent.getClass();
return defaultStateStorageChooser.selectStorages(storages, persistentStateComponent, operation);
}
+ else if (storageChooserClass == LastStorageChooserForWrite.class) {
+ return LastStorageChooserForWrite.INSTANCE.selectStorages(storages, persistentStateComponent, operation);
+ }
else {
try {
@SuppressWarnings("unchecked")
@@ -361,7 +354,7 @@ public abstract class ComponentStoreImpl implements IComponentStore {
@NotNull
@Override
- public List<IFile> getAllStorageFilesToSave(final boolean includingSubStructures) throws IOException {
+ public List<File> getAllStorageFilesToSave(final boolean includingSubStructures) throws IOException {
try {
return myStorageManagerSaveSession.getAllStorageFilesToSave();
}
@@ -426,12 +419,10 @@ public abstract class ComponentStoreImpl implements IComponentStore {
protected void commit() throws StateStorageException {
final StateStorageManager storageManager = getStateStorageManager();
-
final StateStorageManager.ExternalizationSession session = storageManager.startExternalization();
String[] names = ArrayUtil.toStringArray(myComponents.keySet());
Arrays.sort(names);
-
for (String name : names) {
Object component = myComponents.get(name);
if (component instanceof PersistentStateComponent) {
@@ -452,10 +443,9 @@ public abstract class ComponentStoreImpl implements IComponentStore {
@NotNull
@Override
- public List<IFile> getAllStorageFiles(final boolean includingSubStructures) {
+ public List<File> getAllStorageFiles(final boolean includingSubStructures) {
return myStorageManagerSaveSession.getAllStorageFiles();
}
-
}
@Override
diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/CompoundSaveSession.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/CompoundSaveSession.java
index 51cc717726f3..aacdb58aeeec 100644
--- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/CompoundSaveSession.java
+++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/CompoundSaveSession.java
@@ -18,9 +18,9 @@ package com.intellij.openapi.components.impl.stores;
import com.intellij.openapi.components.StateStorage;
import com.intellij.openapi.components.StateStorageException;
import com.intellij.util.SmartList;
-import com.intellij.util.io.fs.IFile;
import gnu.trove.THashMap;
+import java.io.File;
import java.util.List;
import java.util.Map;
@@ -36,8 +36,8 @@ public class CompoundSaveSession {
}
}
- public List<IFile> getAllStorageFilesToSave() throws StateStorageException {
- List<IFile> result = new SmartList<IFile>();
+ public List<File> getAllStorageFilesToSave() throws StateStorageException {
+ List<File> result = new SmartList<File>();
for (StateStorage.SaveSession saveSession : mySaveSessions.values()) {
result.addAll(saveSession.getStorageFilesToSave());
}
@@ -70,8 +70,8 @@ public class CompoundSaveSession {
return mySaveSessions.get(storage);
}
- public List<IFile> getAllStorageFiles() {
- List<IFile> result = new SmartList<IFile>();
+ public List<File> getAllStorageFiles() {
+ List<File> result = new SmartList<File>();
for (StateStorage.SaveSession saveSession : mySaveSessions.values()) {
result.addAll(saveSession.getAllStorageFiles());
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DefaultProjectStoreImpl.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DefaultProjectStoreImpl.java
index 6f0c3b8122cf..fad17c8d2889 100644
--- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DefaultProjectStoreImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DefaultProjectStoreImpl.java
@@ -21,13 +21,12 @@ import com.intellij.openapi.project.impl.ProjectImpl;
import com.intellij.openapi.project.impl.ProjectManagerImpl;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.util.io.fs.IFile;
-import org.jdom.Document;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
@@ -40,10 +39,10 @@ public class DefaultProjectStoreImpl extends ProjectStoreImpl {
private final ProjectManagerImpl myProjectManager;
@NonNls private static final String ROOT_TAG_NAME = "defaultProject";
- public DefaultProjectStoreImpl(final ProjectImpl project, final ProjectManagerImpl projectManager) {
+ public DefaultProjectStoreImpl(@NotNull ProjectImpl project, final ProjectManagerImpl projectManager) {
super(project);
- myProjectManager = projectManager;
+ myProjectManager = projectManager;
myElement = projectManager.getDefaultProjectRootElement();
}
@@ -53,29 +52,28 @@ public class DefaultProjectStoreImpl extends ProjectStoreImpl {
return element != null ? element.clone() : null;
}
-
@NotNull
@Override
protected StateStorageManager createStateStorageManager() {
- Document _d = null;
+ Element _d = null;
if (myElement != null) {
myElement.detach();
- _d = new Document(myElement);
+ _d = myElement;
}
final ComponentManager componentManager = getComponentManager();
final PathMacroManager pathMacroManager = PathMacroManager.getInstance(componentManager);
- final Document document = _d;
+ final Element element = _d;
- final XmlElementStorage storage = new XmlElementStorage(pathMacroManager.createTrackingSubstitutor(), componentManager,
- ROOT_TAG_NAME, null, "", ComponentRoamingManager.getInstance(),
+ final XmlElementStorage storage = new XmlElementStorage("", RoamingType.DISABLED, pathMacroManager.createTrackingSubstitutor(), componentManager,
+ ROOT_TAG_NAME, null,
ComponentVersionProvider.EMPTY) {
@Override
@Nullable
- protected Document loadDocument() throws StateStorageException {
- return document;
+ protected Element loadLocalData() {
+ return element;
}
@Override
@@ -96,26 +94,28 @@ public class DefaultProjectStoreImpl extends ProjectStoreImpl {
@Override
protected void doSave() throws StateStorageException {
- myProjectManager.setDefaultProjectRootElement(getDocumentToSave().getRootElement());
+ Element element = getElementToSave();
+ myProjectManager.setDefaultProjectRootElement(element == null ? null : element);
}
@NotNull
@Override
- public Collection<IFile> getStorageFilesToSave() throws StateStorageException {
+ public Collection<File> getStorageFilesToSave() throws StateStorageException {
return Collections.emptyList();
}
@NotNull
@Override
- public List<IFile> getAllStorageFiles() {
+ public List<File> getAllStorageFiles() {
return Collections.emptyList();
}
}
};
+ //noinspection deprecation
return new StateStorageManager() {
@Override
- public void addMacro(String macro, String expansion) {
+ public void addMacro(@NotNull String macro, @NotNull String expansion) {
throw new UnsupportedOperationException("Method addMacro not implemented in " + getClass());
}
@@ -131,6 +131,12 @@ public class DefaultProjectStoreImpl extends ProjectStoreImpl {
return storage;
}
+ @Nullable
+ @Override
+ public StateStorage getStateStorage(@NotNull String fileSpec, @NotNull RoamingType roamingType) {
+ return storage;
+ }
+
@Override
@Nullable
public StateStorage getFileStateStorage(@NotNull String fileSpec) {
@@ -158,6 +164,7 @@ public class DefaultProjectStoreImpl extends ProjectStoreImpl {
storage.finishSave(((MySaveSession)saveSession).saveSession);
}
+ @NotNull
@Override
public String expandMacros(@NotNull String file) {
throw new UnsupportedOperationException("Method expandMacros not implemented in " + getClass());
@@ -186,6 +193,7 @@ public class DefaultProjectStoreImpl extends ProjectStoreImpl {
throw new UnsupportedOperationException("Method getStreamProviders not implemented in " + getClass());
}
+ @NotNull
@Override
public Collection<String> getStorageFileNames() {
throw new UnsupportedOperationException("Method getStorageFileNames not implemented in " + getClass());
@@ -238,13 +246,13 @@ public class DefaultProjectStoreImpl extends ProjectStoreImpl {
@NotNull
@Override
- public List<IFile> getAllStorageFilesToSave() throws StateStorageException {
+ public List<File> getAllStorageFilesToSave() throws StateStorageException {
return Collections.emptyList();
}
@NotNull
@Override
- public List<IFile> getAllStorageFiles() {
+ public List<File> getAllStorageFiles() {
return Collections.emptyList();
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DefaultsStateStorage.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DefaultsStateStorage.java
index b62db63b73c2..9415aee49b09 100644
--- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DefaultsStateStorage.java
+++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DefaultsStateStorage.java
@@ -65,12 +65,12 @@ class DefaultsStateStorage implements StateStorage {
}
@Nullable
- public <T> T getState(final Object component, final String componentName, final Class<T> stateClass, @Nullable final T mergeInto) throws
+ public <T> T getState(final Object component, @NotNull final String componentName, final Class<T> stateClass, @Nullable final T mergeInto) throws
StateStorageException {
return DefaultStateSerializer.deserializeState(getState(component, componentName), stateClass, mergeInto);
}
- public boolean hasState(final Object component, final String componentName, final Class<?> aClass, final boolean reloadData) throws StateStorageException {
+ public boolean hasState(final Object component, @NotNull final String componentName, final Class<?> aClass, final boolean reloadData) throws StateStorageException {
final URL url = DecodeDefaultsUtil.getDefaults(component, componentName);
return url != null;
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DirectoryBasedStorage.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DirectoryBasedStorage.java
index cda453be5cd2..912c239cffcb 100644
--- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DirectoryBasedStorage.java
+++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/DirectoryBasedStorage.java
@@ -26,7 +26,8 @@ import com.intellij.openapi.util.WriteExternalException;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.*;
import com.intellij.openapi.vfs.tracker.VirtualFileTracker;
-import com.intellij.util.io.fs.IFile;
+import com.intellij.util.SmartList;
+import com.intellij.util.containers.SmartHashSet;
import com.intellij.util.messages.MessageBus;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
@@ -37,16 +38,13 @@ import java.io.File;
import java.io.IOException;
import java.util.*;
-import static com.intellij.util.io.fs.FileSystem.FILE_SYSTEM;
-
//todo: support missing plugins
//todo: support storage data
public class DirectoryBasedStorage implements StateStorage, Disposable {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.components.impl.stores.DirectoryBasedStorage");
- private static final IFile[] EMPTY_FILES = new IFile[0];
private final TrackingPathMacroSubstitutor myPathMacroSubstitutor;
- private final IFile myDir;
+ private final File myDir;
private final StateSplitter mySplitter;
private final FileTypeManager myFileTypeManager;
@@ -59,7 +57,7 @@ public class DirectoryBasedStorage implements StateStorage, Disposable {
@NotNull Disposable parentDisposable,
@NotNull PicoContainer picoContainer) {
myPathMacroSubstitutor = pathMacroSubstitutor;
- myDir = FILE_SYSTEM.createFile(dir);
+ myDir = new File(dir);
mySplitter = splitter;
Disposer.register(parentDisposable, this);
@@ -96,7 +94,7 @@ public class DirectoryBasedStorage implements StateStorage, Disposable {
@Override
@Nullable
- public <T> T getState(final Object component, final String componentName, Class<T> stateClass, @Nullable T mergeInto)
+ public <T> T getState(final Object component, @NotNull final String componentName, Class<T> stateClass, @Nullable T mergeInto)
throws StateStorageException {
if (myStorageData == null) myStorageData = loadState();
@@ -116,7 +114,7 @@ public class DirectoryBasedStorage implements StateStorage, Disposable {
@Override
- public boolean hasState(final Object component, final String componentName, final Class<?> aClass, final boolean reloadData) throws StateStorageException {
+ public boolean hasState(final Object component, @NotNull String componentName, final Class<?> aClass, final boolean reloadData) throws StateStorageException {
if (!myDir.exists()) return false;
if (reloadData) myStorageData = null;
return true;
@@ -180,32 +178,28 @@ public class DirectoryBasedStorage implements StateStorage, Disposable {
@Override
public void save() throws StateStorageException {
assert mySession == this;
- final Set<String> currentNames = new HashSet<String>();
-
- IFile[] children = myDir.exists() ? myDir.listFiles() : EMPTY_FILES;
- for (IFile child : children) {
- final String fileName = child.getName();
- if (!myFileTypeManager.isFileIgnored(fileName) && StringUtil.endsWithIgnoreCase(fileName, ".xml")) {
- currentNames.add(fileName);
+ final Set<String> currentNames = new SmartHashSet<String>();
+ File[] children = myDir.listFiles();
+ if (children != null) {
+ for (File child : children) {
+ final String fileName = child.getName();
+ if (!myFileTypeManager.isFileIgnored(fileName) && StringUtil.endsWithIgnoreCase(fileName, ".xml")) {
+ currentNames.add(fileName);
+ }
}
}
myStorageData.process(new DirectoryStorageData.StorageDataProcessor() {
@Override
- public void process(final String componentName, final IFile file, final Element element) {
+ public void process(final String componentName, final File file, final Element element) {
currentNames.remove(file.getName());
if (myPathMacroSubstitutor != null) {
myPathMacroSubstitutor.collapsePaths(element);
}
- if (file.getTimeStamp() <= myStorageData.getLastTimeStamp()) {
- if (!myDir.exists()) {
- myDir.createParentDirs();
- myDir.mkDir();
- }
-
- StorageUtil.save(file, element, MySaveSession.this);
+ if (file.lastModified() <= myStorageData.getLastTimeStamp()) {
+ StorageUtil.save(file, element, MySaveSession.this, false, null);
myStorageData.updateLastTimestamp(file);
}
}
@@ -217,15 +211,14 @@ public class DirectoryBasedStorage implements StateStorage, Disposable {
public void run() {
if (myDir.exists()) {
for (String name : currentNames) {
- IFile child = myDir.getChild(name);
-
- if (child.getTimeStamp() > myStorageData.getLastTimeStamp()) {
+ File child = new File(myDir, name);
+ if (child.lastModified() > myStorageData.getLastTimeStamp()) {
// do not touch new files during VC update (which aren't read yet)
// now got an opposite problem: file is recreated if was removed by VC during update.
return;
}
- final VirtualFile virtualFile = StorageUtil.getVirtualFile(child);
+ final VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByIoFile(child);
if (virtualFile != null) {
try {
LOG.debug("Removing configuration file: " + virtualFile.getPresentableUrl());
@@ -272,23 +265,26 @@ public class DirectoryBasedStorage implements StateStorage, Disposable {
@Override
@NotNull
- public Collection<IFile> getStorageFilesToSave() throws StateStorageException {
+ public Collection<File> getStorageFilesToSave() throws StateStorageException {
assert mySession == this;
if (!myDir.exists()) return getAllStorageFiles();
assert myDir.isDirectory() : myDir.getPath();
- final List<IFile> filesToSave = new ArrayList<IFile>();
-
- IFile[] children = myDir.listFiles();
- final Set<String> currentChildNames = new HashSet<String>();
- for (IFile child : children) {
- if (!myFileTypeManager.isFileIgnored(child.getName())) currentChildNames.add(child.getName());
+ final List<File> filesToSave = new ArrayList<File>();
+ final Set<String> currentChildNames = new SmartHashSet<String>();
+ File[] children = myDir.listFiles();
+ if (children != null) {
+ for (File child : children) {
+ if (!myFileTypeManager.isFileIgnored(child.getName())) {
+ currentChildNames.add(child.getName());
+ }
+ }
}
myStorageData.process(new DirectoryStorageData.StorageDataProcessor() {
@Override
- public void process(final String componentName, final IFile file, final Element element) {
+ public void process(final String componentName, final File file, final Element element) {
if (currentChildNames.contains(file.getName())) {
currentChildNames.remove(file.getName());
@@ -301,13 +297,11 @@ public class DirectoryBasedStorage implements StateStorage, Disposable {
filesToSave.add(file);
}
}
-
}
});
for (String childName : currentChildNames) {
- final IFile child = myDir.getChild(childName);
- filesToSave.add(child);
+ filesToSave.add(new File(myDir, childName));
}
return filesToSave;
@@ -315,8 +309,8 @@ public class DirectoryBasedStorage implements StateStorage, Disposable {
@Override
@NotNull
- public List<IFile> getAllStorageFiles() {
- return new ArrayList<IFile>(myStorageData.getAllStorageFiles().keySet());
+ public List<File> getAllStorageFiles() {
+ return new SmartList<File>(myStorageData.getAllStorageFiles().keySet());
}
}
@@ -328,24 +322,25 @@ public class DirectoryBasedStorage implements StateStorage, Disposable {
}
@Override
- public void setState(@NotNull final Object component, final String componentName, @NotNull final Object state, final Storage storageSpec)
- throws StateStorageException {
+ public void setState(@NotNull final Object component, final String componentName, @NotNull final Object state, final Storage storageSpec) {
assert mySession == this;
setState(componentName, state, storageSpec);
}
- private void setState(final String componentName, @NotNull Object state, final Storage storageSpec) throws StateStorageException {
+ private void setState(final String componentName, @NotNull Object state, final Storage storageSpec) {
try {
final Element element = DefaultStateSerializer.serializeState(state, storageSpec);
- for (Pair<Element, String> pair : mySplitter.splitState(element)) {
- Element e = pair.first;
- String name = pair.second;
+ if (element != null) {
+ for (Pair<Element, String> pair : mySplitter.splitState(element)) {
+ Element e = pair.first;
+ String name = pair.second;
- Element statePart = new Element(StorageData.COMPONENT);
- statePart.setAttribute(StorageData.NAME, componentName);
- statePart.addContent(e.detach());
+ Element statePart = new Element(StorageData.COMPONENT);
+ statePart.setAttribute(StorageData.NAME, componentName);
+ statePart.addContent(e.detach());
- myStorageData.put(componentName, myDir.getChild(name), statePart, false);
+ myStorageData.put(componentName, new File(myDir, name), statePart, false);
+ }
}
}
catch (WriteExternalException e) {
diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/FileBasedStorage.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/FileBasedStorage.java
index 923072d4fb1d..54fd9d65cb92 100644
--- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/FileBasedStorage.java
+++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/FileBasedStorage.java
@@ -22,19 +22,14 @@ import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.PathManager;
-import com.intellij.openapi.components.ServiceManager;
-import com.intellij.openapi.components.StateStorageException;
-import com.intellij.openapi.components.StoragePathMacros;
-import com.intellij.openapi.components.TrackingPathMacroSubstitutor;
+import com.intellij.openapi.components.*;
import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.util.JDOMUtil;
+import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream;
+import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.*;
import com.intellij.openapi.vfs.tracker.VirtualFileTracker;
-import com.intellij.util.io.fs.FileSystem;
-import com.intellij.util.io.fs.IFile;
import com.intellij.util.messages.MessageBus;
-import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jetbrains.annotations.NonNls;
@@ -44,46 +39,40 @@ import org.picocontainer.PicoContainer;
import java.io.File;
import java.io.IOException;
-import java.io.InputStream;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
public class FileBasedStorage extends XmlElementStorage {
- private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.components.impl.stores.FileBasedStorage");
+ private static final Logger LOG = Logger.getInstance(FileBasedStorage.class);
private static boolean ourConfigDirectoryRefreshed = false;
private final String myFilePath;
- private final IFile myFile;
- private final String myRootElementName;
+ private final File myFile;
private volatile VirtualFile myCachedVirtualFile;
- public FileBasedStorage(@Nullable TrackingPathMacroSubstitutor pathMacroManager,
- StreamProvider streamProvider,
- String filePath,
- String fileSpec,
- String rootElementName,
+ public FileBasedStorage(@NotNull String filePath,
+ @NotNull String fileSpec,
+ @Nullable RoamingType roamingType,
+ @Nullable TrackingPathMacroSubstitutor pathMacroManager,
+ @NotNull String rootElementName,
@NotNull Disposable parentDisposable,
PicoContainer picoContainer,
- ComponentRoamingManager componentRoamingManager,
+ @Nullable StreamProvider streamProvider,
ComponentVersionProvider componentVersionProvider) {
- super(pathMacroManager, parentDisposable, rootElementName, streamProvider, fileSpec, componentRoamingManager, componentVersionProvider);
+ super(fileSpec, roamingType, pathMacroManager, parentDisposable, rootElementName, streamProvider, componentVersionProvider);
refreshConfigDirectoryOnce();
- myRootElementName = rootElementName;
myFilePath = filePath;
- myFile = FileSystem.FILE_SYSTEM.createFile(myFilePath);
+ myFile = new File(filePath);
VirtualFileTracker virtualFileTracker = ServiceManager.getService(VirtualFileTracker.class);
MessageBus messageBus = (MessageBus)picoContainer.getComponentInstanceOfType(MessageBus.class);
if (virtualFileTracker != null && messageBus != null) {
- final String path = myFile.getAbsolutePath();
- final String fileUrl = LocalFileSystem.PROTOCOL_PREFIX + path.replace(File.separatorChar, '/');
-
final Listener listener = messageBus.syncPublisher(STORAGE_TOPIC);
- virtualFileTracker.addTracker(fileUrl, new VirtualFileAdapter() {
+ virtualFileTracker.addTracker(LocalFileSystem.PROTOCOL_PREFIX + myFile.getAbsolutePath().replace(File.separatorChar, '/'), new VirtualFileAdapter() {
@Override
public void fileMoved(@NotNull VirtualFileMoveEvent event) {
myCachedVirtualFile = null;
@@ -95,6 +84,11 @@ public class FileBasedStorage extends XmlElementStorage {
}
@Override
+ public void fileCreated(@NotNull VirtualFileEvent event) {
+ myCachedVirtualFile = event.getFile();
+ }
+
+ @Override
public void contentsChanged(@NotNull final VirtualFileEvent event) {
if (!isDisposed()) {
listener.storageFileChanged(event, FileBasedStorage.this);
@@ -130,13 +124,6 @@ public class FileBasedStorage extends XmlElementStorage {
return new FileSaveSession(externalizationSession);
}
- public void resetProviderCache() {
- myProviderUpToDateHash = -1;
- if (myRemoteVersionProvider != null) {
- myRemoteVersionProvider.myProviderVersions = null;
- }
- }
-
private class FileSaveSession extends MySaveSession {
protected FileSaveSession(MyExternalizationSession externalizationSession) {
super(externalizationSession);
@@ -145,9 +132,11 @@ public class FileBasedStorage extends XmlElementStorage {
@Override
protected boolean physicalContentNeedsSave() {
VirtualFile file = getVirtualFile();
- if (file == null || !file.exists())
+ if (file == null || !file.exists()) {
return !myStorageData.isEmpty();
- return !StorageUtil.contentEquals(getDocumentToSave(), file);
+ }
+ Element element = getElementToSave();
+ return element == null || !StorageUtil.contentEquals(element, file);
}
@Override
@@ -169,14 +158,13 @@ public class FileBasedStorage extends XmlElementStorage {
}
LOG.assertTrue(myFile != null);
- myCachedVirtualFile = StorageUtil.save(myFile, getDocumentToSave(), this);
+ myCachedVirtualFile = StorageUtil.save(myFile, getElementToSave(), this, true, myCachedVirtualFile);
}
@NotNull
@Override
- public Collection<IFile> getStorageFilesToSave() throws StateStorageException {
- boolean needsSave = needsSave();
- if (needsSave) {
+ public Collection<File> getStorageFilesToSave() {
+ if (needsSave()) {
if (LOG.isDebugEnabled()) {
LOG.info("File " + myFileSpec + " needs save; hash=" + myUpToDateHash + "; currentHash=" + calcHash() + "; " +
"content needs save=" + physicalContentNeedsSave());
@@ -190,21 +178,17 @@ public class FileBasedStorage extends XmlElementStorage {
@NotNull
@Override
- public List<IFile> getAllStorageFiles() {
+ public List<File> getAllStorageFiles() {
return Collections.singletonList(myFile);
}
}
@Override
- protected void loadState(final StorageData result, final Element element) throws StateStorageException {
- ((FileStorageData)result).myFilePath = myFile.getAbsolutePath();
- super.loadState(result, element);
- }
-
- @Override
@NotNull
protected StorageData createStorageData() {
- return new FileStorageData(myRootElementName);
+ FileStorageData data = new FileStorageData(myRootElementName);
+ data.myFilePath = myFilePath;
+ return data;
}
public static class FileStorageData extends StorageData {
@@ -234,18 +218,24 @@ public class FileBasedStorage extends XmlElementStorage {
public VirtualFile getVirtualFile() {
VirtualFile virtualFile = myCachedVirtualFile;
if (virtualFile == null) {
- myCachedVirtualFile = virtualFile = StorageUtil.getVirtualFile(myFile);
+ myCachedVirtualFile = virtualFile = LocalFileSystem.getInstance().findFileByIoFile(myFile);
}
return virtualFile;
}
+ @NotNull
public File getFile() {
- return new File(myFile.getPath());
+ return myFile;
+ }
+
+ @NotNull
+ public String getFilePath() {
+ return myFilePath;
}
@Override
@Nullable
- protected Document loadDocument() throws StateStorageException {
+ protected Element loadLocalData() {
myBlockSavingTheContent = false;
try {
VirtualFile file = getVirtualFile();
@@ -256,7 +246,7 @@ public class FileBasedStorage extends XmlElementStorage {
if (file.getLength() == 0) {
return processReadException(null);
}
- return loadDocumentImpl(file);
+ return StorageData.load(file);
}
catch (final JDOMException e) {
return processReadException(e);
@@ -267,7 +257,7 @@ public class FileBasedStorage extends XmlElementStorage {
}
@Nullable
- private Document processReadException(@Nullable final Exception e) {
+ private Element processReadException(@Nullable final Exception e) {
boolean contentTruncated = e == null;
myBlockSavingTheContent = isProjectOrModuleOrWorkspaceFile() && !contentTruncated;
if (!ApplicationManager.getApplication().isUnitTestMode() && !ApplicationManager.getApplication().isHeadlessEnvironment()) {
@@ -291,45 +281,27 @@ public class FileBasedStorage extends XmlElementStorage {
return isProjectOrModuleOrWorkspaceFile() && !contentTruncated ? "Please correct the file content" : "File content will be recreated";
}
- private static Document loadDocumentImpl(final VirtualFile file) throws IOException, JDOMException {
- InputStream stream = file.getInputStream();
- try {
- return JDOMUtil.loadDocument(stream);
- }
- finally {
- stream.close();
- }
- }
-
- public String getFileName() {
- return myFile.getName();
- }
-
- public String getFilePath() {
- return myFilePath;
- }
-
@Override
public void setDefaultState(final Element element) {
element.setName(myRootElementName);
super.setDefaultState(element);
}
- protected boolean physicalContentNeedsSave(final Document doc) {
- VirtualFile file = getVirtualFile();
- return file == null || !file.exists() || !StorageUtil.contentEquals(doc, file);
- }
-
@Nullable
public File updateFileExternallyFromStreamProviders() throws IOException {
- StorageData loadedData = loadData(true);
- Document document = getDocument(loadedData);
- if (physicalContentNeedsSave(document)) {
- File file = new File(myFile.getAbsolutePath());
- JDOMUtil.writeDocument(document, file, "\n");
- return file;
+ Element element = getElement(loadData(true));
+ if (element == null) {
+ FileUtil.delete(myFile);
+ return null;
}
- return null;
+ BufferExposingByteArrayOutputStream out = StorageUtil.newContentIfDiffers(element, getVirtualFile());
+ if (out == null) {
+ return null;
+ }
+
+ File file = new File(myFile.getAbsolutePath());
+ FileUtil.writeToFile(file, out.getInternalBuffer(), 0, out.size());
+ return file;
}
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/IApplicationStore.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/IApplicationStore.java
index c669bd1f37be..0ebfae887771 100644
--- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/IApplicationStore.java
+++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/IApplicationStore.java
@@ -15,18 +15,18 @@
*/
package com.intellij.openapi.components.impl.stores;
-import com.intellij.openapi.components.StateStorageException;
-import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.components.StateStorage;
+import com.intellij.openapi.components.StateStorageException;
import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
-import java.util.Set;
-import java.util.Collection;
import java.io.IOException;
+import java.util.Collection;
+import java.util.Set;
public interface IApplicationStore extends IComponentStore {
- void setOptionsPath(String path);
+ void setOptionsPath(@NotNull String path);
void setConfigPath(@NotNull String configPath);
diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/IComponentStore.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/IComponentStore.java
index 0427a8be15ab..93a65a2eb50b 100644
--- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/IComponentStore.java
+++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/IComponentStore.java
@@ -19,10 +19,10 @@ import com.intellij.openapi.components.StateStorage;
import com.intellij.openapi.components.StateStorageException;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.util.io.fs.IFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Set;
@@ -54,17 +54,19 @@ public interface IComponentStore {
interface SaveSession {
@NotNull
- List<IFile> getAllStorageFilesToSave(final boolean includingSubStructures) throws IOException;
+ List<File> getAllStorageFilesToSave(final boolean includingSubStructures) throws IOException;
+
@NotNull
SaveSession save() throws IOException;
+
void finishSave();
+
void reset();
@Nullable
- Set<String> analyzeExternalChanges(@NotNull Set<Pair<VirtualFile,StateStorage>> changedFiles);
+ Set<String> analyzeExternalChanges(@NotNull Set<Pair<VirtualFile, StateStorage>> changedFiles);
@NotNull
- List<IFile> getAllStorageFiles(final boolean includingSubStructures);
+ List<File> getAllStorageFiles(final boolean includingSubStructures);
}
-
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/OldStreamProviderAdapter.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/OldStreamProviderAdapter.java
index 2120030db2c1..ac7bf84f6b3e 100644
--- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/OldStreamProviderAdapter.java
+++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/OldStreamProviderAdapter.java
@@ -12,6 +12,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+@SuppressWarnings("deprecation")
final class OldStreamProviderAdapter extends StreamProvider implements CurrentUserHolder {
final com.intellij.openapi.options.StreamProvider myProvider;
private final RoamingType myRoamingType;
@@ -32,9 +33,8 @@ final class OldStreamProviderAdapter extends StreamProvider implements CurrentUs
}
@Override
- public boolean saveContent(@NotNull String fileSpec, @NotNull byte[] content, int size, @NotNull RoamingType roamingType, boolean async) throws IOException {
+ public void saveContent(@NotNull String fileSpec, @NotNull byte[] content, int size, @NotNull RoamingType roamingType, boolean async) throws IOException {
myProvider.saveContent(fileSpec, new BufferExposingByteArrayInputStream(content, size), size, roamingType, async);
- return false;
}
@Nullable
@@ -65,4 +65,4 @@ final class OldStreamProviderAdapter extends StreamProvider implements CurrentUs
public String getCurrentUserName() {
return myProvider instanceof CurrentUserHolder ? ((CurrentUserHolder)myProvider).getCurrentUserName() : null;
}
-} \ No newline at end of file
+}
diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ProjectStateStorageManager.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ProjectStateStorageManager.java
index 0eed50a65131..c7b93afbe8d8 100644
--- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ProjectStateStorageManager.java
+++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ProjectStateStorageManager.java
@@ -56,17 +56,12 @@ class ProjectStateStorageManager extends StateStorageManagerImpl {
assert config != null : "Couldn't find old storage for " + component.getClass().getName();
final boolean workspace = isWorkspace(config.options);
- String macro = StoragePathMacros.getMacroName(workspace ? StoragePathMacros.WORKSPACE_FILE : StoragePathMacros.PROJECT_FILE);
-
- String name = "$" + macro + "$";
-
- StateStorage storage = getFileStateStorage(name);
-
+ String fileSpec = workspace ? StoragePathMacros.WORKSPACE_FILE : StoragePathMacros.PROJECT_FILE;
+ StateStorage storage = getStateStorage(fileSpec, workspace ? RoamingType.DISABLED : RoamingType.PER_USER);
if (operation == StateStorageOperation.READ && storage != null && workspace && !storage.hasState(component, componentName, Element.class, false)) {
- name = StoragePathMacros.PROJECT_FILE;
+ fileSpec = StoragePathMacros.PROJECT_FILE;
}
-
- return name;
+ return fileSpec;
}
@Override
diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ProjectStoreImpl.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ProjectStoreImpl.java
index 6288c62ab9e5..01e2f9e036d0 100644
--- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ProjectStoreImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/ProjectStoreImpl.java
@@ -39,13 +39,14 @@ import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.io.FileUtilRt;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.*;
+import com.intellij.util.PathUtilRt;
+import com.intellij.util.SmartList;
import com.intellij.util.containers.OrderedSet;
-import com.intellij.util.io.fs.FileSystem;
-import com.intellij.util.io.fs.IFile;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.io.*;
import java.lang.annotation.Annotation;
@@ -55,23 +56,21 @@ import java.util.List;
import java.util.Set;
class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProjectStore {
- private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.components.impl.stores.ProjectStoreImpl");
+ private static final Logger LOG = Logger.getInstance(ProjectStoreImpl.class);
@NonNls private static final String OLD_PROJECT_SUFFIX = "_old.";
@NonNls static final String OPTION_WORKSPACE = "workspace";
- @NonNls static final String DEFAULT_STATE_STORAGE = StoragePathMacros.PROJECT_FILE;
-
static final Storage DEFAULT_STORAGE_ANNOTATION = new MyStorage();
private static int originalVersion = -1;
protected ProjectImpl myProject;
private StorageScheme myScheme = StorageScheme.DEFAULT;
- private String myCachedLocation;
private String myPresentableUrl;
- ProjectStoreImpl(final ProjectImpl project) {
+ ProjectStoreImpl(@NotNull ProjectImpl project) {
super(project);
+
myProject = project;
}
@@ -169,15 +168,15 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject
final File dirStore = file.isDirectory() ? new File(file, Project.DIRECTORY_STORE_FOLDER)
: new File(file.getParentFile(), Project.DIRECTORY_STORE_FOLDER);
- stateStorageManager.addMacro(StoragePathMacros.getMacroName(StoragePathMacros.PROJECT_FILE), new File(dirStore, "misc.xml").getPath());
+ stateStorageManager.addMacro(StoragePathMacros.PROJECT_FILE, new File(dirStore, "misc.xml").getPath());
final File ws = new File(dirStore, "workspace.xml");
- stateStorageManager.addMacro(StoragePathMacros.getMacroName(StoragePathMacros.WORKSPACE_FILE), ws.getPath());
+ stateStorageManager.addMacro(StoragePathMacros.WORKSPACE_FILE, ws.getPath());
if (!ws.exists() && !file.isDirectory()) {
useOldWsContent(filePath, ws);
}
- stateStorageManager.addMacro(StoragePathMacros.getMacroName(StoragePathMacros.PROJECT_CONFIG_DIR), dirStore.getPath());
+ stateStorageManager.addMacro(StoragePathMacros.PROJECT_CONFIG_DIR, dirStore.getPath());
ApplicationManager.getApplication().invokeAndWait(new Runnable() {
@Override
@@ -189,10 +188,10 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject
else {
myScheme = StorageScheme.DEFAULT;
- stateStorageManager.addMacro(StoragePathMacros.getMacroName(StoragePathMacros.PROJECT_FILE), filePath);
+ stateStorageManager.addMacro(StoragePathMacros.PROJECT_FILE, filePath);
final String workspacePath = composeWsPath(filePath);
- stateStorageManager.addMacro(StoragePathMacros.getMacroName(StoragePathMacros.WORKSPACE_FILE), workspacePath);
+ stateStorageManager.addMacro(StoragePathMacros.WORKSPACE_FILE, workspacePath);
ApplicationManager.getApplication().invokeAndWait(new Runnable() {
@Override
@@ -202,7 +201,6 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject
}, ModalityState.defaultModalityState());
}
- myCachedLocation = null;
myPresentableUrl = null;
}
@@ -258,18 +256,26 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject
final String path = getProjectFilePath();
if (!StringUtil.isEmptyOrSpaces(path)) {
- return myScheme == StorageScheme.DEFAULT ? new File(path).getParent() : new File(path).getParentFile().getParent();
+ return getBasePath(new File(path));
}
//we are not yet initialized completely ("open directory", etc)
- final StateStorage s = getStateStorageManager().getFileStateStorage(StoragePathMacros.PROJECT_FILE);
- if (!(s instanceof FileBasedStorage)) return null;
- final FileBasedStorage storage = (FileBasedStorage)s;
+ StateStorage storage = getStateStorageManager().getStateStorage(StoragePathMacros.PROJECT_FILE, RoamingType.PER_USER);
+ if (!(storage instanceof FileBasedStorage)) {
+ return null;
+ }
- final File file = storage.getFile();
- if (file == null) return null;
+ return getBasePath(((FileBasedStorage)storage).getFile());
+ }
- return myScheme == StorageScheme.DEFAULT ? file.getParent() : file.getParentFile().getParent();
+ private String getBasePath(@NotNull File file) {
+ if (myScheme == StorageScheme.DEFAULT) {
+ return file.getParent();
+ }
+ else {
+ File parentFile = file.getParentFile();
+ return parentFile == null ? null : parentFile.getParent();
+ }
}
@NotNull
@@ -302,7 +308,7 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject
return baseDir.getName().replace(":", "");
}
else {
- String temp = getProjectFileName();
+ String temp = PathUtilRt.getFileName(((FileBasedStorage)getProjectFileStorage()).getFilePath());
FileType fileType = FileTypeManager.getInstance().getFileTypeByFileName(temp);
if (fileType instanceof ProjectFileType) {
temp = temp.substring(0, temp.length() - fileType.getDefaultExtension().length() - 1);
@@ -316,13 +322,6 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject
}
@NotNull
- private String getProjectFileName() {
- final FileBasedStorage storage = (FileBasedStorage)getStateStorageManager().getFileStateStorage(StoragePathMacros.PROJECT_FILE);
- assert storage != null;
- return storage.getFileName();
- }
-
- @NotNull
@Override
public StorageScheme getStorageScheme() {
return myScheme;
@@ -349,26 +348,28 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject
@Override
public VirtualFile getProjectFile() {
- if (myProject.isDefault()) return null;
- final FileBasedStorage storage = (FileBasedStorage)getStateStorageManager().getFileStateStorage(StoragePathMacros.PROJECT_FILE);
+ return myProject.isDefault() ? null : ((FileBasedStorage)getProjectFileStorage()).getVirtualFile();
+ }
+
+ @NotNull
+ private XmlElementStorage getProjectFileStorage() {
+ // XmlElementStorage if default project, otherwise FileBasedStorage
+ XmlElementStorage storage = (XmlElementStorage)getStateStorageManager().getStateStorage(StoragePathMacros.PROJECT_FILE, RoamingType.PER_USER);
assert storage != null;
- return storage.getVirtualFile();
+ return storage;
}
@Override
public VirtualFile getWorkspaceFile() {
if (myProject.isDefault()) return null;
- final FileBasedStorage storage = (FileBasedStorage)getStateStorageManager().getFileStateStorage(StoragePathMacros.WORKSPACE_FILE);
+ final FileBasedStorage storage = (FileBasedStorage)getStateStorageManager().getStateStorage(StoragePathMacros.WORKSPACE_FILE, RoamingType.DISABLED);
assert storage != null;
return storage.getVirtualFile();
}
@Override
public void loadProjectFromTemplate(@NotNull final ProjectImpl defaultProject) {
- final StateStorage stateStorage = getStateStorageManager().getFileStateStorage(DEFAULT_STATE_STORAGE);
-
- assert stateStorage instanceof XmlElementStorage;
- XmlElementStorage xmlElementStorage = (XmlElementStorage)stateStorage;
+ XmlElementStorage stateStorage = getProjectFileStorage();
defaultProject.save();
final IProjectStore projectStore = defaultProject.getStateStore();
@@ -376,24 +377,19 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject
DefaultProjectStoreImpl defaultProjectStore = (DefaultProjectStoreImpl)projectStore;
final Element element = defaultProjectStore.getStateCopy();
if (element != null) {
- xmlElementStorage.setDefaultState(element);
+ stateStorage.setDefaultState(element);
}
}
@NotNull
@Override
public String getProjectFilePath() {
- if (myProject.isDefault()) return "";
- final FileBasedStorage storage = (FileBasedStorage)getStateStorageManager().getFileStateStorage(StoragePathMacros.PROJECT_FILE);
- assert storage != null;
- return storage.getFilePath();
+ return myProject.isDefault() ? "" : ((FileBasedStorage)getProjectFileStorage()).getFilePath();
}
@Override
protected XmlElementStorage getMainStorage() {
- final XmlElementStorage storage = (XmlElementStorage)getStateStorageManager().getFileStateStorage(DEFAULT_STATE_STORAGE);
- assert storage != null;
- return storage;
+ return getProjectFileStorage();
}
@NotNull
@@ -402,7 +398,6 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject
return new ProjectStateStorageManager(PathMacroManager.getInstance(getComponentManager()).createTrackingSubstitutor(), myProject);
}
-
static class ProjectStorageData extends BaseStorageData {
protected final Project myProject;
@@ -447,16 +442,16 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject
}
@Override
- public void load(@NotNull final Element root) throws IOException {
- final String v = root.getAttributeValue(VERSION_OPTION);
+ public void load(@NotNull Element rootElement, @Nullable PathMacroSubstitutor pathMacroSubstitutor, boolean intern) {
+ final String v = rootElement.getAttributeValue(VERSION_OPTION);
//noinspection AssignmentToStaticFieldFromInstanceMethod
originalVersion = v != null ? Integer.parseInt(v) : 0;
if (originalVersion != ProjectManagerImpl.CURRENT_FORMAT_VERSION) {
- convert(root, originalVersion);
+ convert(rootElement, originalVersion);
}
- super.load(root);
+ super.load(rootElement, pathMacroSubstitutor, intern);
}
protected void convert(final Element root, final int originalVersion) {
@@ -479,19 +474,16 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject
@NotNull
@Override
- public List<IFile> getAllStorageFilesToSave(final boolean includingSubStructures) throws IOException {
- List<IFile> result = new ArrayList<IFile>();
-
+ public List<File> getAllStorageFilesToSave(final boolean includingSubStructures) throws IOException {
+ List<File> result = new SmartList<File>();
if (includingSubStructures) {
- collectSubfilesToSave(result);
+ collectSubFilesToSave(result);
}
-
result.addAll(super.getAllStorageFilesToSave(false));
-
return result;
}
- protected void collectSubfilesToSave(final List<IFile> result) throws IOException { }
+ protected void collectSubFilesToSave(final List<File> result) throws IOException { }
@NotNull
@Override
@@ -523,10 +515,10 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject
return ApplicationManager.getApplication().runReadAction(new Computable<ReadonlyStatusHandler.OperationStatus>() {
@Override
public ReadonlyStatusHandler.OperationStatus compute() {
- final List<IFile> filesToSave;
+ final List<File> filesToSave;
try {
filesToSave = getAllStorageFilesToSave(true);
- final Iterator<IFile> iterator = filesToSave.iterator();
+ final Iterator<File> iterator = filesToSave.iterator();
while (iterator.hasNext()) {
if (!iterator.next().exists()) {
iterator.remove();
@@ -543,14 +535,12 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject
if (myProject.isToSaveProjectName()) {
final VirtualFile baseDir = getProjectBaseDir();
if (baseDir != null && baseDir.isValid()) {
- filesToSave.add(FileSystem.FILE_SYSTEM
- .createFile(new File(new File(baseDir.getPath(), Project.DIRECTORY_STORE_FOLDER), ProjectImpl.NAME_FILE).getPath()));
+ filesToSave.add(new File(new File(baseDir.getPath(), Project.DIRECTORY_STORE_FOLDER), ProjectImpl.NAME_FILE));
}
}
- for (IFile file : filesToSave) {
+ for (File file : filesToSave) {
final VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByIoFile(file);
-
if (virtualFile != null) {
virtualFile.refresh(false, false);
if (virtualFile.isValid() && !virtualFile.isWritable()) {
@@ -670,7 +660,7 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject
@Override
public String file() {
- return DEFAULT_STATE_STORAGE;
+ return StoragePathMacros.PROJECT_FILE;
}
@Override
@@ -679,15 +669,21 @@ class ProjectStoreImpl extends BaseFileConfigurableStoreImpl implements IProject
}
@Override
+ public RoamingType roamingType() {
+ return RoamingType.PER_USER;
+ }
+
+ @Override
public Class<? extends StateStorage> storageClass() {
- return StorageAnnotationsDefaultValues.NullStateStorage.class;
+ return StateStorage.class;
}
@Override
public Class<? extends StateSplitter> stateSplitter() {
- return StorageAnnotationsDefaultValues.NullStateSplitter.class;
+ return StateSplitter.class;
}
+ @NotNull
@Override
public Class<? extends Annotation> annotationType() {
throw new UnsupportedOperationException("Method annotationType not implemented in " + getClass());
diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManager.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManager.java
index 68d882d2b204..d3e9d1c03d2e 100644
--- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManager.java
+++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManager.java
@@ -19,10 +19,10 @@ import com.intellij.openapi.components.*;
import com.intellij.openapi.options.StreamProvider;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.util.io.fs.IFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import java.io.File;
import java.util.Collection;
import java.util.List;
import java.util.Set;
@@ -31,7 +31,7 @@ import java.util.Set;
* @author mike
*/
public interface StateStorageManager {
- void addMacro(String macro, String expansion);
+ void addMacro(@NotNull String macro, @NotNull String expansion);
@Nullable
TrackingPathMacroSubstitutor getMacroSubstitutor();
@@ -40,8 +40,16 @@ public interface StateStorageManager {
StateStorage getStateStorage(@NotNull Storage storageSpec) throws StateStorageException;
@Nullable
+ StateStorage getStateStorage(@NotNull String fileSpec, @NotNull RoamingType roamingType);
+
+ @Deprecated
+ @Nullable
+ /**
+ * @deprecated Use {@link #getStateStorage(String, com.intellij.openapi.components.RoamingType)}
+ */
StateStorage getFileStateStorage(@NotNull String fileSpec);
+ @NotNull
Collection<String> getStorageFileNames();
void clearStateStorage(@NotNull String file);
@@ -57,7 +65,7 @@ public interface StateStorageManager {
@Nullable
StateStorage getOldStorage(Object component, String componentName, StateStorageOperation operation) throws StateStorageException;
- @Nullable
+ @NotNull
String expandMacros(@NotNull String file);
@Deprecated
@@ -81,11 +89,11 @@ public interface StateStorageManager {
Set<String> analyzeExternalChanges(@NotNull Set<Pair<VirtualFile, StateStorage>> files);
@NotNull
- List<IFile> getAllStorageFilesToSave() throws StateStorageException;
+ List<File> getAllStorageFilesToSave() throws StateStorageException;
@NotNull
- List<IFile> getAllStorageFiles();
+ List<File> getAllStorageFiles();
void save() throws StateStorageException;
}
-} \ No newline at end of file
+}
diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java
index 431c9a97820c..651acce271c0 100644
--- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StateStorageManagerImpl.java
@@ -24,12 +24,14 @@ import com.intellij.openapi.options.CurrentUserHolder;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.util.RoamingTypeDisabled;
import com.intellij.openapi.util.io.FileUtilRt;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ObjectUtils;
+import com.intellij.util.PathUtilRt;
+import com.intellij.util.ReflectionUtil;
import com.intellij.util.SmartList;
-import com.intellij.util.io.fs.IFile;
import gnu.trove.THashMap;
import gnu.trove.THashSet;
import gnu.trove.TObjectLongHashMap;
@@ -99,9 +101,14 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di
}
@Override
- public synchronized void addMacro(String macro, String expansion) {
- // avoid hundreds of $MODULE_FILE$ instances
- myMacros.put(("$" + macro + "$").intern(), expansion);
+ public synchronized void addMacro(@NotNull String macro, @NotNull String expansion) {
+ assert !macro.isEmpty();
+ // backward compatibility
+ if (macro.charAt(0) != '$') {
+ LOG.warn("Add macros instead of macro name: " + macro);
+ expansion = '$' + macro + '$';
+ }
+ myMacros.put(macro, expansion);
}
@Override
@@ -123,15 +130,15 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di
}
}
- @Override
@Nullable
- public StateStorage getFileStateStorage(@NotNull String fileName) {
+ @Override
+ public StateStorage getStateStorage(@NotNull String fileSpec, @NotNull RoamingType roamingType) {
myStorageLock.lock();
try {
- StateStorage stateStorage = myStorages.get(fileName);
+ StateStorage stateStorage = myStorages.get(fileSpec);
if (stateStorage == null) {
- stateStorage = createFileStateStorage(fileName);
- putStorageToMap(fileName, stateStorage);
+ stateStorage = createFileStateStorage(fileSpec, roamingType);
+ putStorageToMap(fileSpec, stateStorage);
}
return stateStorage;
}
@@ -141,6 +148,13 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di
}
@Override
+ @Nullable
+ public StateStorage getFileStateStorage(@NotNull String fileSpec) {
+ return getStateStorage(fileSpec, RoamingType.PER_USER);
+ }
+
+ @NotNull
+ @Override
public Collection<String> getStorageFileNames() {
myStorageLock.lock();
try {
@@ -176,19 +190,19 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di
@Nullable
private StateStorage createStateStorage(Storage storageSpec) throws StateStorageException {
- if (!storageSpec.storageClass().equals(StorageAnnotationsDefaultValues.NullStateStorage.class)) {
+ if (!storageSpec.storageClass().equals(StateStorage.class)) {
String key = UUID.randomUUID().toString();
((MutablePicoContainer)myPicoContainer).registerComponentImplementation(key, storageSpec.storageClass());
return (StateStorage)myPicoContainer.getComponentInstance(key);
}
- if (!storageSpec.stateSplitter().equals(StorageAnnotationsDefaultValues.NullStateSplitter.class)) {
+ if (!storageSpec.stateSplitter().equals(StateSplitter.class)) {
return createDirectoryStateStorage(storageSpec.file(), storageSpec.stateSplitter());
}
- return createFileStateStorage(storageSpec.file());
+ return createFileStateStorage(storageSpec.file(), storageSpec.roamingType());
}
private static String getStorageSpecId(Storage storageSpec) {
- if (!storageSpec.storageClass().equals(StorageAnnotationsDefaultValues.NullStateStorage.class)) {
+ if (!storageSpec.storageClass().equals(StateStorage.class)) {
return storageSpec.storageClass().getName();
}
else {
@@ -209,41 +223,30 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di
@Nullable
private StateStorage createDirectoryStateStorage(String file, Class<? extends StateSplitter> splitterClass) throws StateStorageException {
- String expandedFile = expandMacros(file);
- if (expandedFile == null) {
- myStorages.put(file, null);
- return null;
- }
-
final StateSplitter splitter;
try {
- splitter = splitterClass.newInstance();
+ splitter = ReflectionUtil.newInstance(splitterClass);
}
- catch (InstantiationException e) {
+ catch (RuntimeException e) {
throw new StateStorageException(e);
}
- catch (IllegalAccessException e) {
- throw new StateStorageException(e);
- }
-
- return new DirectoryBasedStorage(myPathMacroSubstitutor, expandedFile, splitter, this, myPicoContainer);
+ return new DirectoryBasedStorage(myPathMacroSubstitutor, expandMacros(file), splitter, this, myPicoContainer);
}
@Nullable
- private StateStorage createFileStateStorage(@NotNull final String fileSpec) {
+ private StateStorage createFileStateStorage(@NotNull final String fileSpec, @Nullable RoamingType roamingType) {
String expandedFile = expandMacros(fileSpec);
- if (expandedFile == null) {
- myStorages.put(fileSpec, null);
- return null;
- }
- String extension = FileUtilRt.getExtension(new File(expandedFile).getName());
- if (!ourHeadlessEnvironment && extension.isEmpty()) {
+ if (!ourHeadlessEnvironment && PathUtilRt.getFileName(expandedFile).lastIndexOf('.') < 0) {
throw new IllegalArgumentException("Extension is missing for storage file: " + expandedFile);
}
- return new FileBasedStorage(getMacroSubstitutor(fileSpec), getStreamProvider(), expandedFile, fileSpec, myRootTagName, this,
- myPicoContainer, ComponentRoamingManager.getInstance(), this) {
+ if (roamingType != RoamingType.PER_USER && fileSpec.equals(StoragePathMacros.WORKSPACE_FILE)) {
+ roamingType = RoamingType.DISABLED;
+ }
+
+ return new FileBasedStorage(expandedFile, fileSpec, roamingType, getMacroSubstitutor(fileSpec), myRootTagName, this,
+ myPicoContainer, getStreamProvider(), this) {
@Override
@NotNull
protected StorageData createStorageData() {
@@ -271,8 +274,7 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di
String filePath = getNotNullVersionsFilePath();
if (filePath != null) {
try {
- Document document = JDOMUtil.loadDocument(new File(filePath));
- loadComponentVersions(result, document);
+ loadComponentVersions(result, JDOMUtil.loadDocument(new File(filePath)));
}
catch (JDOMException e) {
LOG.debug(e);
@@ -294,6 +296,7 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di
public static void loadComponentVersions(TObjectLongHashMap<String> result, Document document) {
List<Element> componentObjects = document.getRootElement().getChildren("component");
+ result.ensureCapacity(componentObjects.size());
for (Element component : componentObjects) {
String name = component.getAttributeValue("name");
String version = component.getAttributeValue("version");
@@ -330,26 +333,21 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di
private static final Pattern MACRO_PATTERN = Pattern.compile("(\\$[^\\$]*\\$)");
@Override
- @Nullable
+ @NotNull
public synchronized String expandMacros(@NotNull String file) {
- final Matcher matcher = MACRO_PATTERN.matcher(file);
+ Matcher matcher = MACRO_PATTERN.matcher(file);
while (matcher.find()) {
String m = matcher.group(1);
- if (!myMacros.containsKey(m) || !ApplicationManager.getApplication().isUnitTestMode() && myMacros.get(m) == null) {
- throw new IllegalArgumentException("Unknown macro: " + m + " in storage spec: " + file);
+ if (!myMacros.containsKey(m)) {
+ throw new IllegalArgumentException("Unknown macro: " + m + " in storage file spec: " + file);
}
}
- String actualFile = file;
-
+ String expanded = file;
for (String macro : myMacros.keySet()) {
- final String replacement = myMacros.get(macro);
- if (replacement != null) {
- actualFile = StringUtil.replace(actualFile, macro, replacement);
- }
+ expanded = StringUtil.replace(expanded, macro, myMacros.get(macro));
}
-
- return actualFile;
+ return expanded;
}
@NotNull
@@ -424,7 +422,9 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di
@Override
@Nullable
public StateStorage getOldStorage(Object component, String componentName, StateStorageOperation operation) throws StateStorageException {
- return getFileStateStorage(getOldStorageSpec(component, componentName, operation));
+ String oldStorageSpec = getOldStorageSpec(component, componentName, operation);
+ //noinspection deprecation
+ return oldStorageSpec == null ? null : getStateStorage(oldStorageSpec, component instanceof RoamingTypeDisabled ? RoamingType.DISABLED : RoamingType.PER_USER);
}
@Nullable
@@ -440,14 +440,14 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di
@Override
@NotNull
- public List<IFile> getAllStorageFilesToSave() throws StateStorageException {
+ public List<File> getAllStorageFilesToSave() throws StateStorageException {
assert mySession == this;
return myCompoundSaveSession.getAllStorageFilesToSave();
}
@Override
@NotNull
- public List<IFile> getAllStorageFiles() {
+ public List<File> getAllStorageFiles() {
return myCompoundSaveSession.getAllStorageFiles();
}
@@ -503,15 +503,16 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di
}
public void save() {
- if (!isDirty) return;
+ if (!isDirty) {
+ return;
+ }
+
String filePath = getNotNullVersionsFilePath();
if (filePath != null) {
- File dir = new File(filePath).getParentFile();
- if (!dir.isDirectory() && !dir.mkdirs()) {
- LOG.warn("Unable to create: " + dir);
- }
+ File file = new File(filePath);
+ FileUtilRt.createParentDirs(file);
try {
- JDOMUtil.writeDocument(new Document(createComponentVersionsXml(getComponentVersions())), filePath, "\n");
+ JDOMUtil.writeParent(createComponentVersionsXml(getComponentVersions()), file, "\n");
isDirty = false;
}
catch (IOException e) {
@@ -546,6 +547,7 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di
return root;
}
+ @SuppressWarnings("deprecation")
private static class OldStreamProviderManager extends StreamProvider implements CurrentUserHolder {
private final List<OldStreamProviderAdapter> myStreamProviders = new SmartList<OldStreamProviderAdapter>();
@@ -575,22 +577,17 @@ public abstract class StateStorageManagerImpl implements StateStorageManager, Di
}
@Override
- public boolean saveContent(@NotNull String fileSpec, @NotNull byte[] content, int size, @NotNull RoamingType roamingType, boolean async) throws IOException {
- boolean result = false;
+ public void saveContent(@NotNull String fileSpec, @NotNull byte[] content, int size, @NotNull RoamingType roamingType, boolean async) throws IOException {
for (StreamProvider streamProvider : myStreamProviders) {
try {
- if (streamProvider.isEnabled() && streamProvider.isApplicable(fileSpec, roamingType) && streamProvider.saveContent(fileSpec, content, size, roamingType, async)) {
- result = true;
+ if (streamProvider.isEnabled() && streamProvider.isApplicable(fileSpec, roamingType)) {
+ streamProvider.saveContent(fileSpec, content, size, roamingType, async);
}
}
- catch (ConnectException e) {
- LOG.debug("Cannot send user profile to server: " + e.getLocalizedMessage());
- }
catch (Exception e) {
LOG.debug(e);
}
}
- return result;
}
@Override
diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StorageUtil.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StorageUtil.java
index bd732705446a..2344c8526b0a 100644
--- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StorageUtil.java
+++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StorageUtil.java
@@ -26,7 +26,6 @@ import com.intellij.openapi.editor.DocumentRunnable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectBundle;
import com.intellij.openapi.project.ex.ProjectEx;
-import com.intellij.openapi.util.Couple;
import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream;
@@ -38,7 +37,6 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.SystemProperties;
import com.intellij.util.UniqueFileNamesProvider;
import com.intellij.util.containers.ContainerUtil;
-import com.intellij.util.io.fs.IFile;
import com.intellij.util.ui.UIUtil;
import org.jdom.Document;
import org.jdom.Element;
@@ -59,11 +57,12 @@ import java.util.Set;
* @author mike
*/
public class StorageUtil {
- private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.components.impl.stores.StorageUtil");
+ private static final Logger LOG = Logger.getInstance(StorageUtil.class);
private static final boolean DUMP_COMPONENT_STATES = SystemProperties.getBooleanProperty("idea.log.externally.changed.component.states", false);
@SuppressWarnings("SpellCheckingInspection")
private static final SimpleDateFormat LOG_DIR_FORMAT = new SimpleDateFormat("yyyyMMdd-HHmmss");
+ private static final Pair<byte[], String> NON_EXISTENT_FILE_DATA = Pair.create(null, SystemProperties.getLineSeparator());
private StorageUtil() { }
@@ -110,34 +109,86 @@ public class StorageUtil {
return notified;
}
+
+ public static boolean isEmpty(@Nullable Parent element) {
+ if (element == null) {
+ return true;
+ }
+ else if (element instanceof Element) {
+ return JDOMUtil.isEmpty((Element)element);
+ }
+ else {
+ Document document = (Document)element;
+ return !document.hasRootElement() || JDOMUtil.isEmpty(document.getRootElement());
+ }
+ }
+
+ /**
+ * Due to historical reasons files in ROOT_CONFIG don’t wrapped into document (xml prolog) opposite to files in APP_CONFIG
+ */
@Nullable
- static VirtualFile save(@NotNull IFile file, Parent element, Object requestor) throws StateStorageException {
- try {
- String lineSeparator;
- String oldText;
- if (file.exists()) {
- VirtualFile vFile = LocalFileSystem.getInstance().findFileByIoFile(file);
- Couple<String> pair = loadFile(vFile);
- lineSeparator = pair.second;
- oldText = pair.first;
+ static VirtualFile save(@NotNull File file, @Nullable Parent element, Object requestor, boolean wrapAsDocument, @Nullable VirtualFile cachedVirtualFile) throws StateStorageException {
+ if (isEmpty(element)) {
+ if (!file.exists()) {
+ return null;
+ }
+
+ VirtualFile virtualFile = cachedVirtualFile;
+ if (virtualFile == null || !virtualFile.isValid()) {
+ virtualFile = LocalFileSystem.getInstance().findFileByIoFile(file);
+ }
+ if (virtualFile == null) {
+ LOG.info("Cannot find virtual file " + file.getAbsolutePath());
+ FileUtil.delete(file);
}
else {
- oldText = null;
- lineSeparator = SystemProperties.getLineSeparator();
- file.createParentDirs();
+ AccessToken token = ApplicationManager.getApplication().acquireWriteActionLock(DocumentRunnable.IgnoreDocumentRunnable.class);
+ try {
+ virtualFile.delete(requestor);
+ }
+ catch (IOException e) {
+ throw new StateStorageException(e);
+ }
+ finally {
+ token.finish();
+ }
}
+ return null;
+ }
- String text = JDOMUtil.writeParent(element, lineSeparator);
- if (text.equals(oldText)) {
- return null;
+ VirtualFile virtualFile = cachedVirtualFile == null || !cachedVirtualFile.isValid() ? null : cachedVirtualFile;
+ Parent document = !wrapAsDocument || element instanceof Document ? element : new Document((Element)element);
+ try {
+ BufferExposingByteArrayOutputStream byteOut;
+ if (file.exists()) {
+ if (virtualFile == null) {
+ virtualFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file);
+ }
+
+ Pair<byte[], String> pair = loadFile(virtualFile);
+ byteOut = writeToBytes(document, pair.second);
+ if (equal(pair.first, byteOut)) {
+ return null;
+ }
+ }
+ else {
+ FileUtil.createParentDirs(file);
+ byteOut = writeToBytes(document, SystemProperties.getLineSeparator());
}
// mark this action as modifying the file which daemon analyzer should ignore
AccessToken token = ApplicationManager.getApplication().acquireWriteActionLock(DocumentRunnable.IgnoreDocumentRunnable.class);
try {
- VirtualFile virtualFile = getOrCreateVirtualFile(requestor, file);
- byte[] bytes = text.getBytes(CharsetToolkit.UTF8);
- virtualFile.setBinaryContent(bytes, -1, -1, requestor);
+ if (virtualFile == null) {
+ virtualFile = getOrCreateVirtualFile(requestor, file);
+ }
+ OutputStream virtualFileOut = virtualFile.getOutputStream(requestor);
+ try {
+ byteOut.writeTo(virtualFileOut);
+ }
+ finally {
+ virtualFileOut.close();
+ }
return virtualFile;
}
finally {
@@ -150,70 +201,78 @@ public class StorageUtil {
}
@NotNull
- static VirtualFile getOrCreateVirtualFile(final Object requestor, final IFile ioFile) throws IOException {
- VirtualFile vFile = getVirtualFile(ioFile);
-
- if (vFile == null) {
- vFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(ioFile);
- }
+ private static BufferExposingByteArrayOutputStream writeToBytes(@NotNull Parent element, @NotNull String lineSeparator) throws IOException {
+ BufferExposingByteArrayOutputStream out = new BufferExposingByteArrayOutputStream(512);
+ JDOMUtil.writeParent(element, out, lineSeparator);
+ return out;
+ }
- if (vFile == null) {
- final IFile parentFile = ioFile.getParentFile();
- final VirtualFile parentVFile =
- LocalFileSystem.getInstance().refreshAndFindFileByIoFile(parentFile); // need refresh if the directory has just been created
- if (parentVFile == null) {
- throw new IOException(ProjectBundle.message("project.configuration.save.file.not.found", parentFile.getPath()));
+ @NotNull
+ static VirtualFile getOrCreateVirtualFile(@Nullable Object requestor, @NotNull File ioFile) throws IOException {
+ VirtualFile virtualFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(ioFile);
+ if (virtualFile == null) {
+ File parentFile = ioFile.getParentFile();
+ // need refresh if the directory has just been created
+ VirtualFile parentVirtualFile = parentFile == null ? null : LocalFileSystem.getInstance().refreshAndFindFileByIoFile(parentFile);
+ if (parentVirtualFile == null) {
+ throw new IOException(ProjectBundle.message("project.configuration.save.file.not.found", parentFile == null ? "" : parentFile.getPath()));
}
- vFile = parentVFile.createChildData(requestor, ioFile.getName());
+ virtualFile = parentVirtualFile.createChildData(requestor, ioFile.getName());
}
-
- return vFile;
- }
-
- @Nullable
- static VirtualFile getVirtualFile(final IFile ioFile) {
- return LocalFileSystem.getInstance().findFileByIoFile(ioFile);
+ return virtualFile;
}
/**
* @return pair.first - file contents (null if file does not exist), pair.second - file line separators
*/
- private static Couple<String> loadFile(@Nullable final VirtualFile file) throws IOException {
+ @NotNull
+ private static Pair<byte[], String> loadFile(@Nullable final VirtualFile file) throws IOException {
if (file == null || !file.exists()) {
- return Couple.of(null, SystemProperties.getLineSeparator());
+ return NON_EXISTENT_FILE_DATA;
}
- String fileText = new String(file.contentsToByteArray(), CharsetToolkit.UTF8);
- final int index = fileText.indexOf('\n');
- return Couple.of(fileText, index == -1
- ? SystemProperties.getLineSeparator()
- : index - 1 >= 0 ? fileText.charAt(index - 1) == '\r' ? "\r\n" : "\n" : "\n");
+ byte[] bytes = file.contentsToByteArray();
+ String lineSeparator = file.getDetectedLineSeparator();
+ if (lineSeparator == null) {
+ String fileText = new String(bytes, CharsetToolkit.UTF8);
+ final int index = fileText.indexOf('\n');
+ lineSeparator = index == -1
+ ? SystemProperties.getLineSeparator()
+ : index - 1 >= 0 ? fileText.charAt(index - 1) == '\r' ? "\r\n" : "\n" : "\n";
+ }
+ return Pair.create(bytes, lineSeparator);
}
- public static boolean contentEquals(@NotNull final Document document, @NotNull final VirtualFile file) {
+ public static boolean contentEquals(@NotNull Parent element, @NotNull VirtualFile file) {
+ return newContentIfDiffers(element, file) == null;
+ }
+
+ @Nullable
+ public static BufferExposingByteArrayOutputStream newContentIfDiffers(@NotNull Parent element, @Nullable VirtualFile file) {
try {
- final Couple<String> pair = loadFile(file);
- return pair.first != null && pair.first.equals(JDOMUtil.writeDocument(document, pair.second));
+ Pair<byte[], String> pair = loadFile(file);
+ BufferExposingByteArrayOutputStream out = writeToBytes(element, pair.second);
+ return pair.first != null && equal(pair.first, out) ? null : out;
}
catch (IOException e) {
LOG.debug(e);
- return false;
+ return null;
}
}
- public static boolean contentEquals(@NotNull final Element element, @NotNull final VirtualFile file) {
- try {
- final Couple<String> pair = loadFile(file);
- return pair.first != null && pair.first.equals(printElement(element, pair.second));
- }
- catch (IOException e) {
- LOG.debug(e);
+ public static boolean equal(byte[] a1, @NotNull BufferExposingByteArrayOutputStream out) {
+ int length = out.size();
+ if (a1.length != length) {
return false;
}
- }
- static String printElement(final Element element, final String lineSeparator) throws StateStorageException {
- return JDOMUtil.writeElement(element, lineSeparator);
+ byte[] internalBuffer = out.getInternalBuffer();
+ for (int i = 0; i < length; i++) {
+ if (a1[i] != internalBuffer[i]) {
+ return false;
+ }
+ }
+ return true;
}
@Nullable
@@ -229,6 +288,7 @@ public class StorageUtil {
}
}
+ @SuppressWarnings("Contract")
@Nullable
public static Document loadDocument(@Nullable InputStream stream) {
if (stream == null) {
@@ -252,29 +312,20 @@ public class StorageUtil {
}
@NotNull
- public static BufferExposingByteArrayOutputStream documentToBytes(@NotNull Document document, boolean useSystemLineSeparator) throws IOException {
- BufferExposingByteArrayOutputStream out = new BufferExposingByteArrayOutputStream(512);
- OutputStreamWriter writer = new OutputStreamWriter(out, CharsetToolkit.UTF8_CHARSET);
- try {
- JDOMUtil.writeDocument(document, writer, useSystemLineSeparator ? SystemProperties.getLineSeparator() : "\n");
- return out;
- }
- finally {
- writer.close();
- }
+ public static BufferExposingByteArrayOutputStream elementToBytes(@NotNull Parent element, boolean useSystemLineSeparator) throws IOException {
+ return writeToBytes(element, useSystemLineSeparator ? SystemProperties.getLineSeparator() : "\n");
}
- public static boolean sendContent(@NotNull StreamProvider provider, @NotNull String fileSpec, @NotNull Document copy, @NotNull RoamingType type, boolean async) {
+ public static void sendContent(@NotNull StreamProvider provider, @NotNull String fileSpec, @NotNull Parent element, @NotNull RoamingType type, boolean async) {
if (!provider.isApplicable(fileSpec, type)) {
- return false;
+ return;
}
try {
- return doSendContent(provider, fileSpec, copy, type, async);
+ doSendContent(provider, fileSpec, element, type, async);
}
catch (IOException e) {
LOG.warn(e);
- return false;
}
}
@@ -287,10 +338,10 @@ public class StorageUtil {
/**
* You must call {@link StreamProvider#isApplicable(String, com.intellij.openapi.components.RoamingType)} before
*/
- public static boolean doSendContent(StreamProvider provider, String fileSpec, Document copy, RoamingType type, boolean async) throws IOException {
+ public static void doSendContent(@NotNull StreamProvider provider, @NotNull String fileSpec, @NotNull Parent element, @NotNull RoamingType type, boolean async) throws IOException {
// we should use standard line-separator (\n) - stream provider can share file content on any OS
- BufferExposingByteArrayOutputStream content = documentToBytes(copy, false);
- return provider.saveContent(fileSpec, content.getInternalBuffer(), content.size(), type, async);
+ BufferExposingByteArrayOutputStream content = elementToBytes(element, false);
+ provider.saveContent(fileSpec, content.getInternalBuffer(), content.size(), type, async);
}
public static void logStateDiffInfo(Set<Pair<VirtualFile, StateStorage>> changedFiles, Set<String> componentNames) {
@@ -309,10 +360,9 @@ public class StorageUtil {
StateStorage storage = pair.second;
if (storage instanceof XmlElementStorage) {
- Document state = ((XmlElementStorage)storage).logComponents();
+ Element state = ((XmlElementStorage)storage).logComponents();
if (state != null) {
- File logFile = new File(logDirectory, "prev_" + file.getName());
- JDOMUtil.writeDocument(state, logFile, "\n");
+ JDOMUtil.writeParent(state, new File(logDirectory, "prev_" + file.getName()), "\n");
}
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StreamProvider.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StreamProvider.java
index ec57d8c63601..cf49b927ad0e 100644
--- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StreamProvider.java
+++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/StreamProvider.java
@@ -12,7 +12,9 @@ import java.util.Collections;
public abstract class StreamProvider {
public static final StreamProvider[] EMPTY_ARRAY = new StreamProvider[0];
- public abstract boolean isEnabled();
+ public boolean isEnabled() {
+ return true;
+ }
/**
* If true, special version file per storage file will keep version of component.
@@ -37,7 +39,7 @@ public abstract class StreamProvider {
* @param roamingType
* @param async
*/
- public abstract boolean saveContent(@NotNull String fileSpec, @NotNull byte[] content, int size, @NotNull RoamingType roamingType, boolean async) throws IOException;
+ public abstract void saveContent(@NotNull String fileSpec, @NotNull byte[] content, int size, @NotNull RoamingType roamingType, boolean async) throws IOException;
@Nullable
public abstract InputStream loadContent(@NotNull String fileSpec, @NotNull RoamingType roamingType) throws IOException;
diff --git a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java
index b028676168d5..76f47db77533 100644
--- a/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java
+++ b/platform/platform-impl/src/com/intellij/openapi/components/impl/stores/XmlElementStorage.java
@@ -15,44 +15,48 @@
*/
package com.intellij.openapi.components.impl.stores;
-import com.intellij.ide.plugins.IdeaPluginDescriptorImpl;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.components.*;
import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.options.CurrentUserHolder;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.openapi.vfs.SafeWriteRequestor;
import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.util.io.fs.IFile;
import gnu.trove.THashMap;
+import gnu.trove.THashSet;
import gnu.trove.TObjectLongHashMap;
import org.jdom.Document;
import org.jdom.Element;
+import org.jdom.JDOMException;
import org.jdom.filter.ElementFilter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import java.io.File;
import java.io.IOException;
+import java.io.InputStream;
import java.util.*;
public abstract class XmlElementStorage implements StateStorage, Disposable {
- private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.components.impl.stores.XmlElementStorage");
+ private static final Logger LOG = Logger.getInstance(XmlElementStorage.class);
+
+ private final static RoamingElementFilter DISABLED_ROAMING_ELEMENT_FILTER = new RoamingElementFilter(RoamingType.DISABLED);
private static final String ATTR_NAME = "name";
private static final String VERSION_FILE_SUFFIX = ".ver";
protected TrackingPathMacroSubstitutor myPathMacroSubstitutor;
- @NotNull private final String myRootElementName;
+ @NotNull protected final String myRootElementName;
private Object mySession;
private StorageData myLoadedData;
protected final StreamProvider myStreamProvider;
protected final String myFileSpec;
- private final ComponentRoamingManager myComponentRoamingManager;
protected boolean myBlockSavingTheContent = false;
protected int myUpToDateHash = -1;
- protected int myProviderUpToDateHash = -1;
+ private int myProviderUpToDateHash = -1;
private boolean mySavingDisabled = false;
private final Map<String, Object> myStorageComponentStates = new THashMap<String, Object>(); // at load we store Element, on setState Integer of hash
@@ -60,6 +64,8 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
private final ComponentVersionProvider myLocalVersionProvider;
protected final RemoteComponentVersionProvider myRemoteVersionProvider;
+ private final RoamingType myRoamingType;
+
protected ComponentVersionListener myListener = new ComponentVersionListener(){
@Override
public void componentStateChanged(String componentName) {
@@ -69,18 +75,18 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
private boolean myDisposed;
- protected XmlElementStorage(@Nullable TrackingPathMacroSubstitutor pathMacroSubstitutor,
+ protected XmlElementStorage(@NotNull String fileSpec,
+ @Nullable RoamingType roamingType,
+ @Nullable TrackingPathMacroSubstitutor pathMacroSubstitutor,
@NotNull Disposable parentDisposable,
@NotNull String rootElementName,
@Nullable StreamProvider streamProvider,
- String fileSpec,
- ComponentRoamingManager componentRoamingManager,
ComponentVersionProvider componentVersionProvider) {
+ myFileSpec = fileSpec;
+ myRoamingType = roamingType == null ? RoamingType.PER_USER : roamingType;
myPathMacroSubstitutor = pathMacroSubstitutor;
myRootElementName = rootElementName;
- myStreamProvider = streamProvider;
- myFileSpec = fileSpec;
- myComponentRoamingManager = componentRoamingManager;
+ myStreamProvider = myRoamingType == RoamingType.DISABLED ? null : streamProvider;
Disposer.register(parentDisposable, this);
myLocalVersionProvider = componentVersionProvider;
@@ -92,36 +98,39 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
}
@Nullable
- protected abstract Document loadDocument() throws StateStorageException;
+ protected abstract Element loadLocalData();
@Nullable
- public synchronized Element getState(final String componentName) throws StateStorageException {
+ public synchronized Element getState(@NotNull String componentName) {
final StorageData storageData = getStorageData(false);
final Element state = storageData.getState(componentName);
-
if (state != null) {
if (!myStorageComponentStates.containsKey(componentName)) {
myStorageComponentStates.put(componentName, state);
}
storageData.removeState(componentName);
}
-
return state;
}
@Override
- public boolean hasState(final Object component, final String componentName, final Class<?> aClass, final boolean reloadData) throws StateStorageException {
+ public boolean hasState(final Object component, @NotNull String componentName, final Class<?> aClass, final boolean reloadData) throws StateStorageException {
return getStorageData(reloadData).hasState(componentName);
}
@Override
@Nullable
- public <T> T getState(final Object component, final String componentName, Class<T> stateClass, @Nullable T mergeInto) throws StateStorageException {
+ public <T> T getState(final Object component, @NotNull String componentName, Class<T> stateClass, @Nullable T mergeInto) throws StateStorageException {
return DefaultStateSerializer.deserializeState(getState(componentName), stateClass, mergeInto);
}
@NotNull
- protected StorageData getStorageData(final boolean reloadData) throws StateStorageException {
+ protected StorageData getStorageData() {
+ return getStorageData(false);
+ }
+
+ @NotNull
+ private StorageData getStorageData(boolean reloadData) {
if (myLoadedData != null && !reloadData) {
return myLoadedData;
}
@@ -131,48 +140,48 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
}
@NotNull
- protected StorageData loadData(boolean useProvidersData) throws StateStorageException {
- Document document = loadDocument();
+ protected StorageData loadData(boolean useProvidersData) {
StorageData result = createStorageData();
- if (document != null) {
- loadState(result, document.getRootElement());
- }
-
if (useProvidersData && myStreamProvider != null && myStreamProvider.isEnabled()) {
- for (RoamingType roamingType : RoamingType.values()) {
- if (roamingType != RoamingType.DISABLED && roamingType != RoamingType.GLOBAL) {
- try {
- Document sharedDocument = StorageUtil.loadDocument(myStreamProvider.loadContent(myFileSpec, roamingType));
- if (sharedDocument != null) {
- filterOutOfDate(sharedDocument.getRootElement());
- loadState(result, sharedDocument.getRootElement());
- }
- }
- catch (Exception e) {
- LOG.warn(e);
- }
- }
+ boolean wasLoaded = false;
+ try {
+ wasLoaded = loadDataFromStreamProvider(result);
+ }
+ catch (Exception e) {
+ LOG.warn(e);
+ }
+
+ //noinspection deprecation
+ if (wasLoaded && !myStreamProvider.isVersioningRequired() && !(myStreamProvider instanceof OldStreamProviderAdapter || myStreamProvider instanceof CurrentUserHolder)) {
+ // we don't use local data if stream provider has one (to preserve backward compatibility, we don't use this logic for old stream providers)
+ return result;
}
}
+ Element element = loadLocalData();
+ if (element != null) {
+ loadState(result, element);
+ }
+
return result;
}
- protected void loadState(final StorageData result, final Element element) throws StateStorageException {
- if (myPathMacroSubstitutor != null) {
- myPathMacroSubstitutor.expandPaths(element);
+ private boolean loadDataFromStreamProvider(@NotNull StorageData result) throws IOException, JDOMException {
+ assert myStreamProvider != null;
+ InputStream inputStream = myStreamProvider.loadContent(myFileSpec, myRoamingType);
+ if (inputStream == null) {
+ return false;
}
- IdeaPluginDescriptorImpl.internJDOMElement(element);
+ Element element = JDOMUtil.loadDocument(inputStream).getRootElement();
+ filterOutOfDate(element);
+ loadState(result, element);
+ return true;
+ }
- try {
- result.load(element);
- result.checkUnknownMacros(myPathMacroSubstitutor);
- }
- catch (IOException e) {
- throw new StateStorageException(e);
- }
+ private void loadState(@NotNull StorageData result, @NotNull Element element) {
+ result.load(element, myPathMacroSubstitutor, true);
}
@NotNull
@@ -182,25 +191,15 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
public void setDefaultState(final Element element) {
myLoadedData = createStorageData();
- try {
- loadState(myLoadedData, element);
- }
- catch (StateStorageException e) {
- LOG.error(e);
- }
+ loadState(myLoadedData, element);
}
@Override
@NotNull
public ExternalizationSession startExternalization() {
- try {
- final ExternalizationSession session = new MyExternalizationSession(getStorageData(false).clone(), myListener);
- mySession = session;
- return session;
- }
- catch (StateStorageException e) {
- throw new RuntimeException(e);
- }
+ ExternalizationSession session = new MyExternalizationSession(getStorageData().clone(), myListener);
+ mySession = session;
+ return session;
}
@Override
@@ -226,19 +225,19 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
@NotNull
@Override
- public Collection<IFile> getStorageFilesToSave() throws StateStorageException {
+ public Collection<File> getStorageFilesToSave() throws StateStorageException {
return Collections.emptySet();
}
@NotNull
@Override
- public List<IFile> getAllStorageFiles() {
+ public List<File> getAllStorageFiles() {
return Collections.emptyList();
}
};
}
- protected abstract MySaveSession createSaveSession(final MyExternalizationSession externalizationSession);
+ protected abstract MySaveSession createSaveSession(MyExternalizationSession externalizationSession);
@Override
public void finishSave(@NotNull final SaveSession saveSession) {
@@ -265,22 +264,26 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
}
@Override
- public void setState(@NotNull final Object component, final String componentName, @NotNull final Object state, final Storage storageSpec) throws StateStorageException {
+ public void setState(@NotNull Object component, @NotNull String componentName, @NotNull Object state, @Nullable Storage storageSpec) {
assert mySession == this;
+ Element element;
try {
- setState(componentName, DefaultStateSerializer.serializeState(state, storageSpec));
+ element = DefaultStateSerializer.serializeState(state, storageSpec);
}
catch (WriteExternalException e) {
LOG.debug(e);
+ return;
}
- }
- private synchronized void setState(final String componentName, final Element element) {
- if (element.getAttributes().isEmpty() && element.getChildren().isEmpty()) {
+ if (element == null || JDOMUtil.isEmpty(element)) {
return;
}
+ setState(componentName, element);
+ }
+
+ private synchronized void setState(@NotNull String componentName, @NotNull Element element) {
myStorageData.setState(componentName, element);
int hash = JDOMUtil.getTreeHash(element);
try {
@@ -296,8 +299,12 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
}
}
- protected Document getDocument(StorageData data) {
- final Element element = data.save();
+ @Nullable
+ protected Element getElement(@NotNull StorageData data) {
+ Element element = data.save();
+ if (element == null || JDOMUtil.isEmpty(element)) {
+ return null;
+ }
if (myPathMacroSubstitutor != null) {
try {
@@ -308,18 +315,18 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
}
}
- return new Document(element);
+ return element;
}
protected abstract class MySaveSession implements SaveSession, SafeWriteRequestor {
final StorageData myStorageData;
- private Document myDocumentToSave;
+ private Element myElementToSave;
public MySaveSession(MyExternalizationSession externalizationSession) {
myStorageData = externalizationSession.myStorageData;
}
- public final boolean needsSave() throws StateStorageException {
+ public final boolean needsSave() {
assert mySession == this;
return _needsSave(calcHash());
}
@@ -382,11 +389,10 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
try {
if (myStreamProvider != null && myStreamProvider.isEnabled() && (myProviderUpToDateHash == -1 || myProviderUpToDateHash != hash)) {
try {
- //noinspection IfStatementWithIdenticalBranches
- if (saveForProvider(myStreamProvider)) {
- //noinspection UnnecessaryReturnStatement
- return;
- }
+ saveForProvider();
+ }
+ catch (IOException e) {
+ LOG.warn(e);
}
finally {
myProviderUpToDateHash = hash;
@@ -398,9 +404,9 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
}
}
- private void saveLocally(final Integer hash) {
+ private void saveLocally(int hash) {
try {
- if (!isHashUpToDate(hash) && _needsSave(hash)) {
+ if (!(myUpToDateHash != -1 && myUpToDateHash == hash) && _needsSave(hash)) {
doSave();
}
}
@@ -409,15 +415,15 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
}
}
- private boolean saveForProvider(@NotNull StreamProvider streamProvider) {
- if (!streamProvider.isApplicable(myFileSpec, RoamingType.PER_USER)) {
- return false;
+ private void saveForProvider() throws IOException {
+ if (!myStreamProvider.isApplicable(myFileSpec, myRoamingType)) {
+ return;
}
- Document document = getDocumentToSave();
- Element rootElement = document.getRootElement();
- if (rootElement.getChildren().isEmpty()) {
- return false;
+ Element element = getElementToSave();
+ if (element == null || element.getChildren().isEmpty()) {
+ myStreamProvider.delete(myFileSpec, myRoamingType);
+ return;
}
// skip the whole document if some component has disabled roaming type
@@ -425,59 +431,34 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
// one exclusion: workspace file (you don't have choice in this case)
// for example, it is important for ICS ProjectId - we cannot keep project in another place,
// but this project id must not be shared
- if (!myFileSpec.equals(StoragePathMacros.WORKSPACE_FILE) &&
- rootElement.getContent(new RoamingElementFilter(RoamingType.DISABLED)).iterator().hasNext()) {
- return false;
- }
-
- RoamingElementFilter perPlatformFilter = new RoamingElementFilter(RoamingType.PER_PLATFORM);
- if (rootElement.getContent(perPlatformFilter).iterator().hasNext()) {
- return doSaveForProvider(rootElement, new RoamingElementFilter(RoamingType.PER_USER)) ||
- doSaveForProvider(rootElement, perPlatformFilter);
+ if (myFileSpec.equals(StoragePathMacros.WORKSPACE_FILE)) {
+ Element copiedElement = JDOMUtil.cloneElement(element, DISABLED_ROAMING_ELEMENT_FILTER);
+ if (copiedElement != null) {
+ doSaveForProvider(copiedElement, DISABLED_ROAMING_ELEMENT_FILTER.myRoamingType, myStreamProvider);
+ }
}
else {
- return doSaveForProvider(document, RoamingType.PER_USER, streamProvider);
+ doSaveForProvider(element, myRoamingType, myStreamProvider);
}
}
- private boolean doSaveForProvider(Element element, RoamingElementFilter filter) {
- Element copiedElement = JDOMUtil.cloneElement(element, filter);
- return copiedElement != null && doSaveForProvider(new Document(copiedElement), filter.myRoamingType, myStreamProvider);
- }
-
- private boolean doSaveForProvider(Document actualDocument, RoamingType roamingType, StreamProvider streamProvider) {
- try {
- boolean result = StorageUtil.doSendContent(streamProvider, myFileSpec, actualDocument, roamingType, true);
- if (streamProvider.isVersioningRequired()) {
- TObjectLongHashMap<String> versions = loadVersions(actualDocument.getRootElement().getChildren(StorageData.COMPONENT));
- if (!versions.isEmpty()) {
- Document versionDoc = new Document(StateStorageManagerImpl.createComponentVersionsXml(versions));
- StorageUtil.doSendContent(streamProvider, myFileSpec + VERSION_FILE_SUFFIX, versionDoc, roamingType, true);
- }
+ private void doSaveForProvider(@NotNull Element element, @NotNull RoamingType roamingType, @NotNull StreamProvider streamProvider) throws IOException {
+ StorageUtil.doSendContent(streamProvider, myFileSpec, element, roamingType, true);
+ if (streamProvider.isVersioningRequired()) {
+ TObjectLongHashMap<String> versions = loadVersions(element.getChildren(StorageData.COMPONENT));
+ if (!versions.isEmpty()) {
+ Element versionDoc = StateStorageManagerImpl.createComponentVersionsXml(versions);
+ StorageUtil.doSendContent(streamProvider, myFileSpec + VERSION_FILE_SUFFIX, versionDoc, roamingType, true);
}
- return result;
- }
- catch (IOException e) {
- LOG.warn(e);
- return false;
}
}
- private boolean isHashUpToDate(final Integer hash) {
- return myUpToDateHash != -1 && myUpToDateHash == hash;
- }
-
- protected Document getDocumentToSave() {
- if (myDocumentToSave != null) return myDocumentToSave;
-
- final Element element = myStorageData.save();
- myDocumentToSave = new Document(element);
-
- if (myPathMacroSubstitutor != null) {
- myPathMacroSubstitutor.collapsePaths(element);
+ @Nullable
+ protected Element getElementToSave() {
+ if (myElementToSave == null) {
+ myElementToSave = getElement(myStorageData);
}
-
- return myDocumentToSave;
+ return myElementToSave;
}
public StorageData getData() {
@@ -488,12 +469,12 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
@Nullable
public Set<String> analyzeExternalChanges(@NotNull final Set<Pair<VirtualFile,StateStorage>> changedFiles) {
try {
- Document document = loadDocument();
+ Element element = loadLocalData();
StorageData storageData = createStorageData();
- if (document == null) {
+ if (element == null) {
return Collections.emptySet();
}
- loadState(storageData, document.getRootElement());
+ loadState(storageData, element);
return storageData.getDifference(myStorageData, myPathMacroSubstitutor);
}
catch (StateStorageException e) {
@@ -502,21 +483,6 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
return null;
}
-
- private class RoamingElementFilter extends ElementFilter {
- final RoamingType myRoamingType;
-
- public RoamingElementFilter(RoamingType roamingType) {
- super(StorageData.COMPONENT);
-
- myRoamingType = roamingType;
- }
-
- @Override
- public boolean matches(Object obj) {
- return super.matches(obj) && myComponentRoamingManager.getRoamingType(((Element)obj).getAttributeValue(StorageData.NAME)) == myRoamingType;
- }
- }
}
private TObjectLongHashMap<String> loadVersions(List<Element> elements) {
@@ -545,11 +511,9 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
@Override
public void reload(@NotNull final Set<String> changedComponents) throws StateStorageException {
final StorageData storageData = loadData(false);
-
final StorageData oldLoadedData = myLoadedData;
-
if (oldLoadedData != null) {
- Set<String> componentsToRetain = new HashSet<String>(oldLoadedData.myComponentStates.keySet());
+ Set<String> componentsToRetain = new THashSet<String>(oldLoadedData.myComponentStates.keySet());
componentsToRetain.addAll(changedComponents);
// add empty configuration tags for removed components
@@ -568,7 +532,7 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
myLoadedData = storageData;
}
- private void filterOutOfDate(Element element) {
+ private void filterOutOfDate(@NotNull Element element) {
if (myRemoteVersionProvider == null) {
return;
}
@@ -587,12 +551,19 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
}
@Nullable
- Document logComponents() throws StateStorageException {
- return mySession instanceof MySaveSession ? getDocument(((MySaveSession)mySession).myStorageData) : null;
+ Element logComponents() {
+ return mySession instanceof MySaveSession ? getElement(((MySaveSession)mySession).myStorageData) : null;
}
- protected class RemoteComponentVersionProvider implements ComponentVersionProvider {
- protected TObjectLongHashMap<String> myProviderVersions;
+ public void resetProviderCache() {
+ myProviderUpToDateHash = -1;
+ if (myRemoteVersionProvider != null) {
+ myRemoteVersionProvider.myProviderVersions = null;
+ }
+ }
+
+ private final class RemoteComponentVersionProvider implements ComponentVersionProvider {
+ private TObjectLongHashMap<String> myProviderVersions;
@Override
public long getVersion(String name) {
@@ -632,4 +603,19 @@ public abstract class XmlElementStorage implements StateStorage, Disposable {
}
}
}
+
+ private static class RoamingElementFilter extends ElementFilter {
+ final RoamingType myRoamingType;
+
+ public RoamingElementFilter(RoamingType roamingType) {
+ super(StorageData.COMPONENT);
+
+ myRoamingType = roamingType;
+ }
+
+ @Override
+ public boolean matches(Object obj) {
+ return super.matches(obj) && ComponentRoamingManager.getInstance().getRoamingType(((Element)obj).getAttributeValue(StorageData.NAME)) == myRoamingType;
+ }
+ }
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/ApplicationStarterBase.java b/platform/platform-impl/src/com/intellij/openapi/diff/ApplicationStarterBase.java
index b508686ade00..369acf473cbc 100644
--- a/platform/platform-impl/src/com/intellij/openapi/diff/ApplicationStarterBase.java
+++ b/platform/platform-impl/src/com/intellij/openapi/diff/ApplicationStarterBase.java
@@ -26,6 +26,7 @@ import com.intellij.openapi.vfs.JarFileSystem;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.FileInputStream;
@@ -57,13 +58,13 @@ public abstract class ApplicationStarterBase extends ApplicationStarterEx {
}
@Override
- public void processExternalCommandLine(String[] args) {
+ public void processExternalCommandLine(String[] args, @Nullable String currentDirectory) {
if (!checkArguments(args)) {
Messages.showMessageDialog(getUsageMessage(), StringUtil.toTitleCase(getCommandName()), Messages.getInformationIcon());
return;
}
try {
- processCommand(args);
+ processCommand(args, currentDirectory);
}
catch (Exception e) {
Messages.showMessageDialog(String.format("Error showing %s: %s", getCommandName(), e.getMessage()),
@@ -86,7 +87,7 @@ public abstract class ApplicationStarterBase extends ApplicationStarterEx {
public abstract String getUsageMessage();
- protected abstract void processCommand(String[] args) throws Exception;
+ protected abstract void processCommand(String[] args, @Nullable String currentDirectory) throws Exception;
@Override
public void premain(String[] args) {
@@ -99,7 +100,7 @@ public abstract class ApplicationStarterBase extends ApplicationStarterEx {
@Override
public void main(String[] args) {
try {
- processCommand(args);
+ processCommand(args, null);
}
catch (Exception e) {
e.printStackTrace();
@@ -116,12 +117,12 @@ public abstract class ApplicationStarterBase extends ApplicationStarterEx {
System.exit(0);
}
- public static VirtualFile findOrCreateFile(String path) throws IOException {
+ public static VirtualFile findOrCreateFile(String path, @Nullable String currentDirectory) throws IOException {
final VirtualFile file = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(new File(path));
if (file == null) {
boolean result = new File(path).createNewFile();
if (result) {
- return findFile(path);
+ return findFile(path, currentDirectory);
}
else {
throw new FileNotFoundException("Can't create file " + path);
@@ -167,11 +168,10 @@ public abstract class ApplicationStarterBase extends ApplicationStarterEx {
}
@NotNull
- public static VirtualFile findFile(final String path) throws OperationFailedException {
+ public static VirtualFile findFile(final String path, @Nullable String currentDirectory) throws OperationFailedException {
File ioFile = new File(path);
- if (!ioFile.exists()) {
- final String dir = PathManager.getOriginalWorkingDir();
- ioFile = new File(dir + File.separator + path);
+ if (!ioFile.isAbsolute() && currentDirectory != null) {
+ ioFile = new File(currentDirectory, path);
}
final VirtualFile file = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(ioFile);
if (file == null) {
diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/DiffApplication.java b/platform/platform-impl/src/com/intellij/openapi/diff/DiffApplication.java
index 742a405f350e..143df9617310 100644
--- a/platform/platform-impl/src/com/intellij/openapi/diff/DiffApplication.java
+++ b/platform/platform-impl/src/com/intellij/openapi/diff/DiffApplication.java
@@ -21,6 +21,7 @@ import com.intellij.openapi.application.ApplicationNamesInfo;
import com.intellij.openapi.fileTypes.UnknownFileType;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.vfs.VirtualFile;
+import org.jetbrains.annotations.Nullable;
/**
* @author max
@@ -37,11 +38,11 @@ public class DiffApplication extends ApplicationStarterBase {
return DiffBundle.message("diff.application.usage.parameters.and.description", scriptName);
}
- public void processCommand(String[] args) throws OperationFailedException {
+ public void processCommand(String[] args, @Nullable String currentDirectory) throws OperationFailedException {
final String path1 = args[1];
final String path2 = args[2];
- final VirtualFile file1 = findFile(path1);
- final VirtualFile file2 = findFile(path2);
+ final VirtualFile file1 = findFile(path1, currentDirectory);
+ final VirtualFile file2 = findFile(path2, currentDirectory);
final boolean areDirs = areDirs(file1, file2);
final boolean areJars = areJars(file1, file2);
if (areDirs || areJars) {
diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/MergeApplication.java b/platform/platform-impl/src/com/intellij/openapi/diff/MergeApplication.java
index 0c088929ea49..d1d6cf6cb9f5 100644
--- a/platform/platform-impl/src/com/intellij/openapi/diff/MergeApplication.java
+++ b/platform/platform-impl/src/com/intellij/openapi/diff/MergeApplication.java
@@ -18,6 +18,7 @@ package com.intellij.openapi.diff;
import com.intellij.openapi.application.ApplicationNamesInfo;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.vfs.VirtualFile;
+import org.jetbrains.annotations.Nullable;
/**
* @author Konstantin Bulenkov
@@ -34,11 +35,11 @@ public class MergeApplication extends ApplicationStarterBase {
}
@Override
- protected void processCommand(String[] args) throws Exception {
- final VirtualFile left = findFile(args[1]);
- final VirtualFile right = findFile(args[2]);
- final VirtualFile middle = findFile(args[3]);
- final VirtualFile result = findOrCreateFile(args.length == 4 ? args[3] : args[4]);
+ protected void processCommand(String[] args, @Nullable String currentDirectory) throws Exception {
+ final VirtualFile left = findFile(args[1], currentDirectory);
+ final VirtualFile right = findFile(args[2], currentDirectory);
+ final VirtualFile middle = findFile(args[3], currentDirectory);
+ final VirtualFile result = findOrCreateFile(args.length == 4 ? args[3] : args[4], currentDirectory);
MergeRequest request = DiffRequestFactory.getInstance()
.createMergeRequest(getText(left), getText(right), getText(middle), result,
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/actions/ScrollToTheEndToolbarAction.java b/platform/platform-impl/src/com/intellij/openapi/editor/actions/ScrollToTheEndToolbarAction.java
index cc1be90ef046..dab14bdadcc2 100644
--- a/platform/platform-impl/src/com/intellij/openapi/editor/actions/ScrollToTheEndToolbarAction.java
+++ b/platform/platform-impl/src/com/intellij/openapi/editor/actions/ScrollToTheEndToolbarAction.java
@@ -48,7 +48,7 @@ public class ScrollToTheEndToolbarAction extends DumbAwareAction {
Rectangle visibleArea = myEditor.getScrollingModel().getVisibleArea();
Dimension size = myEditor.getContentComponent().getSize();
boolean isEndVisible = visibleArea.y + visibleArea.height >= size.height;
- boolean isOnLastLine = document.getLineNumber(caretOffset) == document.getLineCount() - 1;
+ boolean isOnLastLine = document.getLineCount() == 0 || document.getLineNumber(caretOffset) == document.getLineCount() - 1;
e.getPresentation().setEnabled(!isEndVisible || !isOnLastLine);
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/colors/impl/EditorColorsManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/colors/impl/EditorColorsManagerImpl.java
index cf3c196a9d78..0d0377bdf7fe 100644
--- a/platform/platform-impl/src/com/intellij/openapi/editor/colors/impl/EditorColorsManagerImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/editor/colors/impl/EditorColorsManagerImpl.java
@@ -382,7 +382,7 @@ public class EditorColorsManagerImpl extends EditorColorsManager implements Name
}
@Override
- public Document writeScheme(@NotNull final EditorColorsSchemeImpl scheme) {
+ public Element writeScheme(@NotNull final EditorColorsSchemeImpl scheme) {
Element root = new Element(SCHEME_NODE_NAME);
try {
scheme.writeExternal(root);
@@ -392,7 +392,7 @@ public class EditorColorsManagerImpl extends EditorColorsManager implements Name
return null;
}
- return new Document(root);
+ return root;
}
@Override
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java
index 51f6ec4a8cdb..165429ce56df 100644
--- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorImpl.java
@@ -81,10 +81,7 @@ import com.intellij.util.containers.ContainerUtilRt;
import com.intellij.util.messages.MessageBusConnection;
import com.intellij.util.text.CharArrayCharSequence;
import com.intellij.util.text.CharArrayUtil;
-import com.intellij.util.ui.ButtonlessScrollBarUI;
-import com.intellij.util.ui.GraphicsUtil;
-import com.intellij.util.ui.MacUIUtil;
-import com.intellij.util.ui.UIUtil;
+import com.intellij.util.ui.*;
import com.intellij.util.ui.update.Activatable;
import com.intellij.util.ui.update.UiNotifyConnector;
import gnu.trove.TIntArrayList;
@@ -4106,7 +4103,7 @@ public final class EditorImpl extends UserDataHolderBase implements EditorEx, Hi
}
private void processMouseDragged(@NotNull MouseEvent e) {
- if (SwingUtilities.isRightMouseButton(e)) {
+ if (JBSwingUtilities.isRightMouseButton(e)) {
return;
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/LazyRangeMarkerFactoryImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/LazyRangeMarkerFactoryImpl.java
index 5a9c704173aa..c4b9a38914cf 100644
--- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/LazyRangeMarkerFactoryImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/LazyRangeMarkerFactoryImpl.java
@@ -56,7 +56,7 @@ public class LazyRangeMarkerFactoryImpl extends LazyRangeMarkerFactory {
private void transformRangeMarkers(@NotNull DocumentEvent e) {
Document document = e.getDocument();
VirtualFile file = fileDocumentManager.getFile(document);
- if (file == null) {
+ if (file == null || myProject.isDisposed()) {
return;
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/SelectionModelImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/SelectionModelImpl.java
index 731d1e26a289..574780a661c2 100644
--- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/SelectionModelImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/SelectionModelImpl.java
@@ -24,6 +24,7 @@
*/
package com.intellij.openapi.editor.impl;
+import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.*;
@@ -36,6 +37,7 @@ import com.intellij.openapi.editor.ex.DocumentEx;
import com.intellij.openapi.editor.ex.PrioritizedDocumentListener;
import com.intellij.openapi.editor.ex.util.EditorUtil;
import com.intellij.openapi.editor.markup.TextAttributes;
+import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Pair;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.ContainerUtil;
@@ -464,6 +466,16 @@ public class SelectionModelImpl implements SelectionModel, PrioritizedDocumentLi
mySelectionListeners.add(listener);
}
+ public void addSelectionListener(final SelectionListener listener, Disposable parent) {
+ mySelectionListeners.add(listener);
+ Disposer.register(parent, new Disposable() {
+ @Override
+ public void dispose() {
+ mySelectionListeners.remove(listener);
+ }
+ });
+ }
+
@Override
public void removeSelectionListener(SelectionListener listener) {
boolean success = mySelectionListeners.remove(listener);
diff --git a/platform/platform-impl/src/com/intellij/openapi/fileChooser/ex/FileChooserDialogImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileChooser/ex/FileChooserDialogImpl.java
index d585ec5a7b7d..2938f419909c 100644
--- a/platform/platform-impl/src/com/intellij/openapi/fileChooser/ex/FileChooserDialogImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/fileChooser/ex/FileChooserDialogImpl.java
@@ -114,16 +114,32 @@ public class FileChooserDialogImpl extends DialogWrapper implements FileChooserD
@Override
@NotNull
- public VirtualFile[] choose(@Nullable VirtualFile toSelect, Project project) {
+ public VirtualFile[] choose(@Nullable final Project project, @NotNull final VirtualFile... toSelect) {
init();
- if (myProject == null && project != null) {
+ if ((myProject == null) && (project != null)) {
myProject = project;
}
- restoreSelection(toSelect);
+ if (toSelect.length == 1) {
+ restoreSelection(toSelect[0]);
+ }
+ else if (toSelect.length == 0) {
+ restoreSelection(null); // select last opened file
+ }
+ else {
+ selectInTree(toSelect, true);
+ }
+
show();
return myChosenFiles;
}
+
+ @NotNull
+ @Override
+ public VirtualFile[] choose(@Nullable final VirtualFile toSelect, @Nullable final Project project) {
+ return choose(project, toSelect);
+ }
+
@Override
public void choose(@Nullable VirtualFile toSelect, @NotNull Consumer<List<VirtualFile>> callback) {
init();
@@ -163,7 +179,6 @@ public class FileChooserDialogImpl extends DialogWrapper implements FileChooserD
if (file != null && file.getFileSystem() instanceof LocalFileSystem) {
saveRecent(file.getPath());
}
-
}
protected void saveRecent(String path) {
diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/ex/FileEditorManagerEx.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/ex/FileEditorManagerEx.java
index 30eb78cf706f..c074a4965493 100644
--- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/ex/FileEditorManagerEx.java
+++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/ex/FileEditorManagerEx.java
@@ -164,6 +164,7 @@ public abstract class FileEditorManagerEx extends FileEditorManager implements B
public abstract boolean isInsideChange();
+ @Override
@Nullable
public final Object getData(@NotNull String dataId, @NotNull Editor editor, @NotNull Caret caret) {
for (final EditorDataProvider dataProvider : myDataProviders) {
diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorComposite.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorComposite.java
index 48a5b7c9a4dc..d8a704d891bf 100644
--- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorComposite.java
+++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorComposite.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -66,7 +66,7 @@ public abstract class EditorComposite implements Disposable {
/**
* File for which composite is created
*/
- private final VirtualFile myFile;
+ @NotNull private final VirtualFile myFile;
/**
* Whether the composite is pinned or not
*/
diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorEmptyTextPainter.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorEmptyTextPainter.java
index 4807812e5047..101f4a7ddfed 100644
--- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorEmptyTextPainter.java
+++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorEmptyTextPainter.java
@@ -54,9 +54,12 @@ public class EditorEmptyTextPainter {
UIUtil.TextPainter painter = new UIUtil.TextPainter().withLineSpacing(1.5f);
painter.withShadow(true, new JBColor(Gray._200.withAlpha(100), Gray._0.withAlpha(255)));
- painter.appendLine("No files are open").underlined(new JBColor(Gray._150, Gray._180));
+ painter.appendLine("No files are open");
- advertiseActions(splitters, painter);
+ if (!splitters.isPreview()) {
+ painter.underlined(new JBColor(Gray._150, Gray._180));
+ advertiseActions(splitters, painter);
+ }
painter.draw(g, new PairFunction<Integer, Integer, Couple<Integer>>() {
@Override
diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorHistoryManager.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorHistoryManager.java
index 32169662ba2a..ddd5395805ff 100644
--- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorHistoryManager.java
+++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorHistoryManager.java
@@ -287,7 +287,7 @@ public final class EditorHistoryManager extends AbstractProjectComponent impleme
}
}
- public FileEditorState getState(final VirtualFile file, final FileEditorProvider provider) {
+ public FileEditorState getState(@NotNull VirtualFile file, final FileEditorProvider provider) {
validateEntries();
final HistoryEntry entry = getEntry(file);
return entry != null ? entry.getState(provider) : null;
@@ -302,7 +302,7 @@ public final class EditorHistoryManager extends AbstractProjectComponent impleme
return entry != null ? entry.mySelectedProvider : null;
}
- private HistoryEntry getEntry(final VirtualFile file){
+ private HistoryEntry getEntry(@NotNull VirtualFile file){
validateEntries();
for (int i = myEntriesList.size() - 1; i >= 0; i--) {
final HistoryEntry entry = myEntriesList.get(i);
diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorTabColorProvider.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorTabColorProvider.java
index babf76dd3709..58f5470aca07 100644
--- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorTabColorProvider.java
+++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorTabColorProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@ package com.intellij.openapi.fileEditor.impl;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.extensions.ExtensionPointName;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.awt.*;
@@ -29,5 +30,5 @@ public interface EditorTabColorProvider {
ExtensionPointName<EditorTabColorProvider> EP_NAME = ExtensionPointName.create("com.intellij.editorTabColorProvider");
@Nullable
- Color getEditorTabColor(Project project, VirtualFile file);
+ Color getEditorTabColor(@NotNull Project project, @NotNull VirtualFile file);
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorTabbedContainer.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorTabbedContainer.java
index 03b03faffe03..3fa0f751e9cb 100644
--- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorTabbedContainer.java
+++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorTabbedContainer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -381,7 +381,7 @@ public final class EditorTabbedContainer implements Disposable, CloseAction.Clos
}
@Nullable
- public static Color calcTabColor(final Project project, final VirtualFile file) {
+ public static Color calcTabColor(@NotNull Project project, @NotNull VirtualFile file) {
for (EditorTabColorProvider provider : Extensions.getExtensions(EditorTabColorProvider.EP_NAME)) {
final Color result = provider.getEditorTabColor(project, file);
if (result != null) {
diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorWindow.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorWindow.java
index 06a3966ade1d..1bf86ea5d62c 100644
--- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorWindow.java
+++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorWindow.java
@@ -287,7 +287,7 @@ public class EditorWindow {
}
}
- public void closeFile(final VirtualFile file, final boolean disposeIfNeeded, final boolean transferFocus) {
+ public void closeFile(@NotNull final VirtualFile file, final boolean disposeIfNeeded, final boolean transferFocus) {
final FileEditorManagerImpl editorManager = getManager();
editorManager.runChange(new FileEditorManagerChange() {
@Override
@@ -525,7 +525,7 @@ public class EditorWindow {
myOwner.setCurrentWindow(this, requestFocus);
}
- public void updateFileBackgroundColor(final VirtualFile file) {
+ public void updateFileBackgroundColor(@NotNull VirtualFile file) {
final int index = findEditorIndex(findFileComposite(file));
if (index != -1) {
final Color color = EditorTabbedContainer.calcTabColor(getManager().getProject(), file);
@@ -569,10 +569,10 @@ public class EditorWindow {
}
protected static class TComp extends JPanel implements DataProvider, EditorWindowHolder {
- final EditorWithProviderComposite myEditor;
+ @NotNull final EditorWithProviderComposite myEditor;
protected final EditorWindow myWindow;
- TComp(final EditorWindow window, final EditorWithProviderComposite editor) {
+ TComp(@NotNull EditorWindow window, @NotNull EditorWithProviderComposite editor) {
super(new BorderLayout());
myEditor = editor;
myWindow = window;
@@ -594,6 +594,7 @@ public class EditorWindow {
});
}
+ @NotNull
@Override
public EditorWindow getEditorWindow() {
return myWindow;
@@ -613,7 +614,7 @@ public class EditorWindow {
}
protected static class TCompForTablessMode extends TComp implements CloseAction.CloseTarget {
- TCompForTablessMode(final EditorWindow window, final EditorWithProviderComposite editor) {
+ TCompForTablessMode(@NotNull EditorWindow window, @NotNull EditorWithProviderComposite editor) {
super(window, editor);
}
@@ -701,6 +702,7 @@ public class EditorWindow {
public void setEditor(@Nullable final EditorWithProviderComposite editor, final boolean selectEditor, final boolean focusEditor) {
if (editor != null) {
+ onBeforeSetEditor(editor.getFile());
if (myTabbedPane == null) {
myPanel.removeAll ();
myPanel.add (new TCompForTablessMode(this, editor), BorderLayout.CENTER);
@@ -741,6 +743,9 @@ public class EditorWindow {
myOwner.validate();
}
+ protected void onBeforeSetEditor(VirtualFile file) {
+ }
+
private boolean splitAvailable() {
return getTabCount() >= 1;
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorWindowHolder.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorWindowHolder.java
index c708d058b63b..2d27bb853531 100644
--- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorWindowHolder.java
+++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorWindowHolder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2011 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,9 +15,12 @@
*/
package com.intellij.openapi.fileEditor.impl;
+import org.jetbrains.annotations.NotNull;
+
/**
* @author Konstantin Bulenkov
*/
public interface EditorWindowHolder {
+ @NotNull
EditorWindow getEditorWindow();
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorsSplitters.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorsSplitters.java
index b9e38809faab..c380d38a5db9 100644
--- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorsSplitters.java
+++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorsSplitters.java
@@ -51,6 +51,7 @@ import com.intellij.util.Alarm;
import com.intellij.util.containers.ArrayListSet;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.UIUtil;
+import gnu.trove.THashSet;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -76,7 +77,7 @@ public class EditorsSplitters extends IdePanePanel implements UISettingsListener
private static final Key<Object> DUMMY_KEY = Key.create("EditorsSplitters.dummy.key");
- private final static EditorEmptyTextPainter ourPainter = ServiceManager.getService(EditorEmptyTextPainter.class);
+ private static final EditorEmptyTextPainter ourPainter = ServiceManager.getService(EditorEmptyTextPainter.class);
private EditorWindow myCurrentWindow;
final Set<EditorWindow> myWindows = new CopyOnWriteArraySet<EditorWindow>();
@@ -346,22 +347,18 @@ public class EditorsSplitters extends IdePanePanel implements UISettingsListener
return virtualFiles;
}
- @NotNull public FileEditor[] getSelectedEditors() {
- final List<FileEditor> editors = new ArrayList<FileEditor>();
+ @NotNull
+ public FileEditor[] getSelectedEditors() {
+ List<FileEditor> editors = new ArrayList<FileEditor>();
+ Set<EditorWindow> windows = new THashSet<EditorWindow>(myWindows);
final EditorWindow currentWindow = getCurrentWindow();
if (currentWindow != null) {
- final EditorWithProviderComposite composite = currentWindow.getSelectedEditor();
- if (composite != null) {
- editors.add (composite.getSelectedEditor());
- }
+ windows.add(currentWindow);
}
-
- for (final EditorWindow window : myWindows) {
- if (!window.equals(currentWindow)) {
- final EditorWithProviderComposite composite = window.getSelectedEditor();
- if (composite != null) {
- editors.add(composite.getSelectedEditor());
- }
+ for (final EditorWindow window : windows) {
+ final EditorWithProviderComposite composite = window.getSelectedEditor();
+ if (composite != null) {
+ editors.add(composite.getSelectedEditor());
}
}
return editors.toArray(new FileEditor[editors.size()]);
@@ -463,7 +460,7 @@ public class EditorsSplitters extends IdePanePanel implements UISettingsListener
myCurrentWindow = currentWindow;
}
- public void updateFileBackgroundColor(final VirtualFile file) {
+ public void updateFileBackgroundColor(@NotNull VirtualFile file) {
final EditorWindow[] windows = getWindows();
for (int i = 0; i != windows.length; ++ i) {
windows [i].updateFileBackgroundColor(file);
@@ -614,10 +611,14 @@ public class EditorsSplitters extends IdePanePanel implements UISettingsListener
public void createCurrentWindow() {
LOG.assertTrue(myCurrentWindow == null);
- setCurrentWindow(new EditorWindow(this));
+ setCurrentWindow(createEditorWindow());
add(myCurrentWindow.myPanel, BorderLayout.CENTER);
}
+ protected EditorWindow createEditorWindow() {
+ return new EditorWindow(this);
+ }
+
/**
* sets the window passed as a current ('focused') window among all splitters. All file openings will be done inside this
* current window
@@ -625,7 +626,7 @@ public class EditorsSplitters extends IdePanePanel implements UISettingsListener
* @param requestFocus whether to request focus to the editor currently selected in this window
*/
public void setCurrentWindow(@Nullable final EditorWindow window, final boolean requestFocus) {
- final EditorWithProviderComposite newEditor = window != null? window.getSelectedEditor() : null;
+ final EditorWithProviderComposite newEditor = window == null ? null : window.getSelectedEditor();
Runnable fireRunnable = new Runnable() {
@Override
@@ -655,7 +656,7 @@ public class EditorsSplitters extends IdePanePanel implements UISettingsListener
//---------------------------------------------------------
public EditorWithProviderComposite[] getEditorsComposites() {
- final ArrayList<EditorWithProviderComposite> res = new ArrayList<EditorWithProviderComposite>();
+ List<EditorWithProviderComposite> res = new ArrayList<EditorWithProviderComposite>();
for (final EditorWindow myWindow : myWindows) {
final EditorWithProviderComposite[] editors = myWindow.getEditors();
@@ -667,8 +668,8 @@ public class EditorsSplitters extends IdePanePanel implements UISettingsListener
//---------------------------------------------------------
@NotNull
- public List<EditorWithProviderComposite> findEditorComposites(final VirtualFile file) {
- final ArrayList<EditorWithProviderComposite> res = new ArrayList<EditorWithProviderComposite>();
+ public List<EditorWithProviderComposite> findEditorComposites(@NotNull VirtualFile file) {
+ List<EditorWithProviderComposite> res = new ArrayList<EditorWithProviderComposite>();
for (final EditorWindow window : myWindows) {
final EditorWithProviderComposite fileComposite = window.findFileComposite(file);
if (fileComposite != null) {
@@ -680,7 +681,7 @@ public class EditorsSplitters extends IdePanePanel implements UISettingsListener
@NotNull
public List<EditorWindow> findWindows(final VirtualFile file) {
- final ArrayList<EditorWindow> res = new ArrayList<EditorWindow>();
+ List<EditorWindow> res = new ArrayList<EditorWindow>();
for (final EditorWindow window : myWindows) {
if (window.findFileComposite(file) != null) {
res.add(window);
@@ -694,7 +695,7 @@ public class EditorsSplitters extends IdePanePanel implements UISettingsListener
}
@NotNull public EditorWindow[] getOrderedWindows() {
- final ArrayList<EditorWindow> res = new ArrayList<EditorWindow>();
+ final List<EditorWindow> res = new ArrayList<EditorWindow>();
// Collector for windows in tree ordering:
class Inner{
@@ -744,6 +745,10 @@ public class EditorsSplitters extends IdePanePanel implements UISettingsListener
return false;
}
+ public boolean isPreview() {
+ return false;
+ }
+
private final class MyFocusWatcher extends FocusWatcher {
@Override
protected void focusedComponentChanged(final Component component, final AWTEvent cause) {
@@ -816,8 +821,10 @@ public class EditorsSplitters extends IdePanePanel implements UISettingsListener
return processFiles(children, context);
}
- protected abstract @Nullable T processFiles(@NotNull List<Element> fileElements, @Nullable T context);
- protected abstract @Nullable T processSplitter(@NotNull Element element, @Nullable Element firstChild, @Nullable Element secondChild, @Nullable T context);
+ @Nullable
+ protected abstract T processFiles(@NotNull List<Element> fileElements, @Nullable T context);
+ @Nullable
+ protected abstract T processSplitter(@NotNull Element element, @Nullable Element firstChild, @Nullable Element secondChild, @Nullable T context);
}
private class UIBuilder extends ConfigTreeReader<JPanel> {
@@ -828,7 +835,7 @@ public class EditorsSplitters extends IdePanePanel implements UISettingsListener
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
@Override
public void run() {
- windowRef.set(context == null ? new EditorWindow(EditorsSplitters.this) : findWindowWith(context));
+ windowRef.set(context == null ? createEditorWindow() : findWindowWith(context));
}
});
final EditorWindow window = windowRef.get();
diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java
index 65adf52041b9..abf16d54c43d 100644
--- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/FileEditorManagerImpl.java
@@ -58,7 +58,6 @@ import com.intellij.openapi.vcs.FileStatusListener;
import com.intellij.openapi.vcs.FileStatusManager;
import com.intellij.openapi.vfs.*;
import com.intellij.openapi.wm.IdeFocusManager;
-import com.intellij.openapi.wm.ToolWindowId;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.openapi.wm.ex.StatusBarEx;
@@ -91,7 +90,6 @@ import java.beans.PropertyChangeListener;
import java.lang.ref.WeakReference;
import java.util.*;
import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
/**
* @author Anton Katilin
@@ -113,7 +111,6 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Projec
private final Project myProject;
private final List<Pair<VirtualFile, EditorWindow>> mySelectionHistory = new ArrayList<Pair<VirtualFile, EditorWindow>>();
private WeakReference<EditorComposite> myLastSelectedComposite = new WeakReference<EditorComposite>(null);
- private final AtomicBoolean myPreviewBlocker = new AtomicBoolean(false);
private final MergingUpdateQueue myQueue = new MergingUpdateQueue("FileEditorManagerUpdateQueue", 50, true, null);
@@ -179,9 +176,9 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Projec
public Set<EditorsSplitters> getAllSplitters() {
HashSet<EditorsSplitters> all = new LinkedHashSet<EditorsSplitters>();
- if (Registry.is("editor.use.preview")) {
- initUI();
- all.add(myPreviewPanel.getWindow().getOwner());
+ EditorWindow previewWindow = getPreviewWindow();
+ if (previewWindow != null) {
+ all.add(previewWindow.getOwner());
}
all.add(getMainSplitters());
Set<DockContainer> dockContainers = myDockManager.getContainers();
@@ -255,16 +252,23 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Projec
}
}
}
- if (myPreviewPanel == null && Registry.is("editor.use.preview")) {
+ if (myPreviewPanel == null && PreviewPanel.isAvailable()) {
synchronized (myInitLock) {
myPreviewPanel = new PreviewPanel(myProject, this, myDockManager);
}
}
}
+ @Nullable
+ private EditorWindow getPreviewWindow() {
+ if (!PreviewPanel.isAvailable()) return null;
+ initUI();
+ return myPreviewPanel.getWindow();
+ }
+
private static class MyBorder implements Border {
@Override
- public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
+ public void paintBorder(@NotNull Component c, @NotNull Graphics g, int x, int y, int width, int height) {
if (UIUtil.isUnderAquaLookAndFeel()) {
g.setColor(JBTabsImpl.MAC_AQUA_BG_COLOR);
final Insets insets = getBorderInsets(c);
@@ -274,6 +278,7 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Projec
}
}
+ @NotNull
@Override
public Insets getBorderInsets(Component c) {
return JBInsets.NONE;
@@ -607,7 +612,7 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Projec
@Override
@NotNull
public Pair<FileEditor[], FileEditorProvider[]> openFileWithProviders(@NotNull final VirtualFile file,
- final boolean focusEditor,
+ boolean focusEditor,
final boolean searchForSplitter) {
if (!file.isValid()) {
throw new IllegalArgumentException("file is not valid: " + file);
@@ -642,9 +647,10 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Projec
}
if (wndToOpenIn == null || !wndToOpenIn.isFileOpen(file)) {
- EditorWindow previewWindow = getPreviewWindow(file, focusEditor, searchForSplitter);
+ EditorWindow previewWindow = getPreviewWindow();
if (previewWindow != null) {
wndToOpenIn = previewWindow;
+ focusEditor = true;
}
}
@@ -658,31 +664,6 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Projec
return openFileImpl2(wndToOpenIn, file, focusEditor);
}
- @Nullable
- private EditorWindow getPreviewWindow(@NotNull VirtualFile virtualFile, final boolean focusEditor, final boolean searchForSplitter) {
- EditorWindow wndToOpenIn = null;
- if (Registry.is("editor.use.preview") && !myPreviewBlocker.get()) {
- wndToOpenIn = myPreviewPanel.getWindow();
- if (virtualFile.equals(myPreviewPanel.getCurrentFile())) return wndToOpenIn;
- final VirtualFile modifiedFile = myPreviewPanel.closeCurrentFile();
- ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.PREVIEW).activate(null, false);
- if (modifiedFile != null) {
- CommandProcessor.getInstance().executeCommand(myProject, new Runnable() {
- @Override
- public void run() {
- myPreviewBlocker.set(true);
- try {
- openFileWithProviders(modifiedFile, focusEditor, searchForSplitter);
- } finally {
- myPreviewBlocker.set(false);
- }
- }
- }, "", null);
- }
- }
- return wndToOpenIn;
- }
-
public Pair<FileEditor[], FileEditorProvider[]> openFileInNewWindow(@NotNull VirtualFile file) {
return ((DockManagerImpl)DockManager.getInstance(getProject())).createNewDockContainerFor(file, this);
}
@@ -805,7 +786,7 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Projec
final FileEditorProvider provider = newProviders[i];
LOG.assertTrue(provider != null, "Provider for file "+file+" is null. All providers: "+Arrays.asList(newProviders));
LOG.assertTrue(provider.accept(myProject, file), "Provider " + provider + " doesn't accept file " + file);
- if ((provider instanceof AsyncFileEditorProvider)) {
+ if (provider instanceof AsyncFileEditorProvider) {
builders[i] = ((AsyncFileEditorProvider)provider).createEditorAsync(myProject, file);
}
}
@@ -944,7 +925,7 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Projec
return Pair.create(compositeRef.get().getEditors(), compositeRef.get().getProviders());
}
- private void clearWindowIfNeeded(EditorWindow window) {
+ private static void clearWindowIfNeeded(EditorWindow window) {
if (UISettings.getInstance().EDITOR_TAB_PLACEMENT == UISettings.TABS_NONE || UISettings.getInstance().PRESENTATION_MODE) {
for (EditorWithProviderComposite composite : window.getEditors()) {
Disposer.dispose(composite);
@@ -1177,9 +1158,15 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Projec
@Override
public Editor getSelectedTextEditor() {
- assertReadAccess();
+ return getSelectedTextEditor(false);
+ }
- final EditorWindow currentWindow = getSplitters().getCurrentWindow();
+ public Editor getSelectedTextEditor(boolean lockfree) {
+ if (!lockfree) {
+ assertDispatchThread();
+ }
+
+ final EditorWindow currentWindow = lockfree ? getMainSplitters().getCurrentWindow() : getSplitters().getCurrentWindow();
if (currentWindow != null) {
final EditorWithProviderComposite selectedEditor = currentWindow.getSelectedEditor();
if (selectedEditor != null && selectedEditor.getSelectedEditor() instanceof TextEditor) {
@@ -1191,6 +1178,7 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Projec
}
+
@Override
public boolean isFileOpen(@NotNull final VirtualFile file) {
return !getEditorComposites(file).isEmpty();
@@ -1760,7 +1748,7 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Projec
private final class MyEditorPropertyChangeListener implements PropertyChangeListener {
@Override
- public void propertyChange(final PropertyChangeEvent e) {
+ public void propertyChange(@NotNull final PropertyChangeEvent e) {
assertDispatchThread();
final String propertyName = e.getPropertyName();
@@ -1999,6 +1987,7 @@ public class FileEditorManagerImpl extends FileEditorManagerEx implements Projec
mySelectionHistory.remove(Pair.create(file, window));
}
+ @NotNull
@Override
public ActionCallback getReady(@NotNull Object requestor) {
return myBusyObject.getReady(requestor);
diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/IdeDocumentHistoryImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/IdeDocumentHistoryImpl.java
index 752ab1228c3e..0e4f057dbeaf 100644
--- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/IdeDocumentHistoryImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/IdeDocumentHistoryImpl.java
@@ -145,16 +145,12 @@ public class IdeDocumentHistoryImpl extends IdeDocumentHistory implements Projec
}
public static class RecentlyChangedFilesState {
- @Transient private List<String> CHANGED_PATHS = new ArrayList<String>();
+ @Transient private final List<String> CHANGED_PATHS = new ArrayList<String>();
public List<String> getChangedFiles() {
return CHANGED_PATHS;
}
- public void setChangedFiles(List<String> changed) {
- CHANGED_PATHS = changed;
- }
-
public void register(VirtualFile file) {
final String path = file.getPath();
CHANGED_PATHS.remove(path);
@@ -275,7 +271,7 @@ public class IdeDocumentHistoryImpl extends IdeDocumentHistory implements Projec
myCurrentChangePlace = placeInfo;
if (!myChangePlaces.isEmpty()) {
- final PlaceInfo lastInfo = myChangePlaces.get(myChangePlaces.size() - 1);
+ final PlaceInfo lastInfo = myChangePlaces.getLast();
if (isSame(placeInfo, lastInfo)) {
myChangePlaces.removeLast();
}
@@ -430,7 +426,7 @@ public class IdeDocumentHistoryImpl extends IdeDocumentHistory implements Projec
}
}
- private static boolean removeInvalidFilesFrom(final LinkedList<PlaceInfo> backPlaces) {
+ private static boolean removeInvalidFilesFrom(@NotNull List<PlaceInfo> backPlaces) {
boolean removed = false;
for (Iterator<PlaceInfo> iterator = backPlaces.iterator(); iterator.hasNext();) {
PlaceInfo info = iterator.next();
@@ -456,7 +452,7 @@ public class IdeDocumentHistoryImpl extends IdeDocumentHistory implements Projec
myEditorManager.setSelectedEditor(info.getFile(), info.getEditorTypeId());
- final FileEditor [] editors = editorsWithProviders.getFirst();
+ final FileEditor[] editors = editorsWithProviders.getFirst();
final FileEditorProvider[] providers = editorsWithProviders.getSecond();
for (int i = 0; i < editors.length; i++) {
String typeId = providers [i].getEditorTypeId();
@@ -483,7 +479,7 @@ public class IdeDocumentHistoryImpl extends IdeDocumentHistory implements Projec
return new PlaceInfo(file, state, fileProvider.getEditorTypeId(), myEditorManager.getCurrentWindow());
}
- private static void clearPlaceList(LinkedList<PlaceInfo> list) {
+ private static void clearPlaceList(@NotNull List<PlaceInfo> list) {
list.clear();
}
@@ -494,9 +490,9 @@ public class IdeDocumentHistoryImpl extends IdeDocumentHistory implements Projec
return "IdeDocumentHistory";
}
- private static void putLastOrMerge(LinkedList<PlaceInfo> list, PlaceInfo next, int limitSizeLimit) {
+ private static void putLastOrMerge(@NotNull LinkedList<PlaceInfo> list, @NotNull PlaceInfo next, int limitSizeLimit) {
if (!list.isEmpty()) {
- PlaceInfo prev = list.get(list.size() - 1);
+ PlaceInfo prev = list.getLast();
if (isSame(prev, next)) {
list.removeLast();
}
@@ -522,7 +518,7 @@ public class IdeDocumentHistoryImpl extends IdeDocumentHistory implements Projec
private final String myEditorTypeId;
private final WeakReference<EditorWindow> myWindow;
- public PlaceInfo(@NotNull VirtualFile file, FileEditorState navigationState, String editorTypeId, @Nullable EditorWindow window) {
+ public PlaceInfo(@NotNull VirtualFile file, @NotNull FileEditorState navigationState, @NotNull String editorTypeId, @Nullable EditorWindow window) {
myNavigationState = navigationState;
myFile = file;
myEditorTypeId = editorTypeId;
@@ -533,6 +529,7 @@ public class IdeDocumentHistoryImpl extends IdeDocumentHistory implements Projec
return myWindow.get();
}
+ @NotNull
public FileEditorState getNavigationState() {
return myNavigationState;
}
@@ -542,24 +539,23 @@ public class IdeDocumentHistoryImpl extends IdeDocumentHistory implements Projec
return myFile;
}
+ @NotNull
public String getEditorTypeId() {
return myEditorTypeId;
}
+ @Override
public String toString() {
return getFile().getName() + " " + getNavigationState();
}
}
- public LinkedList<PlaceInfo> getBackPlaces() {
+ @NotNull
+ public List<PlaceInfo> getBackPlaces() {
return myBackPlaces;
}
- public LinkedList<PlaceInfo> getForwardPlaces() {
- return myForwardPlaces;
- }
-
@Override
public final void initComponent() { }
@@ -572,7 +568,7 @@ public class IdeDocumentHistoryImpl extends IdeDocumentHistory implements Projec
myCmdProcessor.executeCommand(myProject, runnable, name, groupId);
}
- private static boolean isSame(PlaceInfo first, PlaceInfo second) {
+ private static boolean isSame(@NotNull PlaceInfo first, @NotNull PlaceInfo second) {
if (first.getFile().equals(second.getFile())) {
FileEditorState firstState = first.getNavigationState();
FileEditorState secondState = second.getNavigationState();
diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/PreviewPanel.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/PreviewPanel.java
index a9634d5a335a..999fe75523e9 100644
--- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/PreviewPanel.java
+++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/PreviewPanel.java
@@ -17,162 +17,276 @@ package com.intellij.openapi.fileEditor.impl;
import com.intellij.icons.AllIcons;
import com.intellij.ide.ui.UISettings;
+import com.intellij.ide.ui.UISettingsListener;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.editor.Document;
-import com.intellij.openapi.editor.event.DocumentEvent;
-import com.intellij.openapi.editor.event.DocumentListener;
-import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.actionSystem.DefaultActionGroup;
+import com.intellij.openapi.actionSystem.ToggleAction;
+import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.FileEditorManagerListener;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.openapi.wm.ToolWindowAnchor;
-import com.intellij.openapi.wm.ToolWindowId;
-import com.intellij.openapi.wm.ToolWindowManager;
+import com.intellij.openapi.wm.*;
import com.intellij.openapi.wm.impl.ToolWindowImpl;
-import com.intellij.ui.JBColor;
+import com.intellij.openapi.wm.impl.content.ToolWindowContentUi;
+import com.intellij.ui.content.Content;
+import com.intellij.ui.content.ContentManager;
+import com.intellij.ui.content.ContentManagerAdapter;
+import com.intellij.ui.content.ContentManagerEvent;
import com.intellij.ui.docking.DockManager;
+import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
+import java.util.EnumSet;
-class PreviewPanel extends JPanel implements DocumentListener, FileEditorManagerListener.Before {
+class PreviewPanel extends JPanel {
+
+ private CardLayout myLayout;
+
+ enum ContentType {Files, Usages, Diagrams, Documentation}
+
+ private static final Key<VirtualFile> FILE_KEY = Key.create("v_file");
private static final int HISTORY_LIMIT = 10;
private final Project myProject;
private final FileEditorManagerImpl myManager;
private final DockManager myDockManager;
private EditorWindow myWindow;
- private boolean myInitialized = false;
private EditorsSplitters myEditorsSplitters;
private ArrayList<VirtualFile> myHistory = new ArrayList<VirtualFile>();
private VirtualFile myModifiedFile = null;
private ToolWindowImpl myToolWindow;
private VirtualFile myAwaitingForOpen = null;
+ private ContentManager myContentManager;
+ private Content myStubContent;
+ private boolean myBlocked = false;
+
+ private EnumSet<ContentType> myTypes = EnumSet.noneOf(ContentType.class);
+
+ static boolean isAvailable() {
+ return UISettings.getInstance().NAVIGATE_TO_PREVIEW;
+ }
- public PreviewPanel(Project project, FileEditorManagerImpl manager, DockManager dockManager) {
+ PreviewPanel(Project project, FileEditorManagerImpl manager, DockManager dockManager) {
myProject = project;
myManager = manager;
myDockManager = dockManager;
- setOpaque(true);
- setBackground(JBColor.DARK_GRAY);
+ }
+
+ /*
+ * @return null if preview is not avalable
+ */
+ @Nullable
+ EditorWindow getWindow() {
+ if (!isAvailable() || isBlocked() || myProject.isDisposed()) return null;
+ initToolWindowIfNeed();
+ return myWindow;
+ }
+
+ boolean isBlocked() {
+ return myBlocked;
}
private void initToolWindowIfNeed() {
- if (myInitialized) return;
+ if (!isAvailable() || ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.PREVIEW) != null) return;
myToolWindow = (ToolWindowImpl)ToolWindowManager.getInstance(myProject)
.registerToolWindow(ToolWindowId.PREVIEW, this, ToolWindowAnchor.RIGHT, myProject, false);
- myToolWindow.setIcon(AllIcons.Actions.PreviewDetails);
-
- myEditorsSplitters = new EditorsSplitters(myManager, myDockManager, false) {
+ UISettings.getInstance().addUISettingsListener(new UISettingsListener() {
@Override
- public void updateFileName(VirtualFile updatedFile) {
- super.updateFileName(updatedFile);
- if (updatedFile != null && updatedFile.equals(getCurrentFile())) {
- updateWindowTitle(updatedFile);
- }
- }
-
- @Override
- protected void afterFileOpen(VirtualFile file) {
- if (file.equals(myAwaitingForOpen)) {
- updateWindowTitle(file);
- Document document = FileDocumentManager.getInstance().getDocument(file);
- if (document != null) {
- myModifiedFile = null;
- document.addDocumentListener(PreviewPanel.this, myProject);
+ public void uiSettingsChanged(UISettings source) {
+ if (!isAvailable()) {
+ VirtualFile[] files = myWindow.getFiles();
+ for (VirtualFile file : files) {
+ close(file);
}
+ ToolWindowManager.getInstance(myProject).unregisterToolWindow(ToolWindowId.PREVIEW);
}
- myAwaitingForOpen = null;
}
-
+ }, myProject);
+ myToolWindow.setIcon(AllIcons.Actions.PreviewDetails);
+ myToolWindow.setContentUiType(ToolWindowContentUiType.COMBO, null);
+ myContentManager = myToolWindow.getContentManager();
+ myStubContent = myContentManager.getContent(0);
+ myContentManager.addContentManagerListener(new ContentManagerAdapter() {
@Override
- public void setTabsPlacement(int tabPlacement) {
- super.setTabsPlacement(UISettings.TABS_NONE);
- }
+ public void selectionChanged(ContentManagerEvent event) {
+ final VirtualFile file = event.getContent().getUserData(FILE_KEY);
+ if (event.getOperation() == ContentManagerEvent.ContentOperation.remove && file != null && file.equals(myModifiedFile)) {
+ close(file);
+ return;
+ }
- @Override
- protected boolean showEmptyText() {
- return false;
+ if (event.getOperation() != ContentManagerEvent.ContentOperation.add) return;
+
+ if (file != null) {
+ event.getContent().setComponent(PreviewPanel.this);//Actually we share the same component between contents
+ if (!file.equals(myWindow.getSelectedFile())) {
+ ApplicationManager.getApplication().invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ myManager.openFileWithProviders(file, false, myWindow);
+ }
+ });
+ }
+ }
}
- };
-
- myProject.getMessageBus().connect().subscribe(FileEditorManagerListener.Before.FILE_EDITOR_MANAGER, this);
+ });
+
+ myEditorsSplitters = new MyEditorsSplitters();
+
+ myProject.getMessageBus().connect().subscribe(FileEditorManagerListener.Before.FILE_EDITOR_MANAGER,
+ new FileEditorManagerListener.Before() {
+ @Override
+ public void beforeFileOpened(@NotNull FileEditorManager source,
+ @NotNull VirtualFile file) {
+ myAwaitingForOpen = file;
+ VirtualFile currentFile = getCurrentFile();
+ if (currentFile != null &&
+ currentFile.equals(myModifiedFile) &&
+ !currentFile.equals(file)) {
+ close(currentFile);
+ }
+ }
+
+ @Override
+ public void beforeFileClosed(@NotNull FileEditorManager source,
+ @NotNull VirtualFile file) {
+ checkStubContent();
+ }
+ });
myEditorsSplitters.createCurrentWindow();
-
myWindow = myEditorsSplitters.getCurrentWindow();
myWindow.setTabsPlacement(UISettings.TABS_NONE);
+ myLayout = new CardLayout();
+ setLayout(myLayout);
+ add(ContentType.Files.toString(), myEditorsSplitters);
+ //add(ContentType.Usages.toString(), myUsagesPreview);??? tree or editor ???
+ //add(ContentType.Diagrams.toString(), myDiagramPanel);
+ //add(ContentType.Documentation.toString(), myDocumentationPanel);//todo
+ myToolWindow.setTitleActions(new MoveToEditorTabsAction());
+ ArrayList<AnAction> myGearActions = new ArrayList<AnAction>();
+ for (ContentType contentType : ContentType.values()) {
+ myGearActions.add(new ContentTypeToggleAction(contentType));
+ }
+ myToolWindow.setAdditionalGearActions(new DefaultActionGroup("Preview", myGearActions));
+ myToolWindow.hide(null);
+ }
- setLayout(new GridLayout(1, 1));
- add(myEditorsSplitters);
-
- myToolWindow.setTitleActions(new MoveToEditorTabsAction(), new CloseFileAction());
-
- myInitialized = true;
+ @Nullable
+ private VirtualFile getCurrentFile() {
+ VirtualFile[] files = myWindow.getFiles();
+ return files.length == 1 ? files[0] : null;
}
- private void updateWindowTitle(VirtualFile file) {
- if (myToolWindow == null) return;
- if (file == null) {
- myToolWindow.setTitle(": (empty)");
- }
- else {
- myToolWindow.setTitle(": " +
- StringUtil.getShortened(EditorTabbedContainer.calcTabTitle(myProject, file),
- UISettings.getInstance().EDITOR_TAB_TITLE_LIMIT));
+ @NotNull
+ private Content addContent(VirtualFile file) {
+ myHistory.add(file);
+ while (myHistory.size() > HISTORY_LIMIT) {
+ myHistory.remove(0);
}
+ String title =
+ StringUtil.getShortened(EditorTabbedContainer.calcTabTitle(myProject, file), UISettings.getInstance().EDITOR_TAB_TITLE_LIMIT);
+
+ Content content = myContentManager.getFactory().createContent(this, title, false);
+ content.putUserData(ToolWindow.SHOW_CONTENT_ICON, Boolean.TRUE);
+ content.putUserData(FILE_KEY, file);
+ content.setIcon(file.getFileType().getIcon());
+ content.setPopupIcon(file.getFileType().getIcon());
+
+ myContentManager.addContent(content, 0);
+ checkStubContent();
+ return content;
}
- @Override
- public void beforeFileOpened(@NotNull FileEditorManager source, @NotNull VirtualFile file) {
- myAwaitingForOpen = file;
+ private void setSelected(VirtualFile file) {
+ Content content = getContent(file);
+ if (content == null) {
+ content = addContent(file);
+ }
+ myContentManager.setSelectedContent(content);
+ myContentManager.addContent(content, 0);
}
- @Override
- public void beforeFileClosed(@NotNull FileEditorManager source, @NotNull VirtualFile file) {
- if (file.equals(getCurrentFile())) {
- updateWindowTitle(null);
- Document document = FileDocumentManager.getInstance().getDocument(file);
- if (document != null) {
- document.removeDocumentListener(this);
+ @Nullable
+ private Content getContent(VirtualFile file) {
+ Content[] contents = myContentManager.getContents();
+ for (Content content : contents) {
+ if (file.equals(content.getUserData(FILE_KEY))) {
+ return content;
}
}
+ return null;
}
-
- @Override
- public void beforeDocumentChange(DocumentEvent event) {
-
- }
-
- @Override
- public void documentChanged(DocumentEvent event) {
- VirtualFile file = FileDocumentManager.getInstance().getFile(event.getDocument());
- if (file != null) {
- myModifiedFile = file;
+ private void checkStubContent() {
+ if (myContentManager.getContents().length == 0) {
+ myToolWindow.getComponent().putClientProperty(ToolWindowContentUi.HIDE_ID_LABEL, "false");
+ myStubContent.setComponent(this);
+ myContentManager.addContent(myStubContent);
+ ApplicationManager.getApplication().invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ if (myContentManager.getIndexOfContent(myStubContent) != -1) {
+ toggleToolWindow(false);
+ }
+ }
+ });
+ }
+ else if (myContentManager.getContents().length > 1) {
+ myToolWindow.getComponent().putClientProperty(ToolWindowContentUi.HIDE_ID_LABEL, "true");
+ myContentManager.removeContent(myStubContent, false);
}
}
- EditorWindow getWindow() {
- initToolWindowIfNeed();
- return myWindow;
+ private void close(@NotNull VirtualFile file) {
+ myHistory.remove(file);
+ if (ArrayUtil.find(myEditorsSplitters.getOpenFiles(), file) != -1) {
+ myEditorsSplitters.closeFile(file, false);
+ }
+ if (file.equals(myAwaitingForOpen)) {
+ myAwaitingForOpen = null;
+ }
+ if (file.equals(myModifiedFile)) {
+ myBlocked = true;
+ try {
+ myManager.openFileWithProviders(myModifiedFile, false, true);
+ }
+ finally {
+ myBlocked = false;
+ }
+ myModifiedFile = null;
+ }
+ Content content = getContent(file);
+ if (content != null) {
+ myContentManager.removeContent(content, false);
+ checkStubContent();
+ }
}
- @Nullable
- VirtualFile getCurrentFile() {
- VirtualFile[] files = myWindow.getFiles();
- return files.length == 1 ? files[0] : null;
+ private void toggleToolWindow(boolean activate) {
+ ToolWindow toolWindow = ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.PREVIEW);
+ if (toolWindow != null) {
+ if (activate) {
+ toolWindow.activate(null, false);
+ }
+ else {
+ toolWindow.hide(null);
+ }
+ }
}
private class MoveToEditorTabsAction extends AnAction {
+
public MoveToEditorTabsAction() {
- super(null, "Move to main tabs", AllIcons.Duplicates.SendToTheLeftGrayed);
+ super("Move to main tabs", "Move to main tabs", AllIcons.Duplicates.SendToTheLeftGrayed);
}
@Override
@@ -182,63 +296,96 @@ class PreviewPanel extends JPanel implements DocumentListener, FileEditorManager
return;
}
- myManager.openFileWithProviders(virtualFile, false, myManager.getCurrentWindow());
- closeCurrentFile();
+ EditorWindow window = myManager.getCurrentWindow();
+ if (window == null) { //main tab set is still not created, rare situation
+ myManager.getMainSplitters().createCurrentWindow();
+ window = myManager.getCurrentWindow();
+ }
+ myManager.openFileWithProviders(virtualFile, true, window);
+ close(virtualFile);
+ toggleToolWindow(false);
+ }
+ }
+
+ private class ContentTypeToggleAction extends ToggleAction {
+ private final ContentType myContentType;
+
+ ContentTypeToggleAction(ContentType contentType) {
+ super(contentType.toString());
+ myContentType = contentType;
}
@Override
- public void update(AnActionEvent e) {
- super.update(e);
- VirtualFile currentFile = getCurrentFile();
- e.getPresentation().setEnabled(currentFile != null);
- if (currentFile == null) return;
-
- if (isModified(currentFile)) {
- e.getPresentation().setIcon(AllIcons.Duplicates.SendToTheLeft);
- }
- else {
- e.getPresentation().setIcon(AllIcons.Duplicates.SendToTheLeftGrayed);
+ public boolean isSelected(AnActionEvent e) {
+ return myTypes.contains(myContentType);
+ }
+
+ @Override
+ public void setSelected(AnActionEvent e, boolean state) {
+ if (state) {
+ myTypes.add(myContentType);
+ } else {
+ myTypes.remove(myContentType);
}
}
}
- private boolean isModified(@NotNull VirtualFile file) {
- return file.equals(myModifiedFile);
- }
+ private class MyEditorsSplitters extends EditorsSplitters {
+ public MyEditorsSplitters() {
+ super(myManager, myDockManager, false);
+ }
- //returns last open file if it has "modified" status
- @Nullable
- VirtualFile closeCurrentFile() {
- VirtualFile virtualFile = getCurrentFile();
- if (virtualFile == null) return null;
- if (!myHistory.contains(virtualFile)) {
- myHistory.add(virtualFile);
- while (myHistory.size() > HISTORY_LIMIT) {
- myHistory.remove(0);
+ @Override
+ protected void afterFileOpen(VirtualFile file) {
+ if (file.equals(myAwaitingForOpen)) {
+ setSelected(file);
}
+ myAwaitingForOpen = null;
+ }
+
+ @Override
+ protected void afterFileClosed(VirtualFile file) {
+ close(file);
}
- myWindow.closeFile(virtualFile);
- this.revalidate();
- this.repaint();
- return isModified(virtualFile) ? virtualFile : null;
- }
- private class CloseFileAction extends AnAction {
- public CloseFileAction() {
- super(null, "Close", AllIcons.Actions.Close);
+ @Override
+ public void updateFileIcon(@NotNull VirtualFile file) {
+ EditorWithProviderComposite composite = myWindow.findFileComposite(file);
+ if (composite != null && composite.isModified()) {
+ myModifiedFile = file;
+ }
}
@Override
- public void actionPerformed(AnActionEvent e) {
- if (getCurrentFile() == null) return;
- closeCurrentFile();
- ToolWindowManager.getInstance(myProject).getToolWindow(ToolWindowId.PREVIEW).hide(null);
+ protected EditorWindow createEditorWindow() {
+ return new EditorWindow(this) {
+ @Override
+ protected void onBeforeSetEditor(VirtualFile file) {
+ VirtualFile currentFile = getCurrentFile();
+ if (currentFile != null && currentFile.equals(myModifiedFile)) {
+ myBlocked = true;
+ try {
+ myManager.openFileWithProviders(myModifiedFile, false, true);
+ }
+ finally {
+ myBlocked = false;
+ }
+ }
+ else {
+ toggleToolWindow(true);
+ }
+ }
+ };
+ }
+
+ @Override
+ public void setTabsPlacement(int tabPlacement) {
+ super.setTabsPlacement(UISettings.TABS_NONE);
}
@Override
- public void update(AnActionEvent e) {
- super.update(e);
- e.getPresentation().setEnabled(getCurrentFile() != null);
+ public boolean isPreview() {
+ return true;
}
}
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/http/HttpFileEditor.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/http/HttpFileEditor.java
index 00f333ef4002..a676023b6590 100644
--- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/http/HttpFileEditor.java
+++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/http/HttpFileEditor.java
@@ -20,6 +20,7 @@ import com.intellij.openapi.fileEditor.TextEditor;
import com.intellij.openapi.fileEditor.impl.BaseRemoteFileEditor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.impl.http.HttpVirtualFile;
+import com.intellij.openapi.vfs.impl.http.RemoteFileInfo;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -28,14 +29,16 @@ import javax.swing.*;
/**
* @author nik
*/
-public class HttpFileEditor extends BaseRemoteFileEditor {
+class HttpFileEditor extends BaseRemoteFileEditor {
private final RemoteFilePanel myPanel;
public HttpFileEditor(@NotNull Project project, @NotNull HttpVirtualFile virtualFile) {
super(project);
myPanel = new RemoteFilePanel(project, virtualFile, this);
- virtualFile.getFileInfo().download().doWhenDone(new Runnable() {
+ RemoteFileInfo fileInfo = virtualFile.getFileInfo();
+ assert fileInfo != null;
+ fileInfo.download().doWhenDone(new Runnable() {
@Override
public void run() {
ApplicationManager.getApplication().invokeLater(new Runnable() {
diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/http/HttpFileEditorProvider.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/http/HttpFileEditorProvider.java
index 17354c7f4855..22234ab66a74 100644
--- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/http/HttpFileEditorProvider.java
+++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/http/HttpFileEditorProvider.java
@@ -31,7 +31,7 @@ import org.jetbrains.annotations.NotNull;
/**
* @author nik
*/
-public class HttpFileEditorProvider implements FileEditorProvider, DumbAware {
+class HttpFileEditorProvider implements FileEditorProvider, DumbAware {
@Override
public boolean accept(@NotNull final Project project, @NotNull final VirtualFile file) {
return file instanceof HttpVirtualFile && !file.isDirectory();
diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/http/RemoteFilePanel.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/http/RemoteFilePanel.java
index 076d29e64bbe..4bd5549d85ff 100644
--- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/http/RemoteFilePanel.java
+++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/http/RemoteFilePanel.java
@@ -83,6 +83,7 @@ public class RemoteFilePanel {
final RemoteFileInfo remoteFileInfo = virtualFile.getFileInfo();
myDownloadingListener = new MyDownloadingListener();
+ assert remoteFileInfo != null;
remoteFileInfo.addDownloadingListener(myDownloadingListener);
myCancelButton.addActionListener(new ActionListener() {
@Override
diff --git a/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeManagerImpl.java
index 837626b53246..01d278302540 100644
--- a/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeManagerImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/fileTypes/impl/FileTypeManagerImpl.java
@@ -209,7 +209,7 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements NamedJDOME
}
@Override
- public Document writeScheme(@NotNull final AbstractFileType fileType) throws WriteExternalException {
+ public Element writeScheme(@NotNull final AbstractFileType fileType) throws WriteExternalException {
Element root = new Element(ELEMENT_FILETYPE);
writeHeader(root, fileType);
@@ -226,7 +226,7 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements NamedJDOME
writeExtensionsMap(map, fileType, false);
}
- return new Document(root);
+ return root;
}
@Override
@@ -263,7 +263,7 @@ public class FileTypeManagerImpl extends FileTypeManagerEx implements NamedJDOME
});
}
- private final TransferToPooledThreadQueue<Collection<VirtualFile>> reDetectQueue = new TransferToPooledThreadQueue<Collection<VirtualFile>>("File type re-detect", Condition.FALSE, -1, new Processor<Collection<VirtualFile>>() {
+ private final TransferToPooledThreadQueue<Collection<VirtualFile>> reDetectQueue = new TransferToPooledThreadQueue<Collection<VirtualFile>>("File type re-detect", Conditions.alwaysFalse(), -1, new Processor<Collection<VirtualFile>>() {
@Override
public boolean process(Collection<VirtualFile> files) {
reDetect(files);
diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeKeyEventDispatcher.java b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeKeyEventDispatcher.java
index 9a566e9915ef..72e24d626535 100644
--- a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeKeyEventDispatcher.java
+++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/IdeKeyEventDispatcher.java
@@ -55,6 +55,7 @@ import com.intellij.ui.ComponentWithMnemonics;
import com.intellij.ui.SimpleTextAttributes;
import com.intellij.ui.components.JBOptionButton;
import com.intellij.ui.popup.list.ListPopupImpl;
+import com.intellij.ui.speedSearch.SpeedSearchSupply;
import com.intellij.util.Alarm;
import com.intellij.util.Processor;
import com.intellij.util.containers.ContainerUtil;
@@ -140,6 +141,10 @@ public final class IdeKeyEventDispatcher implements Disposable {
return false;
}
+ if (isSpeedSearchEditing(e)) {
+ return false;
+ }
+
// http://www.jetbrains.net/jira/browse/IDEADEV-12372
if (e.getKeyCode() == KeyEvent.VK_CONTROL) {
if (e.getID() == KeyEvent.KEY_PRESSED) {
@@ -226,6 +231,18 @@ public final class IdeKeyEventDispatcher implements Disposable {
}
}
+ private static boolean isSpeedSearchEditing(KeyEvent e) {
+ int keyCode = e.getKeyCode();
+ if (keyCode == KeyEvent.VK_BACK_SPACE) {
+ Component owner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
+ if (owner instanceof JComponent) {
+ SpeedSearchSupply supply = SpeedSearchSupply.getSupply((JComponent)owner);
+ return supply != null && supply.isPopupActive();
+ }
+ }
+ return false;
+ }
+
/**
* @return <code>true</code> if and only if the <code>component</code> represents
* modal context.
diff --git a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/KeymapManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/KeymapManagerImpl.java
index 7c30e4faedec..177aa4babad1 100644
--- a/platform/platform-impl/src/com/intellij/openapi/keymap/impl/KeymapManagerImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/keymap/impl/KeymapManagerImpl.java
@@ -44,11 +44,7 @@ import java.util.*;
@State(
name = "KeymapManager",
- roamingType = RoamingType.PER_PLATFORM,
- storages = {
- @Storage(
- file = StoragePathMacros.APP_CONFIG + "/keymap.xml"
- )}
+ storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/keymap.xml", roamingType = RoamingType.PER_PLATFORM)}
)
public class KeymapManagerImpl extends KeymapManagerEx implements PersistentStateComponent<Element>, ExportableApplicationComponent {
private static final Logger LOG = Logger.getInstance("#com.intellij.keymap.KeymapManager");
@@ -75,8 +71,8 @@ public class KeymapManagerImpl extends KeymapManagerEx implements PersistentStat
}
@Override
- public Document writeScheme(@NotNull final KeymapImpl scheme) throws WriteExternalException {
- return new Document(scheme.writeExternal());
+ public Element writeScheme(@NotNull final KeymapImpl scheme) throws WriteExternalException {
+ return scheme.writeExternal();
}
@Override
diff --git a/platform/platform-impl/src/com/intellij/openapi/options/SchemesManagerFactoryImpl.java b/platform/platform-impl/src/com/intellij/openapi/options/SchemesManagerFactoryImpl.java
index 449a2180e3c1..c2f3b4d72b3e 100644
--- a/platform/platform-impl/src/com/intellij/openapi/options/SchemesManagerFactoryImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/options/SchemesManagerFactoryImpl.java
@@ -28,8 +28,6 @@ import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import java.io.File;
-import java.util.Collection;
-import java.util.Collections;
import java.util.List;
public class SchemesManagerFactoryImpl extends SchemesManagerFactory implements SettingsSavingComponent {
@@ -47,63 +45,10 @@ public class SchemesManagerFactoryImpl extends SchemesManagerFactory implements
}
IApplicationStore applicationStore = ((ApplicationImpl)application).getStateStore();
String baseDirPath = applicationStore.getStateStorageManager().expandMacros(fileSpec);
- if (baseDirPath != null) {
- StreamProvider provider = applicationStore.getStateStorageManager().getStreamProvider();
- SchemesManagerImpl<T, E> manager = new SchemesManagerImpl<T, E>(fileSpec, processor, roamingType, provider, new File(baseDirPath));
- myRegisteredManagers.add(manager);
- return manager;
- }
- else {
- return new AbstractSchemesManager<T, E>() {
- @Override
- @NotNull
- public Collection<E> loadSchemes() {
- return Collections.emptyList();
- }
-
- @Override
- @NotNull
- public Collection<SharedScheme<E>> loadSharedSchemes(final Collection<T> currentSchemeList) {
- return Collections.emptyList();
- }
-
- @Override
- public void exportScheme(@NotNull final E scheme, final String name, final String description) {
- }
-
- @Override
- public boolean isImportAvailable() {
- return false;
- }
-
- @Override
- public boolean isShared(final Scheme scheme) {
- return false;
- }
-
- @Override
- public void save() {
- }
-
- @Override
- protected void onSchemeDeleted(final Scheme toDelete) {
- }
-
- @Override
- protected void onSchemeAdded(final T scheme) {
- }
-
- @Override
- public boolean isExportAvailable() {
- return false;
- }
-
- @Override
- public File getRootDirectory() {
- return null;
- }
- };
- }
+ StreamProvider provider = applicationStore.getStateStorageManager().getStreamProvider();
+ SchemesManagerImpl<T, E> manager = new SchemesManagerImpl<T, E>(fileSpec, processor, roamingType, provider, new File(baseDirPath));
+ myRegisteredManagers.add(manager);
+ return manager;
}
@Override
diff --git a/platform/platform-impl/src/com/intellij/openapi/options/SchemesManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/options/SchemesManagerImpl.java
index 4ff3ebba1ee9..6142b696ff24 100644
--- a/platform/platform-impl/src/com/intellij/openapi/options/SchemesManagerImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/options/SchemesManagerImpl.java
@@ -43,6 +43,7 @@ import gnu.trove.THashSet;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
+import org.jdom.Parent;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -79,7 +80,7 @@ public class SchemesManagerImpl<T extends Scheme, E extends ExternalizableScheme
private boolean myListenerAdded = false;
private Alarm myRefreshAlarm;
-
+
private String mySchemeExtension = DEFAULT_EXT;
private boolean myUpgradeExtension = false;
@@ -535,7 +536,7 @@ public class SchemesManagerImpl<T extends Scheme, E extends ExternalizableScheme
@Nullable
private static Document loadGlobalScheme(final String schemePath) throws IOException {
StreamProvider provider = getProvider();
- return provider != null && provider.isEnabled() ? StorageUtil.loadDocument(provider.loadContent(schemePath, RoamingType.GLOBAL)) : null;
+ return provider != null && provider.isEnabled() ? StorageUtil.loadDocument(provider.loadContent(schemePath, getRoamingType(provider))) : null;
}
private void saveFileName(String fileName, final E schemeKey) {
@@ -548,12 +549,12 @@ public class SchemesManagerImpl<T extends Scheme, E extends ExternalizableScheme
schemeKey.getExternalInfo().setCurrentFileName(fileName);
}
- private static long computeHashValue(final Document document) {
- return JDOMUtil.getTreeHash(document);
+ private static long computeHashValue(Parent element) {
+ return JDOMUtil.getTreeHash(element instanceof Element ? (Element)element : ((Document)element).getRootElement());
}
@Nullable
- private Document writeSchemeToDocument(final E scheme) throws WriteExternalException {
+ private org.jdom.Parent writeSchemeToDocument(@NotNull E scheme) throws WriteExternalException {
if (isShared(scheme)) {
String originalPath = scheme.getExternalInfo().getOriginalPath();
if (originalPath != null) {
@@ -562,11 +563,10 @@ public class SchemesManagerImpl<T extends Scheme, E extends ExternalizableScheme
root.setAttribute(ORIGINAL_SCHEME_PATH, originalPath);
Element localCopy = new Element(SCHEME_LOCAL_COPY);
- localCopy.addContent(myProcessor.writeScheme(scheme).getRootElement().clone());
+ localCopy.addContent(getClone(myProcessor.writeScheme(scheme)));
root.addContent(localCopy);
-
- return new Document(root);
+ return root;
}
else {
return null;
@@ -577,8 +577,12 @@ public class SchemesManagerImpl<T extends Scheme, E extends ExternalizableScheme
}
}
- public void updateConfigFilesFromStreamProviders() {
+ @NotNull
+ private static Element getClone(@NotNull Parent result) {
+ return (result instanceof Element ? (Element)result : ((Document)result).getRootElement()).clone();
+ }
+ public void updateConfigFilesFromStreamProviders() {
}
private static class SharedSchemeData {
@@ -605,9 +609,9 @@ public class SchemesManagerImpl<T extends Scheme, E extends ExternalizableScheme
Collection<String> names = new THashSet<String>(getAllSchemeNames(currentSchemeList));
Map<String, SharedScheme<E>> result = new THashMap<String, SharedScheme<E>>();
- for (String subPath : provider.listSubFiles(myFileSpec, RoamingType.GLOBAL)) {
+ for (String subPath : provider.listSubFiles(myFileSpec, getRoamingType(provider))) {
try {
- final Document subDocument = StorageUtil.loadDocument(provider.loadContent(getFileFullPath(subPath), RoamingType.GLOBAL));
+ final Document subDocument = StorageUtil.loadDocument(provider.loadContent(getFileFullPath(subPath), getRoamingType(provider)));
if (subDocument != null) {
SharedSchemeData original = unwrap(subDocument);
final E scheme = myProcessor.readScheme(original.original);
@@ -669,6 +673,7 @@ public class SchemesManagerImpl<T extends Scheme, E extends ExternalizableScheme
return myFileSpec + '/' + subPath;
}
+ @SuppressWarnings("deprecation")
@Override
public void exportScheme(@NotNull final E scheme, final String name, final String description) throws WriteExternalException, IOException {
StreamProvider provider = getProvider();
@@ -676,31 +681,39 @@ public class SchemesManagerImpl<T extends Scheme, E extends ExternalizableScheme
return;
}
- Document document = myProcessor.writeScheme(scheme);
+ Parent document = myProcessor.writeScheme(scheme);
if (document != null) {
String fileSpec = getFileFullPath(UniqueFileNamesProvider.convertName(scheme.getName())) + mySchemeExtension;
- if (!provider.isApplicable(fileSpec, RoamingType.GLOBAL)) {
+ if (!provider.isApplicable(fileSpec, getRoamingType(provider))) {
return;
}
- Document wrapped = wrap(document, name, description);
+ Element wrapped = wrap(document, name, description);
if (provider instanceof CurrentUserHolder) {
wrapped = wrapped.clone();
String userName = ((CurrentUserHolder)provider).getCurrentUserName();
if (userName != null) {
- wrapped.getRootElement().setAttribute(USER, userName);
+ wrapped.setAttribute(USER, userName);
}
}
- StorageUtil.doSendContent(provider, fileSpec, wrapped, RoamingType.GLOBAL, false);
+ StorageUtil.doSendContent(provider, fileSpec, wrapped, getRoamingType(provider), false);
}
}
- private static Document wrap(@NotNull Document original, @NotNull String name, @NotNull String description) {
+ @SuppressWarnings("deprecation")
+ @NotNull
+ private static RoamingType getRoamingType(@NotNull StreamProvider provider) {
+ // for deprecated old stream we use GLOBAL as before to preserve backward compatibility
+ return provider instanceof CurrentUserHolder ? RoamingType.GLOBAL : RoamingType.PER_USER;
+ }
+
+ @NotNull
+ private static Element wrap(@NotNull Parent original, @NotNull String name, @NotNull String description) {
Element sharedElement = new Element(SHARED_SCHEME_ORIGINAL);
sharedElement.setAttribute(NAME, name);
sharedElement.setAttribute(DESCRIPTION, description);
- sharedElement.addContent(original.getRootElement().clone());
- return new Document(sharedElement);
+ sharedElement.addContent(getClone(original));
+ return sharedElement;
}
@Override
@@ -799,7 +812,7 @@ public class SchemesManagerImpl<T extends Scheme, E extends ExternalizableScheme
deleteServerFiles(DELETED_XML);
}
else if (myProvider != null && myProvider.isEnabled()) {
- StorageUtil.sendContent(myProvider, getFileFullPath(DELETED_XML), createDeletedDocument(), myRoamingType, true);
+ StorageUtil.sendContent(myProvider, getFileFullPath(DELETED_XML), createDeletedElement(), myRoamingType, true);
}
}
finally {
@@ -850,11 +863,11 @@ public class SchemesManagerImpl<T extends Scheme, E extends ExternalizableScheme
final String fileName = getFileNameForScheme(fileNameProvider, eScheme);
try {
- final Document document = writeSchemeToDocument(eScheme);
- if (document != null) {
- long newHash = computeHashValue(document);
+ final Parent element = writeSchemeToDocument(eScheme);
+ if (element != null) {
+ long newHash = computeHashValue(element);
Long oldHash = eScheme.getExternalInfo().getHash();
- saveIfNeeded(eScheme, fileName, document, newHash, oldHash);
+ saveIfNeeded(eScheme, fileName, element, newHash, oldHash);
}
}
catch (final IOException e) {
@@ -889,18 +902,18 @@ public class SchemesManagerImpl<T extends Scheme, E extends ExternalizableScheme
return fileName + mySchemeExtension;
}
- private void saveIfNeeded(E schemeKey, String fileName, Document document, long newHash, Long oldHash) throws IOException {
+ private void saveIfNeeded(E schemeKey, String fileName, Parent element, long newHash, Long oldHash) throws IOException {
if (oldHash == null || newHash != oldHash.longValue() || myVFSBaseDir.findChild(fileName) == null) {
- ensureFileText(fileName, StorageUtil.documentToBytes(document, true).toByteArray());
+ ensureFileText(fileName, StorageUtil.elementToBytes(element, true).toByteArray());
schemeKey.getExternalInfo().setHash(newHash);
saveFileName(fileName, schemeKey);
- saveOnServer(fileName, document);
+ saveOnServer(fileName, element);
}
}
- private void saveOnServer(final String fileName, final Document document) {
+ private void saveOnServer(final String fileName, @NotNull Parent element) {
if (myProvider != null && myProvider.isEnabled()) {
- StorageUtil.sendContent(myProvider, getFileFullPath(fileName), document, myRoamingType, true);
+ StorageUtil.sendContent(myProvider, getFileFullPath(fileName), element, myRoamingType, true);
}
}
@@ -925,16 +938,15 @@ public class SchemesManagerImpl<T extends Scheme, E extends ExternalizableScheme
}
}
- private Document createDeletedDocument() {
+ @NotNull
+ private Element createDeletedElement() {
Element root = new Element("deleted-schemes");
- Document result = new Document(root);
for (String deletedName : myDeletedNames) {
Element child = new Element("scheme");
root.addContent(child);
child.setAttribute("name", deletedName);
}
-
- return result;
+ return root;
}
@Override
diff --git a/platform/platform-impl/src/com/intellij/openapi/options/ex/ConfigurableExtensionPointUtil.java b/platform/platform-impl/src/com/intellij/openapi/options/ex/ConfigurableExtensionPointUtil.java
index 429a55b2b809..ca72bf30c541 100644
--- a/platform/platform-impl/src/com/intellij/openapi/options/ex/ConfigurableExtensionPointUtil.java
+++ b/platform/platform-impl/src/com/intellij/openapi/options/ex/ConfigurableExtensionPointUtil.java
@@ -48,7 +48,7 @@ public class ConfigurableExtensionPointUtil {
}
}
- final Map<String, ConfigurableWrapper> idToConfigurable = new HashMap<String, ConfigurableWrapper>();
+ final Map<String, ConfigurableWrapper> idToConfigurable = new LinkedHashMap<String, ConfigurableWrapper>();
for (ConfigurableEP<Configurable> ep : extensions) {
final Configurable configurable = ConfigurableWrapper.wrapConfigurable(ep);
if (isSuppressed(configurable, filter)) continue;
@@ -75,16 +75,13 @@ public class ConfigurableExtensionPointUtil {
}
}
}
- //leave only roots (i.e. configurables without parents)
- for (final Iterator<String> iterator = idToConfigurable.keySet().iterator(); iterator.hasNext(); ) {
- final String key = iterator.next();
- final ConfigurableWrapper wrapper = idToConfigurable.get(key);
- final String parentId = wrapper.getParentId();
- if (parentId != null && idToConfigurable.containsKey(parentId)) {
- iterator.remove(); // remove only processed parents
+ // add roots only (i.e. configurables without parents)
+ for (ConfigurableWrapper wrapper : idToConfigurable.values()) {
+ String parentId = wrapper.getParentId();
+ if (parentId == null || !idToConfigurable.containsKey(parentId)) {
+ result.add(wrapper);
}
}
- ContainerUtil.addAll(result, idToConfigurable.values());
return result;
}
@@ -164,7 +161,7 @@ public class ConfigurableExtensionPointUtil {
@NotNull
private static <T extends Configurable> T findConfigurable(ConfigurableEP<Configurable>[] extensions, Class<T> configurableClass) {
for (ConfigurableEP<Configurable> extension : extensions) {
- if (extension.providerClass != null || extension.instanceClass != null || extension.implementationClass != null) {
+ if (extension.canCreateConfigurable()) {
final Configurable configurable = extension.createConfigurable();
if (configurableClass.isInstance(configurable)) {
return configurableClass.cast(configurable);
diff --git a/platform/platform-impl/src/com/intellij/openapi/options/ex/ConfigurableVisitor.java b/platform/platform-impl/src/com/intellij/openapi/options/ex/ConfigurableVisitor.java
new file mode 100644
index 000000000000..7d820a255fb3
--- /dev/null
+++ b/platform/platform-impl/src/com/intellij/openapi/options/ex/ConfigurableVisitor.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.openapi.options.ex;
+
+import com.intellij.openapi.options.Configurable;
+import com.intellij.openapi.options.ConfigurableGroup;
+import com.intellij.openapi.options.SearchableConfigurable;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Sergey.Malenkov
+ */
+public abstract class ConfigurableVisitor {
+ public static final ConfigurableVisitor ALL = new ConfigurableVisitor() {
+ @Override
+ protected boolean accept(Configurable configurable) {
+ return true;
+ }
+ };
+
+ protected abstract boolean accept(Configurable configurable);
+
+ public final Configurable find(@NotNull ConfigurableGroup... groups) {
+ for (ConfigurableGroup group : groups) {
+ Configurable result = find(group.getConfigurables());
+ if (result != null) {
+ return result;
+ }
+ }
+ return null;
+ }
+
+ public final Configurable find(@NotNull Configurable... configurables) {
+ for (Configurable configurable : configurables) {
+ if (accept(configurable)) {
+ return configurable;
+ }
+ }
+ for (Configurable configurable : configurables) {
+ if (configurable instanceof Configurable.Composite) {
+ Configurable.Composite composite = (Configurable.Composite)configurable;
+ Configurable result = find(composite.getConfigurables());
+ if (result != null) {
+ return result;
+ }
+ }
+ }
+ return null;
+ }
+
+ public final List<Configurable> findAll(@NotNull ConfigurableGroup... groups) {
+ List<Configurable> list = new ArrayList<Configurable>();
+ for (ConfigurableGroup group : groups) {
+ add(list, group.getConfigurables());
+ }
+ return list;
+ }
+
+ public final List<Configurable> findAll(@NotNull Configurable... configurables) {
+ List<Configurable> list = new ArrayList<Configurable>();
+ add(list, configurables);
+ return list;
+ }
+
+ private void add(List<Configurable> list, Configurable... configurables) {
+ for (Configurable configurable : configurables) {
+ if (accept(configurable)) {
+ list.add(configurable);
+ }
+ if (configurable instanceof Configurable.Composite) {
+ Configurable.Composite composite = (Configurable.Composite)configurable;
+ add(list, composite.getConfigurables());
+ }
+ }
+ }
+
+ public static final class ByID extends ConfigurableVisitor {
+ private final String myID;
+
+ public ByID(@NotNull String id) {
+ myID = id;
+ }
+
+ @Override
+ protected boolean accept(Configurable configurable) {
+ return myID.equals(getID(configurable));
+ }
+
+ public static String getID(Configurable configurable) {
+ return configurable instanceof SearchableConfigurable
+ ? ((SearchableConfigurable)configurable).getId()
+ : configurable.getClass().getName();
+ }
+ }
+
+ public static final class ByName extends ConfigurableVisitor {
+ private final String myName;
+
+ public ByName(@NotNull String name) {
+ myName = name;
+ }
+
+ @Override
+ protected boolean accept(Configurable configurable) {
+ return myName.equals(configurable.getDisplayName());
+ }
+ }
+
+ public static final class ByType extends ConfigurableVisitor {
+ private final Class<? extends Configurable> myType;
+
+ public ByType(@NotNull Class<? extends Configurable> type) {
+ myType = type;
+ }
+
+ @Override
+ protected boolean accept(Configurable configurable) {
+ if (myType.isInstance(configurable)) {
+ return true;
+ }
+ if (configurable instanceof ConfigurableWrapper) {
+ ConfigurableWrapper wrapper = (ConfigurableWrapper)configurable;
+ return myType.isInstance(wrapper.getConfigurable());
+ }
+ return false;
+ }
+ }
+}
diff --git a/platform/platform-impl/src/com/intellij/openapi/options/ex/ConfigurableWrapper.java b/platform/platform-impl/src/com/intellij/openapi/options/ex/ConfigurableWrapper.java
index 3b67a3478368..dd8169e159a7 100644
--- a/platform/platform-impl/src/com/intellij/openapi/options/ex/ConfigurableWrapper.java
+++ b/platform/platform-impl/src/com/intellij/openapi/options/ex/ConfigurableWrapper.java
@@ -47,6 +47,9 @@ public class ConfigurableWrapper implements SearchableConfigurable {
@Nullable
public static <T extends UnnamedConfigurable> T wrapConfigurable(ConfigurableEP<T> ep) {
+ if (!ep.canCreateConfigurable()) {
+ return null;
+ }
if (ep.displayName != null || ep.key != null || ep.groupId != null) {
T configurable = null;
if (ep.providerClass != null) {
@@ -55,9 +58,9 @@ public class ConfigurableWrapper implements SearchableConfigurable {
return null; // it is allowed to return null from provider
}
}
- return ep.children != null || ep.childrenEPName != null || ep.dynamic
- ? (T)new CompositeWrapper(ep, configurable)
- : (T)new ConfigurableWrapper(ep, configurable);
+ return !ep.dynamic && ep.children == null && ep.childrenEPName == null
+ ? (T)new ConfigurableWrapper(ep, configurable)
+ : (T)new CompositeWrapper(ep, configurable);
}
else {
return ep.createConfigurable();
@@ -157,7 +160,16 @@ public class ConfigurableWrapper implements SearchableConfigurable {
@NotNull
@Override
public String getId() {
- return myEp.id == null ? myEp.instanceClass == null ? myEp.providerClass : myEp.instanceClass : myEp.id;
+ if (myEp.id != null) {
+ return myEp.id;
+ }
+ UnnamedConfigurable configurable = getConfigurable();
+ if (configurable instanceof SearchableConfigurable) {
+ return ((SearchableConfigurable)configurable).getId();
+ }
+ return myEp.instanceClass != null
+ ? myEp.instanceClass
+ : myEp.providerClass;
}
@NotNull
diff --git a/platform/platform-impl/src/com/intellij/openapi/options/ex/MixedConfigurableGroup.java b/platform/platform-impl/src/com/intellij/openapi/options/ex/MixedConfigurableGroup.java
deleted file mode 100644
index e3404ec017cd..000000000000
--- a/platform/platform-impl/src/com/intellij/openapi/options/ex/MixedConfigurableGroup.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright 2000-2014 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.intellij.openapi.options.ex;
-
-import com.intellij.openapi.options.Configurable;
-import com.intellij.openapi.options.ConfigurableGroup;
-import com.intellij.openapi.options.ConfigurationException;
-import com.intellij.openapi.options.OptionsBundle;
-import com.intellij.openapi.options.SearchableConfigurable;
-import com.intellij.openapi.util.text.StringUtil;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map.Entry;
-import javax.swing.JComponent;
-
-public final class MixedConfigurableGroup implements SearchableConfigurable, ConfigurableGroup {
- private final String myGroupId;
- private Configurable[] myConfigurables;
-
- private MixedConfigurableGroup(String groupId, ArrayList<Configurable> configurables) {
- myGroupId = groupId;
- myConfigurables = (configurables != null)
- ? configurables.toArray(new Configurable[configurables.size()])
- : new Configurable[0];
- Arrays.sort(myConfigurables, COMPARATOR);
- }
-
- private MixedConfigurableGroup(String groupId, HashMap<String, ArrayList<Configurable>> configurables) {
- this(groupId, configurables.remove(groupId));
- }
-
- @Override
- public JComponent createComponent() {
- return null;
- }
-
- @Override
- public boolean isModified() {
- return false;
- }
-
- @Override
- public void apply() throws ConfigurationException {
- }
-
- @Override
- public void reset() {
- }
-
- @Override
- public void disposeUIResources() {
- myConfigurables = null;
- }
-
- @Override
- public Runnable enableSearch(String option) {
- return null;
- }
-
- @NotNull
- @Override
- public String getId() {
- return "configurable.group." + myGroupId;
- }
-
- @Override
- public String getHelpTopic() {
- return "configurable.group." + myGroupId + ".help.topic";
- }
-
- @Override
- public String getDisplayName() {
- return OptionsBundle.message("configurable.group." + myGroupId + ".settings.display.name");
- }
-
- @Override
- public String getShortName() {
- return getDisplayName();
- }
-
- @Override
- public Configurable[] getConfigurables() {
- return myConfigurables;
- }
-
- public static ConfigurableGroup[] getGroups(Configurable... configurables) {
- HashMap<String, ArrayList<Configurable>> map = new HashMap<String, ArrayList<Configurable>>();
- for (Configurable configurable : configurables) {
- String groupId = null;
- if (configurable instanceof ConfigurableWrapper) {
- groupId = ((ConfigurableWrapper)configurable).getExtensionPoint().groupId;
- }
- ArrayList<Configurable> list = map.get(groupId);
- if (list == null) {
- map.put(groupId, list = new ArrayList<Configurable>());
- }
- list.add(configurable);
- }
- ArrayList<Configurable> buildList = map.get("build");
- if (buildList != null) {
- NodeConfigurable buildTools = new NodeConfigurable("build.tools", 1000);
- buildTools.add(find("MavenSettings", buildList.iterator()));
- buildTools.add(find("reference.settingsdialog.project.gradle", buildList.iterator()));
- buildTools.add(find("reference.settingsdialog.project.gant", buildList.iterator()));
- if (buildTools.getConfigurables() != null) {
- buildList.add(0, buildTools);
- }
- }
- ArrayList<ConfigurableGroup> groups = new ArrayList<ConfigurableGroup>(map.size());
- groups.add(new MixedConfigurableGroup("appearance", map));
- groups.add(new MixedConfigurableGroup("editor", map));
- groups.add(new MixedConfigurableGroup("project", map));
- groups.add(new MixedConfigurableGroup("build", map));
- groups.add(new MixedConfigurableGroup("language", map));
- groups.add(new MixedConfigurableGroup("tools", map));
- ConfigurableGroup other = new MixedConfigurableGroup(null, map);
- for(Entry<String, ArrayList<Configurable>>entry: map.entrySet()){
- groups.add(new MixedConfigurableGroup(entry.getKey(), entry.getValue()));
- }
- groups.add(other);
- return groups.toArray(new ConfigurableGroup[groups.size()]);
- }
-
- private static Configurable find(String id, Iterator<Configurable> iterator) {
- while (iterator.hasNext()) {
- Configurable configurable = iterator.next();
- if (configurable instanceof SearchableConfigurable) {
- SearchableConfigurable sc = (SearchableConfigurable)configurable;
- if (id.equals(sc.getId())) {
- iterator.remove();
- return configurable;
- }
- }
- }
- return null;
- }
-
- public static int getGroupWeight(Configurable configurable) {
- if (configurable instanceof NodeConfigurable) {
- return ((NodeConfigurable)configurable).getGroupWeight();
- }
- if (configurable instanceof ConfigurableWrapper) {
- return ((ConfigurableWrapper)configurable).getExtensionPoint().groupWeight;
- }
- return 0;
- }
-
- private static final Comparator<Configurable> COMPARATOR = new Comparator<Configurable>() {
- @Override
- public int compare(Configurable configurable1, Configurable configurable2) {
- if (configurable1 == null || configurable2 == null) {
- return configurable2 != null ? -1 : configurable1 != null ? 1 : 0;
- }
- int weight1 = getGroupWeight(configurable1);
- int weight2 = getGroupWeight(configurable2);
- return weight1 > weight2 ? -1 : weight1 < weight2 ? 1 : StringUtil.naturalCompare(configurable1.getDisplayName(),
- configurable2.getDisplayName());
- }
- };
-}
diff --git a/platform/platform-impl/src/com/intellij/openapi/options/ex/NodeConfigurable.java b/platform/platform-impl/src/com/intellij/openapi/options/ex/NodeConfigurable.java
deleted file mode 100644
index 609943d02943..000000000000
--- a/platform/platform-impl/src/com/intellij/openapi/options/ex/NodeConfigurable.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright 2000-2014 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.intellij.openapi.options.ex;
-
-import com.intellij.openapi.options.Configurable;
-import com.intellij.openapi.options.OptionsBundle;
-import com.intellij.openapi.options.SearchableConfigurable;
-import org.jetbrains.annotations.Nls;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.ArrayList;
-
-public final class NodeConfigurable extends SearchableConfigurable.Parent.Abstract {
- private final ArrayList<Configurable> myConfigurables = new ArrayList<Configurable>();
- private final String myId;
- private final int myWeight;
-
- public NodeConfigurable(@NotNull String id, int weight) {
- myId = id;
- myWeight = weight;
- }
-
- public int getGroupWeight() {
- return myWeight;
- }
-
- public void add(Configurable configurable) {
- if (configurable != null) {
- super.disposeUIResources();
- myConfigurables.add(configurable);
- }
- }
-
- @Override
- public void disposeUIResources() {
- super.disposeUIResources();
- myConfigurables.clear();
- }
-
- @NotNull
- @Override
- public String getId() {
- return "node.configurable." + myId;
- }
-
- @Nullable
- @Override
- public String getHelpTopic() {
- return "node.configurable." + myId + ".help.topic";
- }
-
- @Nls
- @Override
- public String getDisplayName() {
- return OptionsBundle.message("node.configurable." + myId + ".display.name");
- }
-
- @Override
- protected Configurable[] buildConfigurables() {
- int size = myConfigurables.size();
- return size == 0 ? null : myConfigurables.toArray(new Configurable[size]);
- }
-}
diff --git a/platform/platform-impl/src/com/intellij/openapi/options/ex/SortedConfigurableGroup.java b/platform/platform-impl/src/com/intellij/openapi/options/ex/SortedConfigurableGroup.java
new file mode 100644
index 000000000000..3d87b7679359
--- /dev/null
+++ b/platform/platform-impl/src/com/intellij/openapi/options/ex/SortedConfigurableGroup.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.openapi.options.ex;
+
+import com.intellij.openapi.options.Configurable;
+import com.intellij.openapi.options.ConfigurableGroup;
+import com.intellij.openapi.options.OptionsBundle;
+import com.intellij.openapi.options.SearchableConfigurable;
+import com.intellij.openapi.util.text.StringUtil;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+
+/**
+ * @author Sergey.Malenkov
+ */
+public final class SortedConfigurableGroup
+ extends SearchableConfigurable.Parent.Abstract
+ implements SearchableConfigurable, ConfigurableGroup, Configurable.NoScroll {
+
+ public static ConfigurableGroup getGroup(Configurable... configurables) {
+ SortedConfigurableGroup root = new SortedConfigurableGroup("root");
+ HashMap<String, SortedConfigurableGroup> map = new HashMap<String, SortedConfigurableGroup>();
+ map.put("root", root);
+ for (Configurable configurable : configurables) {
+ int weight = 0;
+ String groupId = null;
+ if (configurable instanceof ConfigurableWrapper) {
+ ConfigurableWrapper wrapper = (ConfigurableWrapper)configurable;
+ weight = wrapper.getExtensionPoint().groupWeight;
+ groupId = wrapper.getExtensionPoint().groupId;
+ }
+ SortedConfigurableGroup composite = map.get(groupId);
+ if (composite == null) {
+ composite = new SortedConfigurableGroup(groupId);
+ map.put(groupId, composite);
+ }
+ composite.add(weight, configurable);
+ }
+ // process supported groups
+ root.add(60, map.remove("appearance"));
+ root.add(50, map.remove("editor"));
+ root.add(40, map.remove("project"));
+ SortedConfigurableGroup build = map.remove("build");
+ if (build == null) {
+ build = map.remove("build.tools");
+ }
+ else {
+ build.add(1000, map.remove("build.tools"));
+ }
+ root.add(30, build);
+ root.add(20, map.remove("language"));
+ root.add(10, map.remove("tools"));
+ root.add(-10, map.remove(null));
+ // process unsupported groups
+ if (1 < map.size()) {
+ for (SortedConfigurableGroup group : map.values()) {
+ if (root != group) {
+ group.myDisplayName = "Category: " + group.myGroupId;
+ root.add(0, group);
+ }
+ }
+ }
+ return root;
+ }
+
+ private final ArrayList<WeightConfigurable> myList = new ArrayList<WeightConfigurable>();
+ private final String myGroupId;
+ private String myDisplayName;
+
+ private SortedConfigurableGroup(String groupId) {
+ myGroupId = groupId;
+ }
+
+ public SortedConfigurableGroup(Configurable... configurables) {
+ myGroupId = "root";
+ // create groups from configurations
+ HashMap<String, SortedConfigurableGroup> map = new HashMap<String, SortedConfigurableGroup>();
+ map.put(myGroupId, this);
+ for (Configurable configurable : configurables) {
+ int weight = 0;
+ String groupId = null;
+ if (configurable instanceof ConfigurableWrapper) {
+ ConfigurableWrapper wrapper = (ConfigurableWrapper)configurable;
+ weight = wrapper.getExtensionPoint().groupWeight;
+ groupId = wrapper.getExtensionPoint().groupId;
+ }
+ SortedConfigurableGroup composite = map.get(groupId);
+ if (composite == null) {
+ composite = new SortedConfigurableGroup(groupId);
+ map.put(groupId, composite);
+ }
+ composite.add(weight, configurable);
+ }
+ // process supported groups
+ add(60, map.remove("appearance"));
+ add(50, map.remove("editor"));
+ add(40, map.remove("project"));
+ SortedConfigurableGroup build = map.remove("build");
+ if (build == null) {
+ build = map.remove("build.tools");
+ }
+ else {
+ build.add(1000, map.remove("build.tools"));
+ }
+ add(30, build);
+ add(20, map.remove("language"));
+ add(10, map.remove("tools"));
+ add(-10, map.remove(null));
+ // process unsupported groups
+ if (1 < map.size()) {
+ for (SortedConfigurableGroup group : map.values()) {
+ if (this != group) {
+ group.myDisplayName = "Category: " + group.myGroupId;
+ add(0, group);
+ }
+ }
+ }
+ }
+
+ private void add(int weight, Configurable configurable) {
+ if (configurable != null) {
+ myList.add(new WeightConfigurable(configurable, weight));
+ }
+ }
+
+ @Override
+ protected Configurable[] buildConfigurables() {
+ Collections.sort(myList);
+ int length = myList.size();
+ Configurable[] result = new Configurable[length];
+ for (int i = 0; i < result.length; i++) {
+ result[i] = myList.get(i).myConfigurable;
+ }
+ myList.clear();
+ return result;
+ }
+
+ @NotNull
+ @Override
+ public String getId() {
+ return "configurable.group." + myGroupId;
+ }
+
+ @Nullable
+ @Override
+ public String getHelpTopic() {
+ return "configurable.group." + myGroupId + ".help.topic";
+ }
+
+ @Nls
+ @Override
+ public String getDisplayName() {
+ return myDisplayName != null ? myDisplayName : OptionsBundle.message("configurable.group." + myGroupId + ".settings.display.name");
+ }
+
+ @Override
+ public String getShortName() {
+ return getDisplayName();
+ }
+
+ private static final class WeightConfigurable implements Comparable<WeightConfigurable> {
+ private final Configurable myConfigurable;
+ private final int myWeight;
+
+ private WeightConfigurable(@NotNull Configurable configurable, int weight) {
+ myConfigurable = configurable;
+ myWeight = weight;
+ }
+
+ @Override
+ public int compareTo(@NotNull WeightConfigurable pair) {
+ return myWeight > pair.myWeight ? -1 :
+ myWeight < pair.myWeight ? 1 :
+ StringUtil.naturalCompare(myConfigurable.getDisplayName(), pair.myConfigurable.getDisplayName());
+ }
+ }
+}
diff --git a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/IdeSettingsDialog.java b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/IdeSettingsDialog.java
index c38bf6ff2033..a995ea372d99 100644
--- a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/IdeSettingsDialog.java
+++ b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/IdeSettingsDialog.java
@@ -16,7 +16,6 @@
package com.intellij.openapi.options.newEditor;
import com.intellij.CommonBundle;
-import com.intellij.ide.ui.search.SearchUtil;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.actionSystem.DataProvider;
import com.intellij.openapi.application.ApplicationManager;
@@ -25,6 +24,7 @@ import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurableGroup;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.SearchableConfigurable;
+import com.intellij.openapi.options.ex.ConfigurableVisitor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.util.ActionCallback;
@@ -45,7 +45,6 @@ import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.Collection;
-import java.util.List;
import java.util.Map;
/**
@@ -114,7 +113,7 @@ public class IdeSettingsDialog extends DialogWrapper implements DataProvider {
@Nullable
private static Configurable getPreselectedByDisplayName(final ConfigurableGroup[] groups, final String preselectedConfigurableDisplayName,
final Project project) {
- Configurable result = findPreselectedByDisplayName(preselectedConfigurableDisplayName, groups);
+ Configurable result = new ConfigurableVisitor.ByName(preselectedConfigurableDisplayName).find(groups);
return result == null ? findLastSavedConfigurable(groups, project) : result;
}
@@ -230,44 +229,7 @@ public class IdeSettingsDialog extends DialogWrapper implements DataProvider {
final String id = PropertiesComponent.getInstance(project).getValue(LAST_SELECTED_CONFIGURABLE);
if (id == null) return null;
- return findConfigurableInGroups(id, groups);
- }
-
- @Nullable
- private static Configurable findConfigurableInGroups(String id, Configurable.Composite... groups) {
- // avoid unnecessary group expand: check top-level configurables in all groups before looking at children
- for (Configurable.Composite group : groups) {
- final Configurable[] configurables = group.getConfigurables();
- for (Configurable c : configurables) {
- if (c instanceof SearchableConfigurable && id.equals(((SearchableConfigurable)c).getId())) {
- return c;
- }
- else if (id.equals(c.getClass().getName())) {
- return c;
- }
- }
- }
- for (Configurable.Composite group : groups) {
- final Configurable[] configurables = group.getConfigurables();
- for (Configurable c : configurables) {
- if (c instanceof Configurable.Composite) {
- Configurable result = findConfigurableInGroups(id, (Configurable.Composite)c);
- if (result != null) {
- return result;
- }
- }
- }
- }
- return null;
- }
-
- @Nullable
- private static Configurable findPreselectedByDisplayName(final String preselectedConfigurableDisplayName, ConfigurableGroup[] groups) {
- final List<Configurable> all = SearchUtil.expand(groups);
- for (Configurable each : all) {
- if (preselectedConfigurableDisplayName.equals(each.getDisplayName())) return each;
- }
- return null;
+ return new ConfigurableVisitor.ByID(id).find(groups);
}
@Override
diff --git a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsEditor.java b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsEditor.java
index c2119596a06e..c1e55a1419a2 100644
--- a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsEditor.java
+++ b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsEditor.java
@@ -17,7 +17,6 @@ package com.intellij.openapi.options.newEditor;
import com.intellij.AbstractBundle;
import com.intellij.CommonBundle;
-import com.intellij.icons.AllIcons;
import com.intellij.ide.ui.laf.darcula.ui.DarculaTextBorder;
import com.intellij.ide.ui.laf.darcula.ui.DarculaTextFieldUI;
import com.intellij.ide.ui.search.SearchUtil;
@@ -1219,27 +1218,31 @@ public class OptionsEditor extends JPanel implements DataProvider, Place.Navigat
* @return default view for the specified configurable
*/
private JComponent createDefaultComponent(SearchableConfigurable searchable) {
- JPanel box = new JPanel();
- box.setLayout(new BoxLayout(box, BoxLayout.Y_AXIS));
+ JPanel panel = new JPanel(new BorderLayout(0, 9));
try {
- box.add(new JLabel(getDefaultDescription(searchable)));
+ panel.add(BorderLayout.NORTH, new JLabel(getDefaultDescription(searchable)));
}
catch (AssertionError error) {
return null; // description is not set
}
if (searchable instanceof Configurable.Composite) {
- box.add(Box.createVerticalStrut(10));
+ JPanel box = new JPanel();
+ box.setLayout(new BoxLayout(box, BoxLayout.Y_AXIS));
+ panel.add(BorderLayout.CENTER, box);
+
Configurable.Composite composite = (Configurable.Composite)searchable;
for (final Configurable configurable : composite.getConfigurables()) {
- box.add(new LinkLabel(configurable.getDisplayName(), AllIcons.Ide.Link) {
+ LinkLabel label = new LinkLabel(configurable.getDisplayName(), null) {
@Override
public void doClick() {
select(configurable, null);
}
- });
+ };
+ label.setBorder(BorderFactory.createEmptyBorder(1, 17, 1, 1));
+ box.add(label);
}
}
- return box;
+ return panel;
}
@NotNull
diff --git a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsTree.java b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsTree.java
index aee9e889fdf1..ed52a7f50bf6 100644
--- a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsTree.java
+++ b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/OptionsTree.java
@@ -23,7 +23,6 @@ import com.intellij.openapi.options.ConfigurableGroup;
import com.intellij.openapi.options.OptionsBundle;
import com.intellij.openapi.options.SearchableConfigurable;
import com.intellij.openapi.options.ex.ConfigurableWrapper;
-import com.intellij.openapi.options.ex.NodeConfigurable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.ActionCallback;
import com.intellij.openapi.util.Disposer;
@@ -383,17 +382,6 @@ public class OptionsTree extends JPanel implements Disposable, OptionsEditorColl
SimpleNode parent = base.getParent();
if (parent == myRoot) {
project = getConfigurableProject(base); // show icon for top-level nodes
- if (base.getConfigurable() instanceof NodeConfigurable) { // special case for custom subgroups (build.tools)
- Configurable[] configurables = ((NodeConfigurable)base.getConfigurable()).getConfigurables();
- if (configurables != null) { // assume that all configurables have the same project
- project = getConfigurableProject(configurables[0]);
- }
- }
- }
- else if (parent instanceof Base && ((Base)parent).getConfigurable() instanceof NodeConfigurable) {
- if (((Base)base.getParent()).getConfigurable() instanceof NodeConfigurable) {
- project = getConfigurableProject(base); // special case for custom subgroups
- }
}
}
if (project != null) {
diff --git a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsTreeView.java b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsTreeView.java
index e10367d583bf..817a042c9bc9 100644
--- a/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsTreeView.java
+++ b/platform/platform-impl/src/com/intellij/openapi/options/newEditor/SettingsTreeView.java
@@ -20,7 +20,7 @@ import com.intellij.ide.util.treeView.NodeDescriptor;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.options.*;
import com.intellij.openapi.options.ex.ConfigurableWrapper;
-import com.intellij.openapi.options.ex.NodeConfigurable;
+import com.intellij.openapi.options.ex.SortedConfigurableGroup;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.ActionCallback;
import com.intellij.openapi.util.Disposer;
@@ -49,6 +49,7 @@ import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.plaf.TreeUI;
import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
import java.awt.*;
@@ -63,6 +64,7 @@ import java.util.List;
* @author Sergey.Malenkov
*/
final class SettingsTreeView extends JComponent implements Disposable, OptionsEditorColleague {
+ private static final String NODE_ICON = "settings.tree.view.icon";
private static final Color NORMAL_NODE = new JBColor(Gray._60, Gray._140);
private static final Color WRONG_CONTENT = JBColor.RED;
private static final Color MODIFIED_CONTENT = JBColor.BLUE;
@@ -74,8 +76,9 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
private final MyRoot myRoot;
private final JScrollPane myScroller;
private JLabel mySeparator;
- private final MyRenderer myRenderer = new MyRenderer();
private final IdentityHashMap<Configurable, MyNode> myConfigurableToNodeMap = new IdentityHashMap<Configurable, MyNode>();
+ private final IdentityHashMap<UnnamedConfigurable, ConfigurableWrapper> myConfigurableToWrapperMap
+ = new IdentityHashMap<UnnamedConfigurable, ConfigurableWrapper>();
private final MergingUpdateQueue myQueue = new MergingUpdateQueue("SettingsTreeView", 150, false, this, this, this)
.setRestartTimerOnAdd(true);
@@ -96,9 +99,10 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
myTree.setRowHeight(-1);
myTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
- myTree.setCellRenderer(myRenderer);
+ myTree.setCellRenderer(new MyRenderer());
myTree.setRootVisible(false);
myTree.setShowsRootHandles(false);
+ myTree.setExpandableItemsEnabled(false);
myScroller = ScrollPaneFactory.createScrollPane(myTree, true);
myScroller.getVerticalScrollBar().setUI(ButtonlessScrollBarUI.createTransparent());
@@ -139,7 +143,7 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
@NotNull
String[] getPathNames(Configurable configurable) {
ArrayDeque<String> path = new ArrayDeque<String>();
- MyNode node = myConfigurableToNodeMap.get(configurable);
+ MyNode node = findNode(configurable);
while (node != null) {
path.push(node.myDisplayName);
SimpleNode parent = node.getParent();
@@ -157,8 +161,9 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
}
@Nullable
- SimpleNode findNode(Configurable configurable) {
- return myConfigurableToNodeMap.get(configurable);
+ MyNode findNode(Configurable configurable) {
+ ConfigurableWrapper wrapper = myConfigurableToWrapperMap.get(configurable);
+ return myConfigurableToNodeMap.get(wrapper != null ? wrapper : configurable);
}
@Nullable
@@ -180,6 +185,7 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
if (configurable instanceof ConfigurableWrapper) {
ConfigurableWrapper wrapper = (ConfigurableWrapper)configurable;
configurable = wrapper.getConfigurable();
+ myConfigurableToWrapperMap.put(configurable, wrapper);
}
if (type.isInstance(configurable)) {
return type.cast(configurable);
@@ -194,7 +200,7 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
ConfigurableWrapper wrapper = (ConfigurableWrapper)configurable;
return wrapper.getExtensionPoint().getProject();
}
- return findConfigurableProject(myConfigurableToNodeMap.get(configurable));
+ return findConfigurableProject(findNode(configurable));
}
@Nullable
@@ -214,15 +220,15 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
}
@Nullable
- private ConfigurableGroup findConfigurableGroupAt(int x, int y) {
+ private String findGroupNameAt(int x, int y) {
TreePath path = myTree.getClosestPathForLocation(x - myTree.getX(), y - myTree.getY());
while (path != null) {
MyNode node = extractNode(path);
if (node == null) {
return null;
}
- if (node.myComposite instanceof ConfigurableGroup) {
- return (ConfigurableGroup)node.myComposite;
+ if (myRoot == node.getParent()) {
+ return node.myDisplayName;
}
path = path.getParentPath();
}
@@ -267,10 +273,10 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
mySeparator.setFont(getFont().deriveFont(Font.BOLD));
}
int height = mySeparator.getPreferredSize().height;
- ConfigurableGroup group = findConfigurableGroupAt(0, height);
- if (group != null && group == findConfigurableGroupAt(0, -myRenderer.getSeparatorHeight())) {
+ String group = findGroupNameAt(0, height);
+ if (group != null && group.equals(findGroupNameAt(0, 0))) {
mySeparator.setBorder(BorderFactory.createEmptyBorder(0, 18, 0, 0));
- mySeparator.setText(group.getDisplayName());
+ mySeparator.setText(group);
Rectangle bounds = myScroller.getViewport().getBounds();
if (bounds.height > height) {
@@ -319,7 +325,7 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
public void run() {
if (configurable != myQueuedConfigurable) return;
- MyNode editorNode = myConfigurableToNodeMap.get(configurable);
+ MyNode editorNode = findNode(configurable);
FilteringTreeStructure.FilteringNode editorUiNode = myBuilder.getVisibleNodeFor(editorNode);
if (editorUiNode == null) return;
@@ -353,7 +359,8 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
}
private void fireSelected(Configurable configurable, ActionCallback callback) {
- myFilter.myContext.fireSelected(configurable, this).doWhenProcessed(callback.createSetDoneRunnable());
+ ConfigurableWrapper wrapper = myConfigurableToWrapperMap.get(configurable);
+ myFilter.myContext.fireSelected(wrapper != null ? wrapper : configurable, this).doWhenProcessed(callback.createSetDoneRunnable());
}
@Override
@@ -396,11 +403,13 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
if (myGroups == null || myGroups.length == 0) {
return NO_CHILDREN;
}
- SimpleNode[] result = new SimpleNode[myGroups.length];
- for (int i = 0; i < myGroups.length; i++) {
- result[i] = new MyNode(this, myGroups[i]);
+ ArrayList<MyNode> list = new ArrayList<MyNode>();
+ for (ConfigurableGroup group : myGroups) {
+ for (Configurable configurable : group.getConfigurables()) {
+ list.add(new MyNode(this, configurable, 0));
+ }
}
- return result;
+ return list.toArray(new SimpleNode[list.size()]);
}
}
@@ -408,21 +417,15 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
private final Configurable.Composite myComposite;
private final Configurable myConfigurable;
private final String myDisplayName;
+ private final int myLevel;
- private MyNode(CachingSimpleNode parent, Configurable configurable) {
+ private MyNode(CachingSimpleNode parent, Configurable configurable, int level) {
super(parent);
myComposite = configurable instanceof Configurable.Composite ? (Configurable.Composite)configurable : null;
myConfigurable = configurable;
String name = configurable.getDisplayName();
myDisplayName = name != null ? name.replace("\n", " ") : "{ " + configurable.getClass().getSimpleName() + " }";
- }
-
- private MyNode(CachingSimpleNode parent, ConfigurableGroup group) {
- super(parent);
- myComposite = group;
- myConfigurable = group instanceof Configurable ? (Configurable)group : null;
- String name = group.getDisplayName();
- myDisplayName = name != null ? name.replace("\n", " ") : "{ " + group.getClass().getSimpleName() + " }";
+ myLevel = level;
}
@Override
@@ -439,7 +442,7 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
}
SimpleNode[] result = new SimpleNode[configurables.length];
for (int i = 0; i < configurables.length; i++) {
- result[i] = new MyNode(this, configurables[i]);
+ result[i] = new MyNode(this, configurables[i], myLevel + 1);
if (myConfigurable != null) {
myFilter.myContext.registerKid(myConfigurable, configurables[i]);
}
@@ -453,25 +456,17 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
}
}
- private final class MyRenderer extends GroupedElementsRenderer.Tree {
- private JLabel myNodeIcon;
- private JLabel myProjectIcon;
-
- protected JComponent createItemComponent() {
- myTextLabel = new ErrorLabel();
- return myTextLabel;
- }
+ private final class MyRenderer extends JPanel implements TreeCellRenderer {
+ private final JLabel myTextLabel = new ErrorLabel();
+ private final JLabel myNodeIcon = new JLabel(" ", SwingConstants.RIGHT);
+ private final JLabel myProjectIcon = new JLabel(" ", SwingConstants.LEFT);
- @Override
- protected void layout() {
- myNodeIcon = new JLabel(" ", SwingConstants.RIGHT);
- myProjectIcon = new JLabel(" ", SwingConstants.LEFT);
- myNodeIcon.setOpaque(false);
- myTextLabel.setOpaque(false);
- myProjectIcon.setOpaque(false);
- myRendererComponent.add(BorderLayout.CENTER, myComponent);
- myRendererComponent.add(BorderLayout.WEST, myNodeIcon);
- myRendererComponent.add(BorderLayout.EAST, myProjectIcon);
+ public MyRenderer() {
+ super(new BorderLayout());
+ myNodeIcon.setName(NODE_ICON);
+ add(BorderLayout.CENTER, myTextLabel);
+ add(BorderLayout.WEST, myNodeIcon);
+ add(BorderLayout.EAST, myProjectIcon);
}
public Component getTreeCellRendererComponent(JTree tree,
@@ -482,7 +477,7 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
int row,
boolean focused) {
myTextLabel.setFont(UIUtil.getLabelFont());
- myRendererComponent.setBackground(selected ? UIUtil.getTreeSelectionBackground() : myTree.getBackground());
+ setPreferredSize(null);
MyNode node = extractNode(value);
if (node == null) {
@@ -494,28 +489,19 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
if (myRoot == node.getParent()) {
myTextLabel.setFont(myTextLabel.getFont().deriveFont(Font.BOLD));
}
- TreePath path = tree.getPathForRow(row);
- if (path == null) {
- if (value instanceof DefaultMutableTreeNode) {
- path = new TreePath(((DefaultMutableTreeNode)value).getPath());
- }
- }
- int forcedWidth = 2000;
- if (path != null && tree.isVisible()) {
- Rectangle visibleRect = tree.getVisibleRect();
-
- int nestingLevel = tree.isRootVisible() ? path.getPathCount() - 1 : path.getPathCount() - 2;
-
- int left = UIUtil.getTreeLeftChildIndent();
- int right = UIUtil.getTreeRightChildIndent();
-
+ if (tree.isVisible()) {
+ int indent = node.myLevel * (UIUtil.getTreeLeftChildIndent() + UIUtil.getTreeRightChildIndent());
Insets treeInsets = tree.getInsets();
-
- int indent = (left + right) * nestingLevel + (treeInsets != null ? treeInsets.left + treeInsets.right : 0);
-
- forcedWidth = visibleRect.width > 0 ? visibleRect.width - indent : forcedWidth;
+ if (treeInsets != null) {
+ indent += treeInsets.left + treeInsets.right;
+ }
+ int visibleWidth = tree.getVisibleRect().width;
+ if (visibleWidth > indent) {
+ Dimension size = getPreferredSize();
+ size.width = visibleWidth - indent;
+ //setPreferredSize(size);
+ }
}
- myRendererComponent.setPrefereedWidth(forcedWidth - 4);
}
// update font color for modified configurables
myTextLabel.setForeground(selected ? UIUtil.getTreeSelectionForeground() : NORMAL_NODE);
@@ -537,15 +523,15 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
if (parent instanceof MyNode) {
if (myRoot == parent.getParent()) {
project = findConfigurableProject(node); // show icon for top-level nodes
- if (node.myConfigurable instanceof NodeConfigurable) { // special case for custom subgroups (build.tools)
- Configurable[] configurables = ((NodeConfigurable)node.myConfigurable).getConfigurables();
+ if (node.myConfigurable instanceof SortedConfigurableGroup) { // special case for custom subgroups (build.tools)
+ Configurable[] configurables = ((SortedConfigurableGroup)node.myConfigurable).getConfigurables();
if (configurables != null) { // assume that all configurables have the same project
project = findConfigurableProject(configurables[0]);
}
}
}
- else if (((MyNode)parent).myConfigurable instanceof NodeConfigurable) {
- if (((MyNode)node.getParent()).myConfigurable instanceof NodeConfigurable) {
+ else if (((MyNode)parent).myConfigurable instanceof SortedConfigurableGroup) {
+ if (((MyNode)node.getParent()).myConfigurable instanceof SortedConfigurableGroup) {
project = findConfigurableProject(node); // special case for custom subgroups
}
}
@@ -564,25 +550,20 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
myProjectIcon.setVisible(false);
}
// configure node icon
- if (value instanceof DefaultMutableTreeNode) {
- DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode)value;
- TreePath treePath = new TreePath(treeNode.getPath());
- myNodeIcon.setIcon(myTree.getHandleIcon(treeNode, treePath));
- }
- else {
- myNodeIcon.setIcon(null);
+ Icon nodeIcon = null;
+ if (node != null) {
+ if (0 == node.getChildCount()) {
+ nodeIcon = myTree.getEmptyHandle();
+ }
+ else if (value instanceof DefaultMutableTreeNode) {
+ DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode)value;
+ nodeIcon = myTree.isExpanded(new TreePath(treeNode.getPath()))
+ ? myTree.getExpandedHandle()
+ : myTree.getCollapsedHandle();
+ }
}
- return myRendererComponent;
- }
-
- int getSeparatorHeight() {
- return mySeparatorComponent.getParent() == null ? 0 : mySeparatorComponent.getPreferredSize().height;
- }
-
- public boolean isUnderHandle(Point point) {
- Point handlePoint = SwingUtilities.convertPoint(myRendererComponent, point, myNodeIcon);
- Rectangle bounds = myNodeIcon.getBounds();
- return bounds.x < handlePoint.x && bounds.getMaxX() >= handlePoint.x;
+ myNodeIcon.setIcon(nodeIcon);
+ return this;
}
}
@@ -616,11 +597,7 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
@Override
public void setUI(TreeUI ui) {
- TreeUI actualUI = ui;
- if (!(ui instanceof MyTreeUi)) {
- actualUI = new MyTreeUi();
- }
- super.setUI(actualUI);
+ super.setUI(ui instanceof MyTreeUi ? ui : new MyTreeUi());
}
@Override
@@ -659,84 +636,92 @@ final class SettingsTreeView extends JComponent implements Disposable, OptionsEd
}
@Override
- protected void processMouseEvent(MouseEvent e) {
+ protected void processMouseEvent(MouseEvent event) {
MyTreeUi ui = (MyTreeUi)myTree.getUI();
- boolean toggleNow = MouseEvent.MOUSE_RELEASED == e.getID()
- && UIUtil.isActionClick(e, MouseEvent.MOUSE_RELEASED)
- && !ui.isToggleEvent(e);
-
- if (toggleNow || MouseEvent.MOUSE_PRESSED == e.getID()) {
- TreePath path = getPathForLocation(e.getX(), e.getY());
- if (path != null) {
- Rectangle bounds = getPathBounds(path);
- if (bounds != null && path.getLastPathComponent() instanceof DefaultMutableTreeNode) {
- DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent();
- boolean selected = isPathSelected(path);
- boolean expanded = isExpanded(path);
- Component comp =
- myRenderer.getTreeCellRendererComponent(this, node, selected, expanded, node.isLeaf(), getRowForPath(path), isFocusOwner());
-
- comp.setBounds(bounds);
- comp.validate();
-
- Point point = new Point(e.getX() - bounds.x, e.getY() - bounds.y);
- if (myRenderer.isUnderHandle(point)) {
- if (toggleNow) {
- ui.toggleExpandState(path);
- }
- e.consume();
- return;
- }
- }
- }
+ if (!ui.processMouseEvent(event)) {
+ super.processMouseEvent(event);
}
-
- super.processMouseEvent(e);
}
+ }
- private final class MyTreeUi extends WideSelectionTreeUI {
+ private static final class MyTreeUi extends WideSelectionTreeUI {
+ boolean processMouseEvent(MouseEvent event) {
+ if (super.tree instanceof SimpleTree) {
+ SimpleTree tree = (SimpleTree)super.tree;
- @Override
- public void toggleExpandState(TreePath path) {
- super.toggleExpandState(path);
- }
+ boolean toggleNow = MouseEvent.MOUSE_RELEASED == event.getID()
+ && UIUtil.isActionClick(event, MouseEvent.MOUSE_RELEASED)
+ && !isToggleEvent(event);
- @Override
- public boolean isToggleEvent(MouseEvent event) {
- return super.isToggleEvent(event);
+ if (toggleNow || MouseEvent.MOUSE_PRESSED == event.getID()) {
+ Component component = tree.getDeepestRendererComponentAt(event.getX(), event.getY());
+ if (component != null && NODE_ICON.equals(component.getName())) {
+ if (toggleNow) {
+ toggleExpandState(tree.getPathForLocation(event.getX(), event.getY()));
+ }
+ event.consume();
+ return true;
+ }
+ }
}
+ return false;
+ }
- @Override
- protected boolean shouldPaintExpandControl(TreePath path,
- int row,
- boolean isExpanded,
- boolean hasBeenExpanded,
- boolean isLeaf) {
- return false;
- }
+ @Override
+ protected boolean shouldPaintExpandControl(TreePath path,
+ int row,
+ boolean isExpanded,
+ boolean hasBeenExpanded,
+ boolean isLeaf) {
+ return false;
+ }
- @Override
- protected void paintHorizontalPartOfLeg(Graphics g,
- Rectangle clipBounds,
- Insets insets,
- Rectangle bounds,
- TreePath path,
- int row,
- boolean isExpanded,
- boolean hasBeenExpanded,
- boolean isLeaf) {
+ @Override
+ protected void paintHorizontalPartOfLeg(Graphics g,
+ Rectangle clipBounds,
+ Insets insets,
+ Rectangle bounds,
+ TreePath path,
+ int row,
+ boolean isExpanded,
+ boolean hasBeenExpanded,
+ boolean isLeaf) {
- }
+ }
- @Override
- protected void paintVerticalPartOfLeg(Graphics g, Rectangle clipBounds, Insets insets, TreePath path) {
- }
+ @Override
+ protected void paintVerticalPartOfLeg(Graphics g, Rectangle clipBounds, Insets insets, TreePath path) {
+ }
- @Override
- public void paint(Graphics g, JComponent c) {
- GraphicsUtil.setupAntialiasing(g);
- super.paint(g, c);
+ @Override
+ public void paint(Graphics g, JComponent c) {
+ GraphicsUtil.setupAntialiasing(g);
+ super.paint(g, c);
+ }
+
+ @Override
+ protected void paintRow(Graphics g,
+ Rectangle clipBounds,
+ Insets insets,
+ Rectangle bounds,
+ TreePath path,
+ int row,
+ boolean isExpanded,
+ boolean hasBeenExpanded,
+ boolean isLeaf) {
+ if (tree != null) {
+ int width = tree.getWidth();
+ Container parent = tree.getParent();
+ if (parent instanceof JViewport) {
+ JViewport viewport = (JViewport)parent;
+ width = viewport.getWidth() - viewport.getViewPosition().x;
+ }
+ width -= bounds.x;
+ if (bounds.width < width) {
+ bounds.width = width;
+ }
}
+ super.paintRow(g, clipBounds, insets, bounds, path, row, isExpanded, hasBeenExpanded, isLeaf);
}
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java b/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java
index 308edb2d81a6..c66eb5eb1a27 100644
--- a/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/project/DumbServiceImpl.java
@@ -34,7 +34,6 @@ import com.intellij.openapi.wm.IdeFrame;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.openapi.wm.ex.ProgressIndicatorEx;
import com.intellij.openapi.wm.ex.StatusBarEx;
-import com.intellij.psi.impl.DebugUtil;
import com.intellij.ui.AppIcon;
import com.intellij.util.concurrency.Semaphore;
import com.intellij.util.containers.ContainerUtil;
@@ -81,7 +80,7 @@ public class DumbServiceImpl extends DumbService implements Disposable {
@Override
public void cancelTask(@NotNull DumbModeTask task) {
- if (ApplicationManager.getApplication().isInternal()) LOG.info("cancel " + task + "\n" + DebugUtil.currentStackTrace());
+ if (ApplicationManager.getApplication().isInternal()) LOG.info("cancel " + task);
ProgressIndicatorEx indicator = myProgresses.get(task);
if (indicator != null) {
indicator.cancel();
diff --git a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java
index 978e20f6b532..8725dc003da5 100644
--- a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectImpl.java
@@ -38,7 +38,6 @@ import com.intellij.openapi.components.impl.stores.IProjectStore;
import com.intellij.openapi.components.impl.stores.StoreUtil;
import com.intellij.openapi.components.impl.stores.UnknownMacroNotification;
import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.util.pico.ConstructorInjectionComponentAdapter;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.progress.ProgressIndicator;
@@ -58,6 +57,8 @@ import com.intellij.openapi.wm.impl.FrameTitleBuilder;
import com.intellij.util.Function;
import com.intellij.util.TimedReference;
import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.pico.ConstructorInjectionComponentAdapter;
+import gnu.trove.THashSet;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -488,7 +489,7 @@ public class ProjectImpl extends PlatformComponentManagerImpl implements Project
}
if (!macros2invalidate.isEmpty()) {
- final Set<String> components = new HashSet<String>();
+ final Set<String> components = new THashSet<String>();
for (TrackingPathMacroSubstitutor substitutor : substitutors) {
components.addAll(substitutor.getComponents(macros2invalidate));
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java
index e7b20959369e..b5243e7c7ec9 100644
--- a/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/project/impl/ProjectManagerImpl.java
@@ -57,7 +57,6 @@ import com.intellij.util.ArrayUtil;
import com.intellij.util.TimeoutUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashMap;
-import com.intellij.util.io.fs.IFile;
import com.intellij.util.messages.MessageBus;
import com.intellij.util.messages.MessageBusConnection;
import com.intellij.util.ui.UIUtil;
@@ -922,9 +921,9 @@ public class ProjectManagerImpl extends ProjectManagerEx implements NamedJDOMExt
IProjectStore projectStore = projectImpl.getStateStore();
final String location = projectImpl.getPresentableUrl();
- final List<IFile> original;
+ final List<File> original;
try {
- final IComponentStore.SaveSession saveSession = projectStore.startSave();
+ IComponentStore.SaveSession saveSession = projectStore.startSave();
original = saveSession.getAllStorageFiles(true);
saveSession.finishSave();
}
@@ -937,7 +936,7 @@ public class ProjectManagerImpl extends ProjectManagerEx implements NamedJDOMExt
application.runWriteAction(new Runnable() {
@Override
public void run() {
- for (final IFile originalFile : original) {
+ for (File originalFile : original) {
restoreCopy(LocalFileSystem.getInstance().refreshAndFindFileByIoFile(originalFile));
}
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/ui/popup/MultiSelectionListPopupStep.java b/platform/platform-impl/src/com/intellij/openapi/ui/popup/MultiSelectionListPopupStep.java
index 815eafd56ab4..96fbccc87054 100644
--- a/platform/platform-impl/src/com/intellij/openapi/ui/popup/MultiSelectionListPopupStep.java
+++ b/platform/platform-impl/src/com/intellij/openapi/ui/popup/MultiSelectionListPopupStep.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,8 +28,8 @@ import java.util.List;
public abstract class MultiSelectionListPopupStep<T> extends BaseListPopupStep<T> {
private int[] myDefaultOptionIndices = ArrayUtil.EMPTY_INT_ARRAY;
- protected MultiSelectionListPopupStep(@Nullable String aTitle, List<? extends T> aValues) {
- super(aTitle, aValues);
+ protected MultiSelectionListPopupStep(@Nullable String title, List<? extends T> values) {
+ super(title, values);
}
public abstract PopupStep<?> onChosen(List<T> selectedValues, boolean finalChoice);
@@ -54,8 +54,8 @@ public abstract class MultiSelectionListPopupStep<T> extends BaseListPopupStep<T
}
@Override
- public final void setDefaultOptionIndex(int aDefaultOptionIndex) {
- myDefaultOptionIndices = new int[]{aDefaultOptionIndex};
+ public final void setDefaultOptionIndex(int defaultOptionIndex) {
+ myDefaultOptionIndices = new int[]{defaultOptionIndex};
}
public int[] getDefaultOptionIndices() {
diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/CheckForUpdateAction.java b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/CheckForUpdateAction.java
index 1f331d7f9232..81b51cab9cb2 100644
--- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/CheckForUpdateAction.java
+++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/CheckForUpdateAction.java
@@ -15,6 +15,7 @@
*/
package com.intellij.openapi.updateSettings.impl;
+import com.intellij.openapi.actionSystem.ActionPlaces;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
@@ -24,7 +25,7 @@ import com.intellij.openapi.util.SystemInfo;
public class CheckForUpdateAction extends AnAction implements DumbAware {
@Override
public void update(AnActionEvent e) {
- e.getPresentation().setVisible(!SystemInfo.isMacSystemMenu);
+ e.getPresentation().setVisible(!SystemInfo.isMacSystemMenu || !ActionPlaces.MAIN_MENU.equals(e.getPlace()));
}
@Override
diff --git a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/NoUpdatesPanel.form b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/NoUpdatesPanel.form
index 2cee5d3e03f9..be22623c2142 100644
--- a/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/NoUpdatesPanel.form
+++ b/platform/platform-impl/src/com/intellij/openapi/updateSettings/impl/NoUpdatesPanel.form
@@ -25,7 +25,6 @@
</constraints>
<properties>
<contentType value="text/html"/>
- <text value="&lt;html&gt;&#10; &lt;head&gt;&#10;&#10; &lt;/head&gt;&#10; &lt;body&gt;&#10; &lt;p style=&quot;margin-top: 0&quot;&gt;&#10; &#10; &lt;/p&gt;&#10; &lt;/body&gt;&#10;&lt;/html&gt;&#10;"/>
</properties>
</component>
<vspacer id="bf1d9">
diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/ex/dummy/DummyCachingFileSystem.java b/platform/platform-impl/src/com/intellij/openapi/vfs/ex/dummy/DummyCachingFileSystem.java
index 071a260fe68c..a95597514bb1 100644
--- a/platform/platform-impl/src/com/intellij/openapi/vfs/ex/dummy/DummyCachingFileSystem.java
+++ b/platform/platform-impl/src/com/intellij/openapi/vfs/ex/dummy/DummyCachingFileSystem.java
@@ -15,12 +15,14 @@
*/
package com.intellij.openapi.vfs.ex.dummy;
+import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.project.ProjectManagerAdapter;
+import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.BidirectionalMap;
@@ -32,7 +34,6 @@ import org.jetbrains.annotations.TestOnly;
import java.io.IOException;
import java.util.Collection;
-import java.util.Iterator;
import java.util.List;
/**
@@ -76,11 +77,6 @@ public abstract class DummyCachingFileSystem<T extends VirtualFile> extends Dumm
public void projectOpened(final Project project) {
onProjectOpened(project);
}
-
- @Override
- public void projectClosed(final Project project) {
- onProjectClosed(project);
- }
});
initProjectMap();
}
@@ -135,7 +131,16 @@ public abstract class DummyCachingFileSystem<T extends VirtualFile> extends Dumm
clearCache();
}
- public void onProjectOpened(Project project) {
+ public void onProjectOpened(final Project project) {
+ // use Disposer instead of ProjectManagerListener#projectClosed() because Disposer.dispose(project)
+ // is called later and some cached files should stay valid till the last moment
+ Disposer.register(project, new Disposable() {
+ @Override
+ public void dispose() {
+ onProjectClosed(project);
+ }
+ });
+
clearCache();
String projectId = project.getLocationHash();
myProject2Id.put(project, projectId);
@@ -157,13 +162,11 @@ public abstract class DummyCachingFileSystem<T extends VirtualFile> extends Dumm
}
protected void clearInvalidFiles() {
- for (Iterator<String> it = myCachedFiles.keySet().iterator(); it.hasNext(); ) {
- String path = it.next();
- T t = myCachedFiles.get(path);
- if (t == null || !t.isValid()) {
- it.remove();
- }
+ for (T t : myCachedFiles.notNullValues()) {
+ if (!t.isValid()) myCachedFiles.removeValue(t);
}
+ //noinspection StatementWithEmptyBody
+ while (myCachedFiles.removeValue(null)) ;
}
@TestOnly
diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VfsRootAccess.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VfsRootAccess.java
index b6fa97092059..5a0f433c7828 100644
--- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VfsRootAccess.java
+++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/impl/VfsRootAccess.java
@@ -49,7 +49,7 @@ import java.util.Set;
public class VfsRootAccess {
private static final boolean SHOULD_PERFORM_ACCESS_CHECK = System.getenv("NO_FS_ROOTS_ACCESS_CHECK") == null;
// we don't want test subclasses to accidentally remove allowed files, added by base classes
- private static final Set<String> ourAdditionalRoots = new THashSet<String>();
+ private static final Set<String> ourAdditionalRoots = new THashSet<String>(FileUtil.PATH_HASHING_STRATEGY);
private static boolean insideGettingRoots;
@TestOnly
@@ -109,7 +109,7 @@ public class VfsRootAccess {
Project[] openProjects = ProjectManager.getInstance().getOpenProjects();
if (openProjects.length == 0) return null;
- final Set<String> allowed = new THashSet<String>();
+ final Set<String> allowed = new THashSet<String>(FileUtil.PATH_HASHING_STRATEGY);
allowed.add(FileUtil.toSystemIndependentName(PathManager.getHomePath()));
try {
diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecords.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecords.java
index b05b7a285e7b..b8a55b333203 100644
--- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecords.java
+++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/FSRecords.java
@@ -29,6 +29,7 @@ import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream;
import com.intellij.openapi.util.io.ByteSequence;
import com.intellij.openapi.util.io.FileAttributes;
import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.vfs.newvfs.FileAttribute;
import com.intellij.openapi.vfs.newvfs.impl.FileNameCache;
import com.intellij.util.ArrayUtil;
import com.intellij.util.SystemProperties;
@@ -57,6 +58,7 @@ public class FSRecords implements Forceable {
private static final Logger LOG = Logger.getInstance("#com.intellij.vfs.persistent.FSRecords");
public static final boolean weHaveContentHashes = SystemProperties.getBooleanProperty("idea.share.contents", true);
+ public static final boolean lazyVfsDataCleaning = SystemProperties.getBooleanProperty("idea.lazy.vfs.data.cleaning", true);
private static final int VERSION = 20 + (weHaveContentHashes ? 0x10:0) + (IOUtil.ourByteBuffersUseNativeByteOrder ? 0x37:0);
private static final int PARENT_OFFSET = 0;
@@ -558,6 +560,7 @@ public class FSRecords implements Forceable {
return newRecord;
}
else {
+ if (lazyVfsDataCleaning) deleteContentAndAttributes(free);
DbConnection.cleanRecord(free);
return free;
}
@@ -588,7 +591,33 @@ public class FSRecords implements Forceable {
try {
w.lock();
incModCount(id);
- doDeleteRecursively(id);
+ if (lazyVfsDataCleaning) {
+ markAsDeletedRecursively(id);
+ } else {
+ doDeleteRecursively(id);
+ }
+ }
+ catch (Throwable e) {
+ throw DbConnection.handleError(e);
+ }
+ finally {
+ w.unlock();
+ }
+ }
+
+ private static void markAsDeletedRecursively(final int id) {
+ for (int subrecord : list(id)) {
+ markAsDeletedRecursively(subrecord);
+ }
+
+ markAsDeleted(id);
+ }
+
+ private static void markAsDeleted(final int id) {
+ try {
+ w.lock();
+ DbConnection.markDirty();
+ addToFreeRecordsList(id);
}
catch (Throwable e) {
throw DbConnection.handleError(e);
@@ -1206,12 +1235,26 @@ public class FSRecords implements Forceable {
}
@Nullable
- static DataInputStream readAttributeWithLock(int fileId, String attId) {
+ public static DataInputStream readAttributeWithLock(int fileId, FileAttribute att) {
try {
- synchronized (attId) {
+ synchronized (att.getId()) {
try {
r.lock();
- return readAttribute(fileId, attId);
+ DataInputStream stream = readAttribute(fileId, att.getId());
+ if (stream != null) {
+ try {
+ int actualVersion = DataInputOutputUtil.readINT(stream);
+ if (actualVersion != att.getVersion()) {
+ stream.close();
+ return null;
+ }
+ }
+ catch (IOException e) {
+ stream.close();
+ return null;
+ }
+ }
+ return stream;
}
finally {
r.unlock();
@@ -1280,7 +1323,9 @@ public class FSRecords implements Forceable {
private static void checkFileIsValid(int fileId) {
assert fileId > 0 : fileId;
// TODO: This assertion is a bit timey, will remove when bug is caught.
- assert (getFlags(fileId) & FREE_RECORD_FLAG) == 0 : "Accessing attribute of a deleted page: " + fileId + ":" + getName(fileId);
+ if (!lazyVfsDataCleaning) {
+ assert (getFlags(fileId) & FREE_RECORD_FLAG) == 0 : "Accessing attribute of a deleted page: " + fileId + ":" + getName(fileId);
+ }
}
public static int acquireFileContent(int fileId) {
@@ -1374,6 +1419,18 @@ public class FSRecords implements Forceable {
return new AttributeOutputStream(fileId, attId, fixedSize);
}
+ @NotNull
+ public static DataOutputStream writeAttribute(final int fileId, @NotNull FileAttribute att) {
+ DataOutputStream stream = writeAttribute(fileId, att.getId(), att.isFixedSize());
+ try {
+ DataInputOutputUtil.writeINT(stream, att.getVersion());
+ }
+ catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ return stream;
+ }
+
private static class ContentOutputStream extends DataOutputStream {
protected final int myFileId;
protected final boolean myFixedSize;
diff --git a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java
index db5de4258d41..6e135018d356 100644
--- a/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/vfs/newvfs/persistent/PersistentFSImpl.java
@@ -223,13 +223,13 @@ public class PersistentFSImpl extends PersistentFS implements ApplicationCompone
@Override
@Nullable
public DataInputStream readAttribute(@NotNull final VirtualFile file, @NotNull final FileAttribute att) {
- return FSRecords.readAttributeWithLock(getFileId(file), att.getId());
+ return FSRecords.readAttributeWithLock(getFileId(file), att);
}
@Override
@NotNull
public DataOutputStream writeAttribute(@NotNull final VirtualFile file, @NotNull final FileAttribute att) {
- return FSRecords.writeAttribute(getFileId(file), att.getId(), att.isFixedSize());
+ return FSRecords.writeAttribute(getFileId(file), att);
}
@Nullable
diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/CommandProcessor.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/CommandProcessor.java
index 30777377bc49..746030e68abd 100644
--- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/CommandProcessor.java
+++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/CommandProcessor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Condition;
+import com.intellij.openapi.util.Conditions;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.wm.impl.commands.FinalizableCommand;
import org.jetbrains.annotations.NotNull;
@@ -124,7 +125,7 @@ public final class CommandProcessor implements Runnable {
FinalizableCommand command = myList.remove(0);
if (isEmpty()) {
// memory leak otherwise
- myExpireCondition = Condition.TRUE;
+ myExpireCondition = Conditions.alwaysTrue();
}
return command;
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/InternalDecorator.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/InternalDecorator.java
index e6c84f5e7768..ba5c59a9ac25 100644
--- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/InternalDecorator.java
+++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/InternalDecorator.java
@@ -17,6 +17,7 @@ package com.intellij.openapi.wm.impl;
import com.intellij.ide.actions.ResizeToolWindowAction;
import com.intellij.idea.ActionsBundle;
+import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.keymap.Keymap;
import com.intellij.openapi.keymap.KeymapManagerListener;
@@ -28,6 +29,7 @@ import com.intellij.openapi.ui.Splitter;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.SystemInfo;
+import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.wm.*;
import com.intellij.ui.Gray;
import com.intellij.ui.JBColor;
@@ -54,8 +56,6 @@ import java.util.Map;
*/
public final class InternalDecorator extends JPanel implements Queryable, TypeSafeDataProvider {
- private static final int DIVIDER_WIDTH = UIUtil.isUnderDarcula() ? 2 : 5;
-
private Project myProject;
private WindowInfoImpl myInfo;
private final ToolWindowImpl myToolWindow;
@@ -169,7 +169,7 @@ public final class InternalDecorator extends JPanel implements Queryable, TypeSa
else if (ToolWindowAnchor.RIGHT == anchor) {
add(myDivider, BorderLayout.WEST);
}
- myDivider.setPreferredSize(new Dimension(DIVIDER_WIDTH, DIVIDER_WIDTH));
+ myDivider.setPreferredSize(new Dimension(0, 0));
}
else { // docked and floating windows don't have divider
remove(myDivider);
@@ -303,10 +303,16 @@ public final class InternalDecorator extends JPanel implements Queryable, TypeSa
@Override
public void paintBorder(final Component c, final Graphics g, final int x, final int y, final int width, final int height) {
- g.setColor(UIUtil.getPanelBackground());
- doPaintBorder(c, g, x, y, width, height);
- g.setColor(new Color(0, 0, 0, 90));
- doPaintBorder(c, g, x, y, width, height);
+ if (UIUtil.isUnderDarcula()) {
+ g.setColor(Gray._40);
+ doPaintBorder(c, g, x, y, width, height);
+ }
+ else {
+ g.setColor(UIUtil.getPanelBackground());
+ doPaintBorder(c, g, x, y, width, height);
+ g.setColor(Gray._155);
+ doPaintBorder(c, g, x, y, width, height);
+ }
}
private void doPaintBorder(Component c, Graphics g, int x, int y, int width, int height) {
@@ -314,18 +320,22 @@ public final class InternalDecorator extends JPanel implements Queryable, TypeSa
if (insets.top > 0) {
UIUtil.drawLine(g, x, y + insets.top - 1, x + width - 1, y + insets.top - 1);
+ UIUtil.drawLine(g, x, y + insets.top, x + width - 1, y + insets.top);
}
if (insets.left > 0) {
- UIUtil.drawLine(g, x, y + insets.top, x, y + height - 1);
+ UIUtil.drawLine(g, x, y, x, y + height);
+ UIUtil.drawLine(g, x + 1, y, x + 1, y + height);
}
if (insets.right > 0) {
- UIUtil.drawLine(g, x + width - 1, y + insets.top, x + width - 1, y + height - 1);
+ UIUtil.drawLine(g, x + width - 1, y + insets.top, x + width - 1, y + height);
+ UIUtil.drawLine(g, x + width, y + insets.top, x + width, y + height);
}
if (insets.bottom > 0) {
- UIUtil.drawLine(g, x, y + height - 1, x + width - 1, y + height - 1);
+ UIUtil.drawLine(g, x, y + height - 1, x + width, y + height - 1);
+ UIUtil.drawLine(g, x, y + height, x + width, y + height);
}
}
@@ -354,7 +364,7 @@ public final class InternalDecorator extends JPanel implements Queryable, TypeSa
component = parent;
parent = component.getParent();
}
- return new Insets(0, anchor == ToolWindowAnchor.RIGHT ? 1 : 0, 0, anchor == ToolWindowAnchor.LEFT ? 1 : 0);
+ return new Insets(0, anchor == ToolWindowAnchor.RIGHT ? 1 : 0, anchor == ToolWindowAnchor.TOP ? 1 : 0, anchor == ToolWindowAnchor.LEFT ? 1 : 0);
}
@Override
@@ -447,6 +457,10 @@ public final class InternalDecorator extends JPanel implements Queryable, TypeSa
}
}
}
+ String separatorText = group.getTemplatePresentation().getText();
+ if (children.length > 0 && !StringUtil.isEmpty(separatorText)) {
+ main.addAction(new Separator(separatorText), Constraints.FIRST);
+ }
}
/**
@@ -609,135 +623,98 @@ public final class InternalDecorator extends JPanel implements Queryable, TypeSa
private final class MyDivider extends JPanel {
private boolean myDragging;
private Point myLastPoint;
+ private Disposable myDisposable;
+ private IdeGlassPane myGlassPane;
+
+ private final MouseAdapter myListener = new MyMouseAdapter();
- private MyDivider() {
- myDragging = false;
- enableEvents(MouseEvent.MOUSE_EVENT_MASK | MouseEvent.MOUSE_MOTION_EVENT_MASK);
- setBorder(new DividerBorder());
+ @Override
+ public void addNotify() {
+ super.addNotify();
+ myGlassPane = IdeGlassPaneUtil.find(this);
+ myDisposable = Disposer.newDisposable();
+ myGlassPane.addMouseMotionPreprocessor(myListener, myDisposable);
+ myGlassPane.addMousePreprocessor(myListener, myDisposable);
}
@Override
- protected final void processMouseMotionEvent(final MouseEvent e) {
- super.processMouseMotionEvent(e);
- if (MouseEvent.MOUSE_DRAGGED == e.getID()) {
- myDragging = true;
- final ToolWindowAnchor anchor = myInfo.getAnchor();
- final boolean isVerticalCursor = myInfo.isDocked() ? anchor.isSplitVertically() : anchor.isHorizontal();
- setCursor(isVerticalCursor ? Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR) : Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR));
- final Point point = e.getPoint();
+ public void removeNotify() {
+ super.removeNotify();
+ if (myDisposable != null && !Disposer.isDisposed(myDisposable)) {
+ Disposer.dispose(myDisposable);
+ }
+ }
+
+ boolean isInDragZone(MouseEvent e) {
+ final Point p = SwingUtilities.convertMouseEvent(e.getComponent(), e, this).getPoint();
+ return Math.abs(myInfo.getAnchor().isHorizontal() ? p.y : p.x) < 6;
+ }
+
+
+ private class MyMouseAdapter extends MouseAdapter {
+
+ private void updateCursor(MouseEvent e) {
+ if (isInDragZone(e)) {
+ myGlassPane.setCursor(MyDivider.this.getCursor(), MyDivider.this);
+ e.consume();
+ }
+ }
+
+ @Override
+ public void mousePressed(MouseEvent e) {
+ myDragging = isInDragZone(e);
+ updateCursor(e);
+ }
+
+ @Override
+ public void mouseClicked(MouseEvent e) {
+ updateCursor(e);
+ }
+
+ @Override
+ public void mouseReleased(MouseEvent e) {
+ updateCursor(e);
+ myDragging = false;
+ }
+ @Override
+ public void mouseMoved(MouseEvent e) {
+ updateCursor(e);
+ }
+
+ @Override
+ public void mouseDragged(MouseEvent e) {
+ if (!myDragging) return;
+ MouseEvent event = SwingUtilities.convertMouseEvent(e.getComponent(), e, MyDivider.this);
+ final ToolWindowAnchor anchor = myInfo.getAnchor();
+ final Point point = event.getPoint();
final Container windowPane = InternalDecorator.this.getParent();
- myLastPoint = SwingUtilities.convertPoint(this, point, windowPane);
+ myLastPoint = SwingUtilities.convertPoint(MyDivider.this, point, windowPane);
myLastPoint.x = Math.min(Math.max(myLastPoint.x, 0), windowPane.getWidth());
myLastPoint.y = Math.min(Math.max(myLastPoint.y, 0), windowPane.getHeight());
final Rectangle bounds = InternalDecorator.this.getBounds();
if (anchor == ToolWindowAnchor.TOP) {
- if (myLastPoint.y < DIVIDER_WIDTH) {
- myLastPoint.y = DIVIDER_WIDTH;
- }
InternalDecorator.this.setBounds(0, 0, bounds.width, myLastPoint.y);
}
else if (anchor == ToolWindowAnchor.LEFT) {
- if (myLastPoint.x < DIVIDER_WIDTH) {
- myLastPoint.x = DIVIDER_WIDTH;
- }
InternalDecorator.this.setBounds(0, 0, myLastPoint.x, bounds.height);
}
else if (anchor == ToolWindowAnchor.BOTTOM) {
- if (myLastPoint.y > windowPane.getHeight() - DIVIDER_WIDTH) {
- myLastPoint.y = windowPane.getHeight() - DIVIDER_WIDTH;
- }
InternalDecorator.this.setBounds(0, myLastPoint.y, bounds.width, windowPane.getHeight() - myLastPoint.y);
}
else if (anchor == ToolWindowAnchor.RIGHT) {
- if (myLastPoint.x > windowPane.getWidth() - DIVIDER_WIDTH) {
- myLastPoint.x = windowPane.getWidth() - DIVIDER_WIDTH;
- }
InternalDecorator.this.setBounds(myLastPoint.x, 0, windowPane.getWidth() - myLastPoint.x, bounds.height);
}
InternalDecorator.this.validate();
+ e.consume();
}
}
@Override
- protected final void processMouseEvent(final MouseEvent e) {
- super.processMouseEvent(e);
+ public Cursor getCursor() {
final boolean isVerticalCursor = myInfo.isDocked() ? myInfo.getAnchor().isSplitVertically() : myInfo.getAnchor().isHorizontal();
- switch (e.getID()) {
- case MouseEvent.MOUSE_MOVED:
- default:
- break;
- case MouseEvent.MOUSE_ENTERED:
- setCursor(
- isVerticalCursor ? Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR) : Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR));
- break;
- case MouseEvent.MOUSE_EXITED:
- if (!myDragging) {
- setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
- }
- break;
- case MouseEvent.MOUSE_PRESSED:
- setCursor(
- isVerticalCursor ? Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR) : Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR));
- break;
- case MouseEvent.MOUSE_RELEASED:
- myDragging = false;
- myLastPoint = null;
- break;
- case MouseEvent.MOUSE_CLICKED:
- break;
- }
- }
-
- private final class DividerBorder implements Border {
- @Override
- public final void paintBorder(final Component c, final Graphics g, final int x, final int y, final int width, final int height) {
- final ToolWindowAnchor anchor = myInfo.getAnchor();
- final boolean isVertical = !anchor.isSplitVertically();
- final JBColor outer = new JBColor(Color.white, Color.darkGray);
- if (isVertical) {
- if (anchor == ToolWindowAnchor.TOP) {
- g.setColor(outer);
- UIUtil.drawLine(g, x, y, x + width - 1, y);
- g.setColor(Color.darkGray);
- UIUtil.drawLine(g, x, y + height - 1, x + width - 1, y + height - 1);
- }
- else {
- g.setColor(Color.darkGray);
- UIUtil.drawLine(g, x, y, x + width - 1, y);
- g.setColor(outer);
- UIUtil.drawLine(g, x, y + height - 1, x + width - 1, y + height - 1);
- }
- }
- else {
- if (anchor == ToolWindowAnchor.LEFT) {
- g.setColor(outer);
- UIUtil.drawLine(g, x, y, x, y + height - 1);
- g.setColor(Color.darkGray);
- UIUtil.drawLine(g, x + width - 1, y, x + width - 1, y + height - 1);
- }
- else {
- g.setColor(Color.darkGray);
- UIUtil.drawLine(g, x, y, x, y + height - 1);
- g.setColor(outer);
- UIUtil.drawLine(g, x + width - 1, y, x + width - 1, y + height - 1);
- }
- }
- }
-
- @Override
- public final Insets getBorderInsets(final Component c) {
- if (c instanceof MyDivider) {
- return new Insets(1, 1, 1, 1);
- }
- return new Insets(0, 0, 0, 0);
- }
-
- @Override
- public final boolean isBorderOpaque() {
- return true;
- }
+ return isVerticalCursor ? Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR) : Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR);
}
}
diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/WindowManagerImpl.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/WindowManagerImpl.java
index 19131753b5ba..e1824f775e82 100644
--- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/WindowManagerImpl.java
+++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/WindowManagerImpl.java
@@ -67,7 +67,6 @@ import java.util.Set;
*/
@State(
name = "WindowManager",
- roamingType = RoamingType.GLOBAL,
storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/window.manager.xml")})
public final class WindowManagerImpl extends WindowManagerEx implements NamedComponent, PersistentStateComponent<Element> {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.wm.impl.WindowManagerImpl");
diff --git a/platform/platform-impl/src/com/intellij/ui/TableExpandableItemsHandler.java b/platform/platform-impl/src/com/intellij/ui/TableExpandableItemsHandler.java
index b7704a687441..6099561c7283 100644
--- a/platform/platform-impl/src/com/intellij/ui/TableExpandableItemsHandler.java
+++ b/platform/platform-impl/src/com/intellij/ui/TableExpandableItemsHandler.java
@@ -16,6 +16,7 @@
package com.intellij.ui;
import com.intellij.openapi.util.Pair;
+import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
@@ -105,8 +106,11 @@ public class TableExpandableItemsHandler extends AbstractExpandableItemsHandler<
return myComponent.getCellRect(tableCellKey.row, tableCellKey.column, false);
}
+ @Nullable
public Pair<Component, Rectangle> getCellRendererAndBounds(TableCell key) {
- if (key.row < 0 || key.row >= myComponent.getRowCount() || key.column < 0 || key.column >= myComponent.getColumnCount()) {
+ if (key.row < 0 || key.row >= myComponent.getRowCount() ||
+ key.column < 0 || key.column >= myComponent.getColumnCount() ||
+ key.row == myComponent.getEditingRow() && key.column == myComponent.getEditingColumn()) {
return null;
}
diff --git a/platform/platform-impl/src/com/intellij/ui/content/impl/ContentManagerImpl.java b/platform/platform-impl/src/com/intellij/ui/content/impl/ContentManagerImpl.java
index d0b110f083bf..2d8bffe98d04 100644
--- a/platform/platform-impl/src/com/intellij/ui/content/impl/ContentManagerImpl.java
+++ b/platform/platform-impl/src/com/intellij/ui/content/impl/ContentManagerImpl.java
@@ -33,9 +33,8 @@ import com.intellij.ui.components.panels.Wrapper;
import com.intellij.ui.content.*;
import com.intellij.ui.switcher.SwitchProvider;
import com.intellij.ui.switcher.SwitchTarget;
-import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.SmartList;
-
+import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -191,7 +190,11 @@ public class ContentManagerImpl implements ContentManager, PropertyChangeListene
private void doAddContent(@NotNull final Content content, final int index) {
ApplicationManager.getApplication().assertIsDispatchThread();
- if (myContents.contains(content)) return;
+ if (myContents.contains(content)) {
+ myContents.remove(content);
+ myContents.add(index == -1 ? myContents.size() : index, content);
+ return;
+ }
((ContentImpl)content).setManager(this);
final int insertIndex = index == -1 ? myContents.size() : index;
@@ -703,6 +706,7 @@ public class ContentManagerImpl implements ContentManager, PropertyChangeListene
myContentWithChangedComponent.clear();
myUI = null;
myListeners.clear();
+ dataProviders.clear();
}
@Override
diff --git a/platform/platform-impl/src/com/intellij/ui/docking/impl/DockManagerImpl.java b/platform/platform-impl/src/com/intellij/ui/docking/impl/DockManagerImpl.java
index ee586418dbd6..37646a19292f 100644
--- a/platform/platform-impl/src/com/intellij/ui/docking/impl/DockManagerImpl.java
+++ b/platform/platform-impl/src/com/intellij/ui/docking/impl/DockManagerImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -94,6 +94,7 @@ public class DockManagerImpl extends DockManager implements PersistentStateCompo
myProject = project;
}
+ @Override
public void register(final DockContainer container) {
myContainers.add(container);
Disposer.register(container, new Disposable() {
@@ -147,6 +148,7 @@ public class DockManagerImpl extends DockManager implements PersistentStateCompo
return wnd != null ? key + "#" + wnd.myId : key;
}
+ @Override
public DockContainer getContainerFor(Component c) {
if (c == null) return null;
@@ -401,7 +403,8 @@ public class DockManagerImpl extends DockManager implements PersistentStateCompo
});
}
- public Pair<FileEditor[], FileEditorProvider[]> createNewDockContainerFor(@NotNull VirtualFile file, FileEditorManagerImpl fileEditorManager) {
+ @NotNull
+ public Pair<FileEditor[], FileEditorProvider[]> createNewDockContainerFor(@NotNull VirtualFile file, @NotNull FileEditorManagerImpl fileEditorManager) {
DockContainer container = getFactory(DockableEditorContainerFactory.TYPE).createContainer(null);
register(container);
diff --git a/platform/platform-impl/src/com/intellij/ui/messages/JBMacMessages.java b/platform/platform-impl/src/com/intellij/ui/messages/JBMacMessages.java
index 2a70b61c6e8a..47ebb829adc2 100644
--- a/platform/platform-impl/src/com/intellij/ui/messages/JBMacMessages.java
+++ b/platform/platform-impl/src/com/intellij/ui/messages/JBMacMessages.java
@@ -190,7 +190,7 @@ public class JBMacMessages extends MacMessagesEmulation {
SheetMessage sheetMessage = new SheetMessage(window, title, message, UIUtil.getQuestionIcon(),
new String [] {yesButton, noButton}, doNotAskDialogOption, yesButton, noButton);
int result = sheetMessage.getResult().equals(yesButton) ? Messages.YES : Messages.NO;
- if (doNotAskDialogOption != null) {
+ if (doNotAskDialogOption != null && (result == Messages.YES || doNotAskDialogOption.shouldSaveOptionsOnCancel())) {
doNotAskDialogOption.setToBeShown(sheetMessage.toBeShown(), result);
}
return result;
diff --git a/platform/platform-impl/src/com/intellij/ui/popup/WizardPopup.java b/platform/platform-impl/src/com/intellij/ui/popup/WizardPopup.java
index 1b9190f6a740..d8b512367f26 100644
--- a/platform/platform-impl/src/com/intellij/ui/popup/WizardPopup.java
+++ b/platform/platform-impl/src/com/intellij/ui/popup/WizardPopup.java
@@ -189,7 +189,7 @@ public abstract class WizardPopup extends AbstractPopup implements ActionListene
targetBounds.x = getParent().getBounds().x - targetBounds.width - STEP_X_PADDING;
}
} else {
- ScreenUtil.moveToFit(targetBounds, ScreenUtil.getScreenRectangle(aScreenX, aScreenY), null);
+ ScreenUtil.moveToFit(targetBounds, ScreenUtil.getScreenRectangle(aScreenX + 1, aScreenY + 1), null);
}
if (getParent() == null) {
diff --git a/platform/platform-impl/src/com/intellij/ui/win/RecentProjectApplication.java b/platform/platform-impl/src/com/intellij/ui/win/RecentProjectApplication.java
index 9561c77b02d6..3ece5a6b77cd 100644
--- a/platform/platform-impl/src/com/intellij/ui/win/RecentProjectApplication.java
+++ b/platform/platform-impl/src/com/intellij/ui/win/RecentProjectApplication.java
@@ -17,6 +17,7 @@ package com.intellij.ui.win;
import com.intellij.ide.impl.ProjectUtil;
import com.intellij.openapi.diff.ApplicationStarterBase;
+import org.jetbrains.annotations.Nullable;
/**
@@ -33,7 +34,7 @@ public class RecentProjectApplication extends ApplicationStarterBase {
}
@Override
- protected void processCommand(String[] args) throws Exception {
+ protected void processCommand(String[] args, @Nullable String currentDirectory) throws Exception {
ProjectUtil.openProject(args[1], null, false);
}
} \ No newline at end of file
diff --git a/platform/platform-impl/src/com/intellij/util/IJSwingUtilities.java b/platform/platform-impl/src/com/intellij/util/IJSwingUtilities.java
index 60c5f90c8b73..bd0efda42c48 100644
--- a/platform/platform-impl/src/com/intellij/util/IJSwingUtilities.java
+++ b/platform/platform-impl/src/com/intellij/util/IJSwingUtilities.java
@@ -22,6 +22,7 @@ import com.intellij.ui.EditorTextField;
import com.intellij.ui.components.OrphanGuardian;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.FilteringIterator;
+import com.intellij.util.ui.JBSwingUtilities;
import com.intellij.util.ui.UIUtil;
import gnu.trove.TIntStack;
import org.jetbrains.annotations.NotNull;
@@ -34,7 +35,7 @@ import java.net.MalformedURLException;
import java.net.URL;
import java.util.Iterator;
-public class IJSwingUtilities {
+public class IJSwingUtilities extends JBSwingUtilities {
public static void invoke(Runnable runnable) {
if (ApplicationManager.getApplication().isDispatchThread()) {
runnable.run();
diff --git a/platform/platform-impl/src/org/jetbrains/io/ChannelRegistrar.java b/platform/platform-impl/src/org/jetbrains/io/ChannelRegistrar.java
index 5565e77a8cfb..179d2db5cf81 100644
--- a/platform/platform-impl/src/org/jetbrains/io/ChannelRegistrar.java
+++ b/platform/platform-impl/src/org/jetbrains/io/ChannelRegistrar.java
@@ -49,8 +49,8 @@ public final class ChannelRegistrar extends ChannelInboundHandlerAdapter {
}
finally {
if (eventLoopGroup != null) {
- eventLoopGroup.shutdownGracefully();
+ eventLoopGroup.shutdownGracefully(1, 2, TimeUnit.NANOSECONDS);
}
}
}
-} \ No newline at end of file
+}
diff --git a/platform/platform-resources-en/src/messages/ApplicationBundle.properties b/platform/platform-resources-en/src/messages/ApplicationBundle.properties
index 75d0f242e38c..42fd4e94be46 100644
--- a/platform/platform-resources-en/src/messages/ApplicationBundle.properties
+++ b/platform/platform-resources-en/src/messages/ApplicationBundle.properties
@@ -212,6 +212,8 @@ wrapping.parameters.annotation=Parameter annotations
wrapping.local.variables.annotation=Local variable annotations
wrapping.enum.constants=Enum constants
wrapping.long.lines=Ensure right margin is not exceeded
+wrapping.comments=Comments
+wrapping.comments.wrap.at.right.margin=Wrap at right margin
checkbox.align.multiline.chained.methods=Chained methods
checkbox.align.multiline.method.parameters=Method parameters
@@ -621,6 +623,7 @@ arrangement.settings.additional.force.rearrange.always=Always
arrangement.settings.additional.force.rearrange.never=Never
arrangement.settings.additional.force.rearrange.according.to.dialog=Use current mode (toggled in the Reformat Code dialog)
arrangement.settings.additional.title=Additional settings
+arrangement.settings.validation.duplicate.matching.rule=Matching rule have to be unique in the current settings. Duplicated rules will be ignored.
arrangement.settings.validation.duplicate.section.text=Section text have to be unique in the current settings. Rule with duplicated text will be ignored.
arrangement.settings.validation.empty.section.rule=Section should contain at least one arrangement entry otherwise it will be never inserted.
arrangement.settings.validation.end.section.rule.without.start=Can not find start section rule for the current end rule.
@@ -644,4 +647,10 @@ group.richcopy=Rich-text copy
combobox.richcopy.color.scheme=Color scheme
combobox.richcopy.color.scheme.active=Active scheme
-settings.code.style.default.general=Default (General) \ No newline at end of file
+settings.code.style.default.general=Default (General)
+wrapping.wrap.if.multiple.annotations=Wrap if multiple
+wrapping.after.annotations=After last field annotation
+
+reformat.changed.text.file.too.big.notification.groupId=Reformat changed text
+reformat.changed.text.file.too.big.notification.title=Couldn't calculate changed ranges
+reformat.changed.text.file.too.big.notification.text=file {0} is too big or there are too many changes \ No newline at end of file
diff --git a/platform/platform-resources-en/src/messages/ExecutionBundle.properties b/platform/platform-resources-en/src/messages/ExecutionBundle.properties
index 183dda3d52b8..508ac2ad2801 100644
--- a/platform/platform-resources-en/src/messages/ExecutionBundle.properties
+++ b/platform/platform-resources-en/src/messages/ExecutionBundle.properties
@@ -40,9 +40,12 @@ jre.not.valid.error.message=''{0}'' is not valid JRE home
applet.configuration.description=Applet configuration
applet.configuration.name=Applet
-application.configuration.description=Application configuration
+application.configuration.description=Java application configuration
application.configuration.name=Application
+jar.application.configuration.description=Configuration to run a JAR file using 'java -jar' command
+jar.application.configuration.name=JAR Application
+
run.configuration.norunner.selected.label=No runner selected
run.configuration.configuration.tab.title=Configuration
run.configuration.startup.connection.rab.title=Startup/Connection
@@ -132,10 +135,10 @@ junit.runing.info.errors.count.message=E:{0}
junit.runing.info.passed.count.message=P:{0}
junit.runing.info.ignored.count.message=I:{0}
-junit.runing.info.status.completed.from.total.failed={0} of {1} Failed: {2}
-junit.runing.info.status.completed.from.total={0} of {1}
-junit.runing.info.status.running.number.with.name=Running: {0} {1}
-junit.runing.info.failed.to.start.error.message=Failed to start
+junit.running.info.status.completed.from.total.failed={0} of {1} Failed: {2}
+junit.running.info.status.completed.from.total={0} of {1}
+junit.running.info.status.running.number.with.name=Running: {0} {1}
+junit.running.info.failed.to.start.error.message=Failed to start
junit.runing.info.tests.failed.label=Tests Failed
junit.runing.info.tests.passed.label=Tests Passed
tests.passed.with.warnings.message=Tests passed (with warnings)
@@ -274,8 +277,8 @@ environment.variables.helper.use.arguments.jdk13.label=<html><body>For JDK 1.3.x
environment.variables.helper.use.arguments.jdk14.label=<html><body>For JDK 1.4.x</body></html>
select.run.configuration.for.item.action.name=Select ''{0}''
save.run.configuration.for.item.action.name=Save ''{0}''
-junit.runing.info.status.done.count=Done: {0}
-junit.runing.info.status.terminated.count=Terminated: {0}
+junit.running.info.status.done.count=Done: {0}
+junit.running.info.status.terminated.count=Terminated: {0}
junit.runing.info.tests.in.progress.done.tree.node=Tests in Progress: Done
junit.runing.info.tests.in.progress.terminated.tre.node=Tests in Progress: Terminated
delete.confirmation.dialog.title=Delete Confirmation
diff --git a/platform/platform-resources-en/src/messages/FeatureStatisticsBundle.properties b/platform/platform-resources-en/src/messages/FeatureStatisticsBundle.properties
index 9a94f1f267bc..346399cfe60e 100644
--- a/platform/platform-resources-en/src/messages/FeatureStatisticsBundle.properties
+++ b/platform/platform-resources-en/src/messages/FeatureStatisticsBundle.properties
@@ -121,4 +121,4 @@ find.recent.search=Recent searches history
find.completion=Completion in Find Bar
switcher=Switcher
dir.diff=Directory Diff
-jar.diff=Jar Files Diff
+jar.diff=JAR Files Diff
diff --git a/platform/platform-resources-en/src/messages/IdeBundle.properties b/platform/platform-resources-en/src/messages/IdeBundle.properties
index 3b3773a07e06..2c0a81a8fcd0 100644
--- a/platform/platform-resources-en/src/messages/IdeBundle.properties
+++ b/platform/platform-resources-en/src/messages/IdeBundle.properties
@@ -641,6 +641,7 @@ checkbox.widescreen.tool.window.layout=Widescreen tool window layout
checkbox.left.toolwindow.layout=Side-by-side layout on the left
checkbox.right.toolwindow.layout=Side-by-side layout on the right
checkbox.show.editor.preview.popup=Show editor preview tooltip
+checkbox.use.preview.window=Navigate to preview
checkbox.show.tool.window.numbers=Show tool window numbers
checkbox.animate.windows=Animate windows
group.transparency=Transparency
@@ -941,10 +942,10 @@ predefined.scope.tests.name=Tests
scope.editor.legend.recursively.included.label=Recursively included
scope.editor.legend.partly.included.label=Partially included
toolwindow.palette=Palette
-jar.build.on.make=Build jars on &make
-jar.build.modules.to.jar=Choose Modules to Jar
-jar.build.module.0.jar.settings=Module ''{0}'' Jar Settings
-jar.build.include.in.jar.file=Include in jar file:
+jar.build.on.make=Build JARs on &make
+jar.build.modules.to.jar=Choose Modules to JAR
+jar.build.module.0.jar.settings=Module ''{0}'' JAR Settings
+jar.build.include.in.jar.file=Include in JAR file:
search.textfield.title=&Search:
select.in.scope=Scope
scope.view.title=Scopes
@@ -1018,7 +1019,7 @@ button.fix=Fix\u2026
setup.library.dialog.title=Setup Library
label.library.will.be.created.description.text={0} level library <b>{1}</b> with {2} {2, choice, 1#file|2#files} will be created
new.library.file.chooser.title=New Library Files
-new.library.file.chooser.description=Select jar files in which library classes are located
+new.library.file.chooser.description=Select JAR files in which library classes are located
create.default.library.type.action.name=Java
popup.title.select.library.type=Select Library Type
@@ -1141,8 +1142,9 @@ whatsnew.action.custom.text=What''s _New in {0}
whatsnew.action.custom.description=Find out about the new features in this version of {0}
diff.dialog.title=Diff Between ''{0}'' and ''{1}''
-goto.custom.region.command=Go to Custom Region
-goto.custom.region.message.dumb.mode=Go to Custom Region action is not available until indices are built.
+goto.custom.region.menu.item=Custom Folding Region...
+goto.custom.region.command=Go to Custom Folding Region
+goto.custom.region.message.dumb.mode=Go to Custom Folding Region action is not available until indices are built.
goto.custom.region.message.unavailable=There are no custom folding regions in the current file.
alphabetical.mode.is.on.warning=Alphabetical order for tabs is ON. Switch it OFF?
diff --git a/platform/platform-resources-en/src/messages/InspectionsBundle.properties b/platform/platform-resources-en/src/messages/InspectionsBundle.properties
index 98e0045a31f3..bccf8c48411f 100644
--- a/platform/platform-resources-en/src/messages/InspectionsBundle.properties
+++ b/platform/platform-resources-en/src/messages/InspectionsBundle.properties
@@ -116,6 +116,8 @@ inspection.redundant.throws.problem.descriptor2=The declared exception {0} is ne
inspection.equals.hashcode.display.name=equals() and hashCode() not paired
inspection.equals.hashcode.only.one.defined.problem.descriptor=Class has {0} defined but does not define {1}
+inspection.equals.hashcode.generate.equals.quickfix=Generate 'equals()'
+inspection.equals.hashcode.generate.hashcode.quickfix=Generate 'hashCode()'
inspection.1.5.display.name=Usages of API documented as @since 1.5 (1.6|1.7)
inspection.1.5.problem.descriptor=Usage of API documented as @since {0}+
diff --git a/platform/platform-resources-en/src/messages/OptionsBundle.properties b/platform/platform-resources-en/src/messages/OptionsBundle.properties
index 2c06b31b53f7..537dec1d8f92 100644
--- a/platform/platform-resources-en/src/messages/OptionsBundle.properties
+++ b/platform/platform-resources-en/src/messages/OptionsBundle.properties
@@ -198,31 +198,35 @@ options.xml.display.name=XML
settings.panel.title=Settings
-node.configurable.build.tools.display.name=Build Tools
-node.configurable.build.tools.settings.description=<html><body>\
- Default view for Build Tools
-
configurable.group.appearance.settings.display.name=Appearance and Behavior
configurable.group.appearance.settings.description=<html><body>\
- Default view for Appearance and Behavior
+ Personalize IntelliJ appearance and behavior: change themes and font size, tune the keymap,\
+ configure plugins and system settings, such as password policies, HTTP proxy, updates and more.
configurable.group.editor.settings.display.name=Editor
configurable.group.editor.settings.description=<html><body>\
- Default view for Editor
+ Personalize source code appearance by changing fonts, highlighting styles, indents, etc.\
+ Customize the Editor from line numbers, caret placement and tabs to source code inspections,\
+ setting up templates and file encodings.
configurable.group.project.settings.display.name=Current Project
configurable.group.project.settings.description=<html><body>\
Default view for Current Project
configurable.group.build.settings.display.name=Build, Execution, Deployment
configurable.group.build.settings.description=<html><body>\
- Default view for Build, Execution, Deployment
+ Configure you project integration with different build tools (Maven, Gradle or Gant),\
+ modify the default compiler settings, manage server access configurations, customize the Debugger behavior, etc.
+configurable.group.build.tools.settings.display.name=Build Tools
+configurable.group.build.tools.settings.description=<html><body>\
+ Configure your project integration with different build tools: Maven, Gradle or Gant.
configurable.group.language.settings.display.name=Languages and Frameworks
configurable.group.language.settings.description=<html><body>\
- Default view for Languages and Frameworks
+ Configure the settings related to specific frameworks and technologies used in your project.
configurable.group.tools.settings.display.name=Tools
configurable.group.tools.settings.description=<html><body>\
- Default view for Tools
+ Configure integration with third-party applications, specify the SSH Terminal connection settings,\
+ manage server certificates and tasks, configure diagrams layout, etc.
configurable.group.null.settings.display.name=Other Settings
configurable.group.null.settings.description=<html><body>\
- Default view for Other Settings
+ Settings that are related to non-bundled custom plugins and are not assigned to any other category.
configurable.default.project.tooltip=For default project
configurable.current.project.tooltip=For current project
diff --git a/platform/platform-resources-en/src/messages/RefactoringBundle.properties b/platform/platform-resources-en/src/messages/RefactoringBundle.properties
index 48d0e63d60c0..72b1cd7ad131 100644
--- a/platform/platform-resources-en/src/messages/RefactoringBundle.properties
+++ b/platform/platform-resources-en/src/messages/RefactoringBundle.properties
@@ -671,7 +671,7 @@ static.initializer.description=static initializer of class {0}
instance.initializer.description=instance initializer of class {0}
file.description=File {0}
directory.description=Directory {0}
-0.is.located.in.a.jar.file={0} is located in a jar file.\n
+0.is.located.in.a.jar.file={0} is located in a JAR file.\n
0.is.read.only={0} is read-only.\n
0.is.not.a.legal.java.identifier=''{0}'' is not a legal java identifier
method.0.is.already.defined.in.the.1=Method {0} is already defined in the {1}
diff --git a/platform/platform-resources-en/src/messages/UIBundle.properties b/platform/platform-resources-en/src/messages/UIBundle.properties
index 5dd72ae735b7..4f67ac6dcbf8 100644
--- a/platform/platform-resources-en/src/messages/UIBundle.properties
+++ b/platform/platform-resources-en/src/messages/UIBundle.properties
@@ -24,6 +24,7 @@ replace.prompt.replace.button=&Replace
replace.prompt.skip.button=&Skip
replace.prompt.all.in.this.file.button=All in This &File
replace.prompt.all.files.action=&All Files
+replace.prompt.review.action=Re&view
replace.prompt.all.button=&All
replace.prompt.replace.occurrence.label=Do you want to replace this occurrence?
search.popup.search.for.label=Search for:
diff --git a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml
index dcdc0e2d983c..2e2e0c80bb17 100644
--- a/platform/platform-resources/src/META-INF/LangExtensionPoints.xml
+++ b/platform/platform-resources/src/META-INF/LangExtensionPoints.xml
@@ -385,7 +385,8 @@
interface="com.intellij.execution.configurations.ConfigurationType"/>
<extensionPoint name="runConfigurationsSettings"
- interface="com.intellij.execution.configurations.RunConfigurationsSettings"/>
+ interface="com.intellij.execution.configurations.RunConfigurationsSettings"
+ area="IDEA_PROJECT"/>
<extensionPoint name="programRunner"
interface="com.intellij.execution.runners.ProgramRunner"/>
diff --git a/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml b/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml
index baea70a67c7a..00bd38430d68 100644
--- a/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml
+++ b/platform/platform-resources/src/META-INF/PlatformExtensionPoints.xml
@@ -10,7 +10,7 @@
interface="com.intellij.openapi.startup.StartupActivity"/>
<extensionPoint name="defaultProjectTypeProvider"
- interface="com.intellij.openapi.project.DefaultProjectTypeProvider"/>
+ beanClass="com.intellij.openapi.project.DefaultProjectTypeEP"/>
<extensionPoint name="errorHandler"
interface="com.intellij.openapi.diagnostic.ErrorReportSubmitter"/>
diff --git a/platform/platform-resources/src/META-INF/PlatformExtensions.xml b/platform/platform-resources/src/META-INF/PlatformExtensions.xml
index 51028d93edac..29dcf0645cef 100644
--- a/platform/platform-resources/src/META-INF/PlatformExtensions.xml
+++ b/platform/platform-resources/src/META-INF/PlatformExtensions.xml
@@ -151,6 +151,9 @@
<applicationService serviceImplementation="com.intellij.internal.statistic.UsageTrigger"/>
+ <applicationService serviceInterface="com.intellij.openapi.application.PathMacros"
+ serviceImplementation="com.intellij.application.options.PathMacrosImpl"/>
+
<projectService serviceInterface="com.intellij.openapi.vfs.ReadonlyStatusHandler"
serviceImplementation="com.intellij.openapi.vcs.readOnlyHandler.ReadonlyStatusHandlerImpl"/>
<projectService serviceInterface="com.intellij.openapi.startup.StartupManager"
diff --git a/platform/platform-resources/src/META-INF/VcsExtensions.xml b/platform/platform-resources/src/META-INF/VcsExtensions.xml
index 2322381c3b89..37fddfafbead 100644
--- a/platform/platform-resources/src/META-INF/VcsExtensions.xml
+++ b/platform/platform-resources/src/META-INF/VcsExtensions.xml
@@ -25,7 +25,8 @@
<selectInTarget implementation="com.intellij.openapi.vcs.changes.SelectInChangesViewTarget"/>
- <projectConfigurable groupId="project" groupWeight="110" dynamic="true" key="version.control.main.configurable.name" bundle="messages.VcsBundle" instance="com.intellij.openapi.vcs.configurable.VcsManagerConfigurable" id="vcs"/>
+ <projectConfigurable groupId="root" groupWeight="45" dynamic="true" key="version.control.main.configurable.name" bundle="messages.VcsBundle"
+ provider="com.intellij.openapi.vcs.configurable.VcsManagerConfigurableProvider" id="vcs"/>
<changesViewContent tabName="Repository" className="com.intellij.openapi.vcs.changes.committed.CommittedChangesViewManager"
predicateClassName="com.intellij.openapi.vcs.changes.committed.CommittedChangesVisibilityPredicate"/>
diff --git a/platform/platform-resources/src/META-INF/XmlPlugin.xml b/platform/platform-resources/src/META-INF/XmlPlugin.xml
index 566d674d0063..b6653d81eec7 100644
--- a/platform/platform-resources/src/META-INF/XmlPlugin.xml
+++ b/platform/platform-resources/src/META-INF/XmlPlugin.xml
@@ -548,7 +548,7 @@
</extensions>
<extensions defaultExtensionNs="org.jetbrains">
<urlOpener implementation="com.intellij.ide.browsers.impl.DefaultUrlOpener" order="last"/>
- <webServerPathHandler implementation="org.jetbrains.builtInWebServer.DefaultWebServerPathHandler"/>
+ <webServerPathHandler implementation="org.jetbrains.builtInWebServer.DefaultWebServerPathHandler" order="last"/>
<webServerFileHandler implementation="org.jetbrains.builtInWebServer.BuiltInWebServer$StaticFileHandler" order="last"/>
<webServerRootsProvider implementation="org.jetbrains.builtInWebServer.DefaultWebServerRootsProvider"/>
</extensions>
diff --git a/platform/platform-resources/src/META-INF/xdebugger.xml b/platform/platform-resources/src/META-INF/xdebugger.xml
index d28921d17ba6..821cb528b6a9 100644
--- a/platform/platform-resources/src/META-INF/xdebugger.xml
+++ b/platform/platform-resources/src/META-INF/xdebugger.xml
@@ -30,7 +30,8 @@
<projectService serviceInterface="com.intellij.xdebugger.impl.XDebuggerHistoryManager"
serviceImplementation="com.intellij.xdebugger.impl.XDebuggerHistoryManager"/>
- <applicationConfigurable groupId="build" dynamic="true" key="debugger.configurable.display.name" bundle="messages.XDebuggerBundle" instance="com.intellij.xdebugger.impl.settings.DebuggerConfigurable"/>
+ <applicationConfigurable groupId="build" dynamic="true" key="debugger.configurable.display.name" bundle="messages.XDebuggerBundle"
+ provider="com.intellij.xdebugger.impl.settings.DebuggerConfigurableProvider"/>
<customizableActionGroupProvider implementation="com.intellij.xdebugger.impl.ui.XDebugTabCustomizableActionGroupProvider"/>
diff --git a/platform/platform-resources/src/brokenPlugins.txt b/platform/platform-resources/src/brokenPlugins.txt
index 584c3a466615..55704f758841 100644
--- a/platform/platform-resources/src/brokenPlugins.txt
+++ b/platform/platform-resources/src/brokenPlugins.txt
@@ -8,7 +8,7 @@ com.jetbrains.twig 133.51 130.1639
org.jetbrains.plugins.ruby 7.0.0.20140807 6.0.0.20140207 6.5.2.20140512 7.0.0.20140704 7.0.0.20140707 7.0.0.20140724
Pythonid 3.1 4.0.25 4.0.26
Karma 138.317 138.21 134.1163 134.1039 134.686 134.31
-org.intellij.scala 0.42.28 0.42.23 0.40.20 0.40.18 0.40.16 0.32.593 0.32.562 0.32.558 0.32.550 0.32.520 0.32.512
+org.intellij.scala 1.0.16 1.0.14 1.0.13 0.42.28 0.42.23 0.40.20 0.40.18 0.40.16 0.32.593 0.32.562 0.32.558 0.32.550 0.32.520 0.32.512
org.jetbrains.kannotator 0.2.420
org.jetbrains.kotlin 0.7.1360 0.7.1376 0.8.7
SBT 1.0.0 1.1.0 1.2.0 1.3.0 1.3.1 1.4.0 1.5.0
diff --git a/platform/platform-resources/src/componentSets/Platform.xml b/platform/platform-resources/src/componentSets/Platform.xml
index 0e2e60d64fd7..9dd7590ac09e 100644
--- a/platform/platform-resources/src/componentSets/Platform.xml
+++ b/platform/platform-resources/src/componentSets/Platform.xml
@@ -70,11 +70,6 @@
</component>
<component>
- <interface-class>com.intellij.openapi.application.PathMacros</interface-class>
- <implementation-class>com.intellij.application.options.PathMacrosImpl</implementation-class>
- </component>
-
- <component>
<interface-class>com.intellij.ide.ui.LafManager</interface-class>
<implementation-class>com.intellij.ide.ui.laf.LafManagerImpl</implementation-class>
<headless-implementation-class>com.intellij.ide.ui.laf.HeadlessLafManagerImpl</headless-implementation-class>
diff --git a/platform/platform-resources/src/idea/LangActions.xml b/platform/platform-resources/src/idea/LangActions.xml
index 39957743629d..a9c204b1e6e7 100644
--- a/platform/platform-resources/src/idea/LangActions.xml
+++ b/platform/platform-resources/src/idea/LangActions.xml
@@ -709,7 +709,6 @@
<group id="XDebugger.ValueGroup" popup="false">
<reference ref="XDebugger.Inspect"/>
- <reference ref="Debugger.ShowReferring"/>
<reference ref="Debugger.MarkObject"/>
<reference ref="XDebugger.SetValue"/>
<reference ref="XDebugger.CopyValue"/>
@@ -719,6 +718,7 @@
<reference ref="EvaluateExpression"/>
<reference ref="Debugger.Tree.EvaluateInConsole"/>
<reference ref="Debugger.Tree.AddToWatches"/>
+ <reference ref="Debugger.ShowReferring"/>
<separator/>
<reference ref="XDebugger.JumpToSource"/>
<reference ref="XDebugger.JumpToTypeSource"/>
@@ -817,7 +817,8 @@
<action id="SendEOF" class="com.intellij.execution.actions.EOFAction" text="Send EOF"/>
<group>
- <action class="com.intellij.execution.testframework.actions.ViewAssertEqualsDiffAction" text="View assertEquals Difference" id="openAssertEqualsDiff"/>
+ <action class="com.intellij.execution.testframework.actions.ViewAssertEqualsDiffAction"
+ text="View assertEquals Difference" id="openAssertEqualsDiff" use-shortcut-of="CompareDirs"/>
<separator/>
<add-to-group anchor="first" group-id="TestTreePopupMenu"/>
</group>
diff --git a/platform/platform-resources/src/launcher.py b/platform/platform-resources/src/launcher.py
index 0a679eec98fe..440f716f8ebf 100644
--- a/platform/platform-resources/src/launcher.py
+++ b/platform/platform-resources/src/launcher.py
@@ -18,27 +18,19 @@ for i, arg in enumerate(sys.argv[1:]):
print(('Usage:\n' + \
' {0} -h |-? | --help\n' + \
' {0} [-l|--line line] file[:line]\n' + \
- ' {0} diff file1 file2').format(sys.argv[0]))
+ ' {0} diff <left> <right>' + \
+ ' {0} merge <local> <remote> [base] <merged>').format(sys.argv[0]))
exit(0)
- elif arg == 'diff' and i == 0:
- args.append(arg)
- elif arg == '-l' or arg == '--line':
- args.append(arg)
- skip_next = True
- elif skip_next:
- args.append(arg)
- skip_next = False
- else:
- if ':' in arg:
- file_path, line_number = arg.rsplit(':', 1)
- if line_number.isdigit():
- args.append('-l')
- args.append(line_number)
- args.append(os.path.abspath(file_path))
- else:
- args.append(os.path.abspath(arg))
+ elif ':' in arg:
+ file_path, line_number = arg.rsplit(':', 1)
+ if line_number.isdigit():
+ args.append('-l')
+ args.append(line_number)
+ args.append(file_path)
else:
- args.append(os.path.abspath(arg))
+ args.append(arg)
+ else:
+ args.append(arg)
def launch_with_port(port):
found = False
@@ -54,7 +46,6 @@ def launch_with_port(port):
try:
path_len = struct.unpack(">h", s.recv(2))[0]
path = s.recv(path_len)
- path = os.path.abspath(path)
if os.path.abspath(path) == os.path.abspath(CONFIG_PATH):
found = True
break
@@ -87,13 +78,5 @@ if port == -1:
else:
if launch_with_port(port): exit()
-if sys.platform == "darwin":
- # Mac OS: RUN_PATH is *.app path
- if len(args):
- args.insert(0, "--args")
- os.execvp("open", ["-a", RUN_PATH] + args)
-else:
- # unix common
- bin_dir, bin_file = os.path.split(RUN_PATH)
- os.chdir(bin_dir)
- os.execv(bin_file, [bin_file] + args)
+bin_dir, bin_file = os.path.split(RUN_PATH)
+os.execv(RUN_PATH, [bin_file] + args) \ No newline at end of file
diff --git a/platform/platform-tests/testData/codeStyle/autodetect/manyComments.java b/platform/platform-tests/testData/codeStyle/autodetect/manyComments.java
new file mode 100644
index 000000000000..7bc7a3a46982
--- /dev/null
+++ b/platform/platform-tests/testData/codeStyle/autodetect/manyComments.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+public interface Doable {
+
+
+ /*
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+ public void count() {
+ }
+
+
+ /*
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+ public void test() {
+ }
+}
diff --git a/platform/platform-tests/testData/codeStyle/autodetect/manyZeroRelativeIndent.java b/platform/platform-tests/testData/codeStyle/autodetect/manyZeroRelativeIndent.java
new file mode 100644
index 000000000000..2ee4c59848ec
--- /dev/null
+++ b/platform/platform-tests/testData/codeStyle/autodetect/manyZeroRelativeIndent.java
@@ -0,0 +1,31 @@
+class Test {
+
+ public void test() {
+ // boolean function-available(string)
+ addFunction(decls, new FunctionImpl("function-available", XPathType.BOOLEAN,
+ new Parameter(XPathType.STRING, Parameter.Kind.REQUIRED)));
+
+ // node-set current()
+ addFunction(decls, new FunctionImpl("current", XPathType.NODESET));
+
+ // EXSLT (http://www.exslt.org) extensions supported by Xalan & Saxon
+ addFunction(decls, EXSLT_DATE_TIME, new FunctionImpl("date", XPathType.STRING, optional_string));
+ addFunction(decls, EXSLT_DATE_TIME, new FunctionImpl("date-time", XPathType.STRING));
+ addFunction(decls, EXSLT_DATE_TIME, new FunctionImpl("day-abbreviation", XPathType.STRING, optional_string));
+ addFunction(decls, EXSLT_DATE_TIME, new FunctionImpl("day-in-month", XPathType.NUMBER, optional_string));
+ addFunction(decls, EXSLT_DATE_TIME, new FunctionImpl("day-in-week", XPathType.NUMBER, optional_string));
+ addFunction(decls, EXSLT_DATE_TIME, new FunctionImpl("day-in-year", XPathType.NUMBER, optional_string));
+ addFunction(decls, EXSLT_DATE_TIME, new FunctionImpl("day-name", XPathType.STRING, optional_string));
+ addFunction(decls, EXSLT_DATE_TIME, new FunctionImpl("day-of-week-in-month", XPathType.NUMBER, optional_string));
+ addFunction(decls, EXSLT_DATE_TIME, new FunctionImpl("hour-in-day", XPathType.NUMBER, optional_string));
+ addFunction(decls, EXSLT_DATE_TIME, new FunctionImpl("leap-year", XPathType.BOOLEAN, optional_string));
+ addFunction(decls, EXSLT_DATE_TIME, new FunctionImpl("minute-in-hour", XPathType.NUMBER, optional_string));
+ addFunction(decls, EXSLT_DATE_TIME, new FunctionImpl("month-abbreviation", XPathType.STRING, optional_string));
+ addFunction(decls, EXSLT_DATE_TIME, new FunctionImpl("month-in-year", XPathType.NUMBER, optional_string));
+ addFunction(decls, EXSLT_DATE_TIME, new FunctionImpl("month-name", XPathType.STRING, optional_string));
+ addFunction(decls, EXSLT_DATE_TIME, new FunctionImpl("second-in-minute", XPathType.NUMBER, optional_string));
+ addFunction(decls, EXSLT_DATE_TIME, new FunctionImpl("time", XPathType.STRING, optional_string));
+ addFunction(decls, EXSLT_DATE_TIME, new FunctionImpl("week-in-year", XPathType.NUMBER, optional_string));
+ addFunction(decls, EXSLT_DATE_TIME, new FunctionImpl("year", XPathType.NUMBER, optional_string));
+ }
+}
diff --git a/platform/platform-tests/testData/codeStyle/autodetect/simpleIndent.java b/platform/platform-tests/testData/codeStyle/autodetect/simpleIndent.java
new file mode 100644
index 000000000000..c4cd369df732
--- /dev/null
+++ b/platform/platform-tests/testData/codeStyle/autodetect/simpleIndent.java
@@ -0,0 +1,14 @@
+public class A {
+
+ public void test() {
+ int a = 2;
+ int c = 2;
+ int r = 3;
+ int rq = 3;
+ int rw = 3;
+ int re = 3;
+ }
+
+ public void a() {
+ }
+}
diff --git a/platform/platform-tests/testSrc/com/intellij/formatting/GeneralCodeFormatterTest.java b/platform/platform-tests/testSrc/com/intellij/formatting/GeneralCodeFormatterTest.java
index 7814e6e5f109..861a4b2c6e4b 100644
--- a/platform/platform-tests/testSrc/com/intellij/formatting/GeneralCodeFormatterTest.java
+++ b/platform/platform-tests/testSrc/com/intellij/formatting/GeneralCodeFormatterTest.java
@@ -109,7 +109,7 @@ import java.io.IOException;
indentOptions.INDENT_SIZE = 4;
indentOptions.LABEL_INDENT_SIZE = 1;
final CodeStyleSettings settings = new CodeStyleSettings(false);
- settings.RIGHT_MARGIN = myRightMargin;
+ settings.setDefaultRightMargin(myRightMargin);
try {
FormatterEx.getInstanceEx().adjustLineIndent(model, settings, indentOptions, initialText.length() - 1, new TextRange(0, initialText.length()));
}
@@ -200,7 +200,7 @@ import java.io.IOException;
indentOptions.INDENT_SIZE = 4;
indentOptions.LABEL_INDENT_SIZE = 1;
final CodeStyleSettings settings = new CodeStyleSettings(false);
- settings.RIGHT_MARGIN = myRightMargin;
+ settings.setDefaultRightMargin(myRightMargin);
try {
FormatterEx.getInstanceEx().format(model, settings, indentOptions, indentOptions, null);
}
diff --git a/platform/platform-tests/testSrc/com/intellij/ide/util/treeView/BaseTreeTestCase.java b/platform/platform-tests/testSrc/com/intellij/ide/util/treeView/BaseTreeTestCase.java
index 53be07ee2a7d..fc5c5edec615 100644
--- a/platform/platform-tests/testSrc/com/intellij/ide/util/treeView/BaseTreeTestCase.java
+++ b/platform/platform-tests/testSrc/com/intellij/ide/util/treeView/BaseTreeTestCase.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -87,7 +87,7 @@ abstract class BaseTreeTestCase<StructureElement> extends FlyIdeaTestCase {
void waitBuilderToCome() {
try {
- waitBuilderToCome(Condition.TRUE);
+ waitBuilderToCome(Conditions.alwaysTrue());
}
catch (Exception e) {
throw new AssertionError(e);
@@ -375,7 +375,7 @@ abstract class BaseTreeTestCase<StructureElement> extends FlyIdeaTestCase {
}
void doAndWaitForBuilder(final Runnable runnable) throws Exception {
- doAndWaitForBuilder(runnable, Condition.TRUE);
+ doAndWaitForBuilder(runnable, Conditions.alwaysTrue());
}
diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/components/impl/ApplicationStoreTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/components/impl/ApplicationStoreTest.java
index cfbd5a12f146..719635a19a30 100644
--- a/platform/platform-tests/testSrc/com/intellij/openapi/components/impl/ApplicationStoreTest.java
+++ b/platform/platform-tests/testSrc/com/intellij/openapi/components/impl/ApplicationStoreTest.java
@@ -7,13 +7,21 @@ import com.intellij.openapi.components.*;
import com.intellij.openapi.components.impl.stores.*;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.testFramework.LightPlatformLangTestCase;
import com.intellij.util.xmlb.XmlSerializerUtil;
+import gnu.trove.THashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assert.assertThat;
public class ApplicationStoreTest extends LightPlatformLangTestCase {
private File testAppConfig;
@@ -53,8 +61,73 @@ public class ApplicationStoreTest extends LightPlatformLangTestCase {
public void testStreamProviderSaveIfSeveralStoragesConfigured() throws Exception {
SeveralStoragesConfigured component = new SeveralStoragesConfigured();
+
+ MyStreamProvider streamProvider = new MyStreamProvider();
+ componentStore.getStateStorageManager().setStreamProvider(streamProvider);
+
componentStore.initComponent(component, false);
+ component.foo = "newValue";
StoreUtil.doSave(componentStore);
+
+ assertThat(streamProvider.data.get(RoamingType.PER_USER).get(StoragePathMacros.APP_CONFIG + "/proxy.settings.xml"), equalTo("<application>\n" +
+ " <component name=\"HttpConfigurable\">\n" +
+ " <option name=\"foo\" value=\"newValue\" />\n" +
+ " </component>\n" +
+ "</application>"));
+ }
+
+ public void testLoadFromStreamProvider() throws Exception {
+ SeveralStoragesConfigured component = new SeveralStoragesConfigured();
+
+ MyStreamProvider streamProvider = new MyStreamProvider();
+ THashMap<String, String> map = new THashMap<String, String>();
+ map.put(StoragePathMacros.APP_CONFIG + "/proxy.settings.xml", "<application>\n" +
+ " <component name=\"HttpConfigurable\">\n" +
+ " <option name=\"foo\" value=\"newValue\" />\n" +
+ " </component>\n" +
+ "</application>");
+ streamProvider.data.put(RoamingType.PER_USER, map);
+
+ componentStore.getStateStorageManager().setStreamProvider(streamProvider);
+ componentStore.initComponent(component, false);
+ assertThat(component.foo, equalTo("newValue"));
+ }
+
+ private static class MyStreamProvider extends StreamProvider {
+ public final Map<RoamingType, Map<String, String>> data = new THashMap<RoamingType, Map<String, String>>();
+
+ @Override
+ public void saveContent(@NotNull String fileSpec,
+ @NotNull byte[] content,
+ int size,
+ @NotNull RoamingType roamingType,
+ boolean async) {
+ getMap(roamingType).put(fileSpec, new String(content, 0, size, CharsetToolkit.UTF8_CHARSET));
+ }
+
+ private Map<String, String> getMap(@NotNull RoamingType roamingType) {
+ Map<String, String> map = data.get(roamingType);
+ if (map == null) {
+ map = new THashMap<String, String>();
+ data.put(roamingType, map);
+ }
+ return map;
+ }
+
+ @Nullable
+ @Override
+ public InputStream loadContent(@NotNull String fileSpec, @NotNull RoamingType roamingType) throws IOException {
+ String data = getMap(roamingType).get(fileSpec);
+ return data == null ? null : new ByteArrayInputStream(data.getBytes(CharsetToolkit.UTF8_CHARSET));
+ }
+
+ @Override
+ public void delete(@NotNull String fileSpec, @NotNull RoamingType roamingType) {
+ Map<String, String> map = data.get(roamingType);
+ if (map != null) {
+ map.remove(fileSpec);
+ }
+ }
}
class MyComponentStore extends ComponentStoreImpl implements Disposable {
@@ -88,7 +161,7 @@ public class ApplicationStoreTest extends LightPlatformLangTestCase {
}
};
- stateStorageManager.addMacro(StoragePathMacros.getMacroName(StoragePathMacros.APP_CONFIG), testAppConfigPath);
+ stateStorageManager.addMacro(StoragePathMacros.APP_CONFIG, testAppConfigPath);
}
@Override
@@ -141,7 +214,6 @@ public class ApplicationStoreTest extends LightPlatformLangTestCase {
@Nullable
@Override
public SeveralStoragesConfigured getState() {
- foo = "newValue";
return this;
}
diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/components/impl/StateStorageManagerImplTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/components/impl/StateStorageManagerImplTest.java
index 76c673626b26..da54b2a65e35 100644
--- a/platform/platform-tests/testSrc/com/intellij/openapi/components/impl/StateStorageManagerImplTest.java
+++ b/platform/platform-tests/testSrc/com/intellij/openapi/components/impl/StateStorageManagerImplTest.java
@@ -16,6 +16,7 @@
package com.intellij.openapi.components.impl;
import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.components.RoamingType;
import com.intellij.openapi.components.StateStorage;
import com.intellij.openapi.components.StateStorageException;
import com.intellij.openapi.components.StateStorageOperation;
@@ -55,7 +56,7 @@ public class StateStorageManagerImplTest extends LightPlatformLangTestCase {
return null;
}
};
- myStateStorageManager.addMacro("MACRO1", "/temp/m1");
+ myStateStorageManager.addMacro("$MACRO1$", "/temp/m1");
}
@Override
@@ -65,23 +66,23 @@ public class StateStorageManagerImplTest extends LightPlatformLangTestCase {
}
public void testCreateFileStateStorageMacroSubstituted() {
- StateStorage data = myStateStorageManager.getFileStateStorage("$MACRO1$/test.xml");
+ StateStorage data = myStateStorageManager.getStateStorage("$MACRO1$/test.xml", RoamingType.PER_USER);
assertThat(data, is(notNullValue()));
}
public void testCreateStateStorageAssertionThrownWhenUnknownMacro() {
try {
- myStateStorageManager.getFileStateStorage("$UNKNOWN_MACRO$/test.xml");
+ myStateStorageManager.getStateStorage("$UNKNOWN_MACRO$/test.xml", RoamingType.PER_USER);
fail("Exception expected");
}
catch (IllegalArgumentException e) {
- assertEquals("Unknown macro: $UNKNOWN_MACRO$ in storage spec: $UNKNOWN_MACRO$/test.xml", e.getMessage());
+ assertEquals("Unknown macro: $UNKNOWN_MACRO$ in storage file spec: $UNKNOWN_MACRO$/test.xml", e.getMessage());
}
}
public void testCreateFileStateStorageMacroSubstitutedWhenExpansionHas$() {
- myStateStorageManager.addMacro("DOLLAR_MACRO", "/temp/d$");
- StateStorage data = myStateStorageManager.getFileStateStorage("$DOLLAR_MACRO$/test.xml");
+ myStateStorageManager.addMacro("$DOLLAR_MACRO$", "/temp/d$");
+ StateStorage data = myStateStorageManager.getStateStorage("$DOLLAR_MACRO$/test.xml", RoamingType.PER_USER);
assertThat(data, is(notNullValue()));
}
}
diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/components/impl/XmlElementStorageTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/components/impl/XmlElementStorageTest.java
index eeffb44915db..414843f69d96 100644
--- a/platform/platform-tests/testSrc/com/intellij/openapi/components/impl/XmlElementStorageTest.java
+++ b/platform/platform-tests/testSrc/com/intellij/openapi/components/impl/XmlElementStorageTest.java
@@ -16,26 +16,26 @@
package com.intellij.openapi.components.impl;
import com.intellij.openapi.Disposable;
+import com.intellij.openapi.components.RoamingType;
import com.intellij.openapi.components.StateStorage;
import com.intellij.openapi.components.StateStorageException;
import com.intellij.openapi.components.TrackingPathMacroSubstitutor;
-import com.intellij.openapi.components.impl.stores.ComponentRoamingManager;
import com.intellij.openapi.components.impl.stores.ComponentVersionProvider;
import com.intellij.openapi.components.impl.stores.XmlElementStorage;
import com.intellij.openapi.util.Disposer;
import com.intellij.testFramework.LightPlatformLangTestCase;
-import com.intellij.util.io.fs.IFile;
-import org.jdom.Document;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import java.io.File;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
-import static com.intellij.openapi.util.JDOMBuilder.*;
+import static com.intellij.openapi.util.JDOMBuilder.attr;
+import static com.intellij.openapi.util.JDOMBuilder.tag;
/**
* @author mike
@@ -57,7 +57,7 @@ public class XmlElementStorageTest extends LightPlatformLangTestCase {
public void testGetStateSucceeded() throws Exception {
MyXmlElementStorage storage =
- new MyXmlElementStorage(document(tag("root", tag("component", attr("name", "test"), tag("foo")))), myParentDisposable);
+ new MyXmlElementStorage(tag("root", tag("component", attr("name", "test"), tag("foo"))), myParentDisposable);
Element state = storage.getState(this, "test", Element.class, null);
assertNotNull(state);
assertEquals("component", state.getName());
@@ -65,36 +65,36 @@ public class XmlElementStorageTest extends LightPlatformLangTestCase {
}
public void testGetStateNotSucceeded() throws Exception {
- MyXmlElementStorage storage = new MyXmlElementStorage(document(tag("root")), myParentDisposable);
+ MyXmlElementStorage storage = new MyXmlElementStorage(tag("root"), myParentDisposable);
Element state = storage.getState(this, "test", Element.class, null);
assertNull(state);
}
public void testSetStateOverridesOldState() throws Exception {
MyXmlElementStorage storage =
- new MyXmlElementStorage(document(tag("root", tag("component", attr("name", "test"), tag("foo")))), myParentDisposable);
+ new MyXmlElementStorage(tag("root", tag("component", attr("name", "test"), tag("foo"))), myParentDisposable);
Element newState = tag("component", attr("name", "test"), tag("bar"));
StateStorage.ExternalizationSession externalizationSession = storage.startExternalization();
externalizationSession.setState(this, "test", newState, null);
storage.startSave(externalizationSession).save();
- assertNotNull(storage.mySavedDocument);
- assertNotNull(storage.mySavedDocument.getRootElement().getChild("component").getChild("bar"));
- assertNull(storage.mySavedDocument.getRootElement().getChild("component").getChild("foo"));
+ assertNotNull(storage.mySavedElement);
+ assertNotNull(storage.mySavedElement.getChild("component").getChild("bar"));
+ assertNull(storage.mySavedElement.getChild("component").getChild("foo"));
}
private class MyXmlElementStorage extends XmlElementStorage {
- private final Document myDocument;
- private Document mySavedDocument;
+ private final Element myElement;
+ private Element mySavedElement;
- public MyXmlElementStorage(final Document document, final Disposable parentDisposable) throws StateStorageException {
- super(new MyPathMacroManager(), parentDisposable, "root", null, "", ComponentRoamingManager.getInstance(), ComponentVersionProvider.EMPTY);
- myDocument = document;
+ public MyXmlElementStorage(Element element, final Disposable parentDisposable) throws StateStorageException {
+ super("", RoamingType.PER_USER, new MyPathMacroManager(), parentDisposable, "root", null, ComponentVersionProvider.EMPTY);
+ myElement = element;
}
@Override
- protected Document loadDocument() throws StateStorageException {
- return myDocument;
+ protected Element loadLocalData() {
+ return myElement;
}
@Override
@@ -102,41 +102,42 @@ public class XmlElementStorageTest extends LightPlatformLangTestCase {
return new MySaveSession(externalizationSession) {
@Override
protected void doSave() throws StateStorageException {
- mySavedDocument = getDocumentToSave().clone();
+ Element elementToSave = getElementToSave();
+ mySavedElement = elementToSave == null ? null : elementToSave.clone();
}
@NotNull
@Override
- public Collection<IFile> getStorageFilesToSave() throws StateStorageException {
- return needsSave() ? getAllStorageFiles() : Collections.<IFile>emptyList();
+ public Collection<File> getStorageFilesToSave() throws StateStorageException {
+ return needsSave() ? getAllStorageFiles() : Collections.<File>emptyList();
}
@NotNull
@Override
- public List<IFile> getAllStorageFiles() {
+ public List<File> getAllStorageFiles() {
throw new UnsupportedOperationException("Method getAllStorageFiles not implemented in " + getClass());
}
-
};
}
}
private static class MyPathMacroManager implements TrackingPathMacroSubstitutor {
@Override
- public void expandPaths(final Element element) {
+ public void expandPaths(@NotNull final Element element) {
}
@Override
public void reset() {
}
+ @NotNull
@Override
- public Collection<String> getComponents(Collection<String> macros) {
+ public Collection<String> getComponents(@NotNull Collection<String> macros) {
return Collections.emptyList();
}
@Override
- public void collapsePaths(final Element element) {
+ public void collapsePaths(@NotNull final Element element) {
}
@Override
@@ -149,17 +150,18 @@ public class XmlElementStorageTest extends LightPlatformLangTestCase {
throw new UnsupportedOperationException("Method collapsePath not implemented in " + getClass());
}
+ @NotNull
@Override
public Collection<String> getUnknownMacros(final String componentName) {
return Collections.emptySet();
}
@Override
- public void invalidateUnknownMacros(Set<String> macros) {
+ public void invalidateUnknownMacros(@NotNull Set<String> macros) {
}
@Override
- public void addUnknownMacros(String componentName, Collection<String> unknownMacros) {
+ public void addUnknownMacros(@NotNull String componentName, @NotNull Collection<String> unknownMacros) {
}
}
}
diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/progress/util/ProgressIndicatorTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/progress/util/ProgressIndicatorTest.java
new file mode 100644
index 000000000000..6e0201628a51
--- /dev/null
+++ b/platform/platform-tests/testSrc/com/intellij/openapi/progress/util/ProgressIndicatorTest.java
@@ -0,0 +1,329 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.openapi.progress.util;
+
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.ModalityState;
+import com.intellij.openapi.application.ex.ApplicationManagerEx;
+import com.intellij.openapi.progress.*;
+import com.intellij.openapi.progress.impl.ProgressManagerImpl;
+import com.intellij.openapi.wm.ex.ProgressIndicatorEx;
+import com.intellij.testFramework.LightPlatformTestCase;
+import com.intellij.testFramework.PlatformTestUtil;
+import com.intellij.util.Alarm;
+import com.intellij.util.containers.DoubleArrayList;
+import com.intellij.util.containers.Stack;
+import com.intellij.util.ui.UIUtil;
+import gnu.trove.TLongArrayList;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * @author yole
+ */
+public class ProgressIndicatorTest extends LightPlatformTestCase {
+ public void testCheckCanceledHasNoStackFrame() {
+ ProgressIndicatorBase pib = new ProgressIndicatorBase();
+ pib.cancel();
+ boolean hadException = false;
+ try {
+ pib.checkCanceled();
+ }
+ catch(ProcessCanceledException ex) {
+ hadException = true;
+ assertTrue("Should have no stackframe", ex.getStackTrace().length == 0);
+ }
+ assertTrue("Please restore ProgressIndicatorBase.checkCanceled() check!", hadException);
+ }
+
+ public void testProgressManagerCheckCanceledWorksRightAfterIndicatorBeenCanceled() {
+ for (int i=0; i<1000;i++) {
+ final ProgressIndicatorBase indicator = new ProgressIndicatorBase();
+ ProgressManager.getInstance().runProcess(new Runnable() {
+ @Override
+ public void run() {
+ ProgressManager.checkCanceled();
+ try {
+ indicator.cancel();
+ ProgressManager.checkCanceled();
+ fail("checkCanceled() must have caught just canceled indicator");
+ }
+ catch (ProcessCanceledException ignored) {
+ }
+ }
+ }, indicator);
+ }
+ }
+
+ private volatile long prevTime;
+ private volatile long now;
+ public void testCheckCanceledGranularity() throws InterruptedException {
+ prevTime = now = 0;
+ final long warmupEnd = System.currentTimeMillis() + 1000;
+ final TLongArrayList times = new TLongArrayList();
+ final long end = warmupEnd + 1000;
+
+ ApplicationManagerEx.getApplicationEx().runProcessWithProgressSynchronously(new Runnable() {
+ @Override
+ public void run() {
+ final Alarm alarm = new Alarm(Alarm.ThreadToUse.OWN_THREAD, getTestRootDisposable());
+ ProgressIndicatorEx indicator = (ProgressIndicatorEx)ProgressIndicatorProvider.getGlobalProgressIndicator();
+ prevTime = System.currentTimeMillis();
+ assert indicator != null;
+ indicator.addStateDelegate(new ProgressIndicatorStub() {
+ @Override
+ public void checkCanceled() throws ProcessCanceledException {
+ now = System.currentTimeMillis();
+ if (now > warmupEnd) {
+ int delta = (int)(now - prevTime);
+ times.add(delta);
+ }
+ prevTime = now;
+ }
+ });
+ while (System.currentTimeMillis() < end) {
+ ProgressManager.checkCanceled();
+ }
+ alarm.cancelAllRequests();
+ }
+ }, "", false, getProject(), null, "");
+ long averageDelay = PlatformTestUtil.averageAmongMedians(times.toNativeArray(), 5);
+ System.out.println("averageDelay = " + averageDelay);
+ assertTrue(averageDelay < ProgressManagerImpl.CHECK_CANCELED_DELAY_MILLIS*3);
+ }
+
+ public void testProgressIndicatorUtils() throws Throwable {
+ final AtomicBoolean run = new AtomicBoolean(true);
+ final AtomicBoolean insideReadAction = new AtomicBoolean();
+ final AtomicReference<Throwable> exception = new AtomicReference<Throwable>();
+ final ProgressIndicatorBase indicator = new ProgressIndicatorBase();
+ ProgressIndicatorUtils.scheduleWithWriteActionPriority(indicator, new ReadTask() {
+ @Override
+ public void computeInReadAction(@NotNull ProgressIndicator indicator) {
+ insideReadAction.set(true);
+ while (run.get()) {
+ ProgressManager.checkCanceled();
+ }
+ }
+
+ @Override
+ public void onCanceled(@NotNull ProgressIndicator indicator) {
+ try {
+ assertTrue(run.get()); // cancel should happen early
+ run.set(false);
+ }
+ catch (Throwable e) {
+ exception.set(e);
+ }
+ }
+ });
+ UIUtil.dispatchAllInvocationEvents();
+ while (!insideReadAction.get()) {
+ ;
+ }
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ assertTrue(indicator.isCanceled());
+ }
+ catch (Throwable e) {
+ exception.set(e);
+ }
+ }
+ });
+ assertFalse(run.get());
+ if (exception.get() != null) throw exception.get();
+ }
+
+ private static class ProgressIndicatorStub implements ProgressIndicatorEx {
+ @Override
+ public void addStateDelegate(@NotNull ProgressIndicatorEx delegate) {
+
+ }
+
+ @Override
+ public boolean isModalityEntered() {
+ return false;
+ }
+
+ @Override
+ public void finish(@NotNull TaskInfo task) {
+
+ }
+
+ @Override
+ public boolean isFinished(@NotNull TaskInfo task) {
+ return false;
+ }
+
+ @Override
+ public boolean wasStarted() {
+ return false;
+ }
+
+ @Override
+ public void processFinish() {
+
+ }
+
+ @Override
+ public void initStateFrom(@NotNull ProgressIndicator indicator) {
+
+ }
+
+ @NotNull
+ @Override
+ public Stack<String> getTextStack() {
+ return null;
+ }
+
+ @NotNull
+ @Override
+ public DoubleArrayList getFractionStack() {
+ return null;
+ }
+
+ @NotNull
+ @Override
+ public Stack<String> getText2Stack() {
+ return null;
+ }
+
+ @Override
+ public int getNonCancelableCount() {
+ return 0;
+ }
+
+ @Override
+ public void start() {
+
+ }
+
+ @Override
+ public void stop() {
+
+ }
+
+ @Override
+ public boolean isRunning() {
+ return false;
+ }
+
+ @Override
+ public void cancel() {
+
+ }
+
+ @Override
+ public boolean isCanceled() {
+ return false;
+ }
+
+ @Override
+ public void setText(String text) {
+
+ }
+
+ @Override
+ public String getText() {
+ return null;
+ }
+
+ @Override
+ public void setText2(String text) {
+
+ }
+
+ @Override
+ public String getText2() {
+ return null;
+ }
+
+ @Override
+ public double getFraction() {
+ return 0;
+ }
+
+ @Override
+ public void setFraction(double fraction) {
+
+ }
+
+ @Override
+ public void pushState() {
+
+ }
+
+ @Override
+ public void popState() {
+
+ }
+
+ @Override
+ public void startNonCancelableSection() {
+
+ }
+
+ @Override
+ public void finishNonCancelableSection() {
+
+ }
+
+ @Override
+ public boolean isModal() {
+ return false;
+ }
+
+ @NotNull
+ @Override
+ public ModalityState getModalityState() {
+ return null;
+ }
+
+ @Override
+ public void setModalityProgress(ProgressIndicator modalityProgress) {
+
+ }
+
+ @Override
+ public boolean isIndeterminate() {
+ return false;
+ }
+
+ @Override
+ public void setIndeterminate(boolean indeterminate) {
+
+ }
+
+ @Override
+ public void checkCanceled() throws ProcessCanceledException {
+
+ }
+
+ @Override
+ public boolean isPopupWasShown() {
+ return false;
+ }
+
+ @Override
+ public boolean isShowing() {
+ return false;
+ }
+ }
+}
diff --git a/platform/platform-tests/testSrc/com/intellij/psi/autodetect/IndentAutoDetectionTest.java b/platform/platform-tests/testSrc/com/intellij/psi/autodetect/IndentAutoDetectionTest.java
new file mode 100644
index 000000000000..4b59416de0d9
--- /dev/null
+++ b/platform/platform-tests/testSrc/com/intellij/psi/autodetect/IndentAutoDetectionTest.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.psi.autodetect;
+
+import com.intellij.openapi.editor.Document;
+import com.intellij.psi.codeStyle.autodetect.*;
+import com.intellij.testFramework.LightPlatformCodeInsightTestCase;
+import com.intellij.testFramework.PlatformTestCase;
+import com.intellij.testFramework.PlatformTestUtil;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Assert;
+
+import java.io.File;
+import java.util.List;
+
+public class IndentAutoDetectionTest extends LightPlatformCodeInsightTestCase {
+ private static final String BASE_PATH = "codeStyle/autodetect/";
+
+ static {
+ PlatformTestCase.initPlatformLangPrefix();
+ }
+
+ public void testSimpleIndent() {
+ doTestMaxUsedIndent(2, 6);
+ }
+
+ public void testManyComments() {
+ doTestMaxUsedIndent(2, 6);
+ }
+
+ public void testManyZeroRelativeIndent() {
+ doTestMaxUsedIndent(2);
+ }
+
+ public void testSpacesToNumbers() throws Exception {
+ String text = " i\n" +
+ " a\n" +
+ " t\n";
+ doTestLineToIndentMapping(text, 5, 4, 10);
+ }
+
+ public void testEmptyLines() throws Exception {
+ doTestLineToIndentMapping(" \n\n\n", -1, -1, -1);
+ }
+
+ public void testSpacesInSimpleClass() {
+ doTestLineToIndentMapping(
+ "public class A {\n" +
+ "\n" +
+ " public void test() {\n" +
+ " int a = 2;\n" +
+ " }\n" +
+ "\n" +
+ " public void a() {\n" +
+ " }\n" +
+ "}",
+ 0, -1, 4, 6, 4, -1, 4, 4, 0
+ );
+ }
+
+ public void testComplexIndents() {
+ doTestLineToIndentMapping(
+ "class Test\n" +
+ "{\n" +
+ " int a;\n" +
+ " int b;\n" +
+ " \n" +
+ " public void test() {\n" +
+ " int c;\n" +
+ " }\n" +
+ " \n" +
+ " public void run() {\n" +
+ " Runnable runnable = new Runnable() {\n" +
+ " @Override\n" +
+ " public void run() {\n" +
+ " System.out.println(\"Hello!\");\n" +
+ " }\n" +
+ " };\n" +
+ " }\n" +
+ "}",
+ 0, 0, 2, 2, -1, 2, 4, 2, -1, 2, 4, 6, 6, 8, 6, 4, 2, 0
+ );
+ }
+
+ public void doTestMaxUsedIndent(int indentExpected, int timesUsedExpected) {
+ IndentUsageInfo maxIndentExpected = new IndentUsageInfo(indentExpected, timesUsedExpected);
+ IndentUsageInfo indentInfo = getMaxUsedIndentInfo();
+ Assert.assertEquals("Indent size mismatch", maxIndentExpected.getIndentSize(), indentInfo.getIndentSize());
+ Assert.assertEquals("Indent size usage number mismatch", maxIndentExpected.getTimesUsed(), indentInfo.getTimesUsed());
+ }
+
+ public void doTestMaxUsedIndent(int indentExpected) {
+ IndentUsageInfo indentInfo = getMaxUsedIndentInfo();
+ Assert.assertEquals("Indent size mismatch", indentExpected, indentInfo.getIndentSize());
+ }
+
+ @NotNull
+ private IndentUsageInfo getMaxUsedIndentInfo() {
+ configureByFile(getTestName(true) + ".java");
+ Document document = getDocument(myFile);
+ List<LineIndentInfo> lines = new LineIndentInfoBuilder(document.getCharsSequence()).build();
+ IndentUsageStatistics statistics = new IndentUsageStatisticsImpl(lines);
+ return statistics.getKMostUsedIndentInfo(0);
+ }
+
+ private static void doTestLineToIndentMapping(@NotNull CharSequence text, int... spacesForLine) {
+ List<LineIndentInfo> list = new LineIndentInfoBuilder(text).build();
+ Assert.assertEquals(list.size(), spacesForLine.length);
+ for (int i = 0; i < spacesForLine.length; i++) {
+ int indentSize = list.get(i).getIndentSize();
+ Assert.assertEquals("Mismatch on line " + i, spacesForLine[i], indentSize);
+ }
+ }
+
+ @Override
+ @NotNull
+ public String getTestDataPath() {
+ return PlatformTestUtil.getCommunityPath().replace(File.separatorChar, '/')
+ + "/platform/platform-tests/testData/"
+ + BASE_PATH;
+ }
+}
diff --git a/platform/projectModel-api/src/com/intellij/openapi/application/PathMacros.java b/platform/projectModel-api/src/com/intellij/openapi/application/PathMacros.java
index 160aed545b03..fac4e5e9edb1 100644
--- a/platform/projectModel-api/src/com/intellij/openapi/application/PathMacros.java
+++ b/platform/projectModel-api/src/com/intellij/openapi/application/PathMacros.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,15 +15,15 @@
*/
package com.intellij.openapi.application;
+import com.intellij.openapi.components.ServiceManager;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.Set;
public abstract class PathMacros {
-
public static PathMacros getInstance() {
- return ApplicationManager.getApplication().getComponent(PathMacros.class);
+ return ServiceManager.getService(PathMacros.class);
}
public abstract Set<String> getAllMacroNames();
@@ -33,9 +33,7 @@ public abstract class PathMacros {
public abstract void setMacro(String name, String value);
/**
- * Obsolete macros that are to be removed gently from the project files. They can be read, but not written again. Not persisted.
- * @param name
- * @param value
+ * Obsolete macros that are to be removed gently from the project files. They can be read, but not written again. Not persisted
*/
public abstract void addLegacyMacro(@NotNull String name, @NotNull String value);
diff --git a/platform/projectModel-api/src/com/intellij/openapi/components/LastStorageChooserForWrite.java b/platform/projectModel-api/src/com/intellij/openapi/components/LastStorageChooserForWrite.java
new file mode 100644
index 000000000000..f9206dee03e3
--- /dev/null
+++ b/platform/projectModel-api/src/com/intellij/openapi/components/LastStorageChooserForWrite.java
@@ -0,0 +1,10 @@
+package com.intellij.openapi.components;
+
+public final class LastStorageChooserForWrite implements StateStorageChooser<Object> {
+ public static final LastStorageChooserForWrite INSTANCE = new LastStorageChooserForWrite();
+
+ @Override
+ public Storage[] selectStorages(Storage[] storages, Object component, StateStorageOperation operation) {
+ return operation == StateStorageOperation.WRITE ? new Storage[]{storages[storages.length - 1]} : storages;
+ }
+} \ No newline at end of file
diff --git a/platform/projectModel-api/src/com/intellij/openapi/components/State.java b/platform/projectModel-api/src/com/intellij/openapi/components/State.java
index ec6b97055a48..38af50e27196 100644
--- a/platform/projectModel-api/src/com/intellij/openapi/components/State.java
+++ b/platform/projectModel-api/src/com/intellij/openapi/components/State.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,14 +23,15 @@ import java.lang.annotation.RetentionPolicy;
public @interface State {
String name();
+ @Deprecated
/**
- * {@link RoamingType#GLOBAL} will be ignored, use only {@link RoamingType#DISABLED} or {@link RoamingType#PER_PLATFORM}
+ * @deprecated Use {@link Storage#roamingType()}
*/
RoamingType roamingType() default RoamingType.PER_USER;
Storage[] storages();
- Class<? extends StateStorageChooser> storageChooser() default StorageAnnotationsDefaultValues.NullStateStorageChooser.class;
+ Class<? extends StateStorageChooser> storageChooser() default StateStorageChooser.class;
boolean reloadable() default true;
-} \ No newline at end of file
+}
diff --git a/platform/projectModel-api/src/com/intellij/openapi/components/StateStorage.java b/platform/projectModel-api/src/com/intellij/openapi/components/StateStorage.java
index 36112e5dc028..ef68ac1e3a7f 100644
--- a/platform/projectModel-api/src/com/intellij/openapi/components/StateStorage.java
+++ b/platform/projectModel-api/src/com/intellij/openapi/components/StateStorage.java
@@ -19,11 +19,11 @@ package com.intellij.openapi.components;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileEvent;
-import com.intellij.util.io.fs.IFile;
import com.intellij.util.messages.Topic;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import java.io.File;
import java.util.Collection;
import java.util.List;
import java.util.Set;
@@ -32,13 +32,16 @@ public interface StateStorage {
Topic<Listener> STORAGE_TOPIC = new Topic<Listener>("STORAGE_LISTENER", Listener.class, Topic.BroadcastDirection.TO_PARENT);
@Nullable
- <T> T getState(final Object component, final String componentName, Class<T> stateClass, @Nullable T mergeInto) throws StateStorageException;
- boolean hasState(final Object component, final String componentName, final Class<?> aClass, final boolean reloadData) throws StateStorageException;
+ <T> T getState(final Object component, @NotNull String componentName, Class<T> stateClass, @Nullable T mergeInto) throws StateStorageException;
+
+ boolean hasState(final Object component, @NotNull String componentName, final Class<?> aClass, final boolean reloadData) throws StateStorageException;
@NotNull
ExternalizationSession startExternalization();
+
@NotNull
SaveSession startSave(@NotNull ExternalizationSession externalizationSession);
+
void finishSave(@NotNull SaveSession saveSession);
void reload(@NotNull Set<String> changedComponents) throws StateStorageException;
@@ -51,13 +54,13 @@ public interface StateStorage {
void save() throws StateStorageException;
@Nullable
- Set<String> analyzeExternalChanges(@NotNull Set<Pair<VirtualFile,StateStorage>> changedFiles);
+ Set<String> analyzeExternalChanges(@NotNull Set<Pair<VirtualFile, StateStorage>> changedFiles);
@NotNull
- Collection<IFile> getStorageFilesToSave() throws StateStorageException;
+ Collection<File> getStorageFilesToSave() throws StateStorageException;
@NotNull
- List<IFile> getAllStorageFiles();
+ List<File> getAllStorageFiles();
}
interface Listener {
diff --git a/platform/projectModel-api/src/com/intellij/openapi/components/Storage.java b/platform/projectModel-api/src/com/intellij/openapi/components/Storage.java
index e10b97755d3a..f9ad4155b2c2 100644
--- a/platform/projectModel-api/src/com/intellij/openapi/components/Storage.java
+++ b/platform/projectModel-api/src/com/intellij/openapi/components/Storage.java
@@ -28,6 +28,11 @@ public @interface Storage {
@NonNls String file() default "";
StorageScheme scheme() default StorageScheme.DEFAULT;
- Class<? extends StateStorage> storageClass() default StorageAnnotationsDefaultValues.NullStateStorage.class;
- Class<? extends StateSplitter> stateSplitter() default StorageAnnotationsDefaultValues.NullStateSplitter.class;
+ /**
+ * You must not store components with different roaming types in one file ({@link #file()}).
+ */
+ RoamingType roamingType() default RoamingType.PER_USER;
+
+ Class<? extends StateStorage> storageClass() default StateStorage.class;
+ Class<? extends StateSplitter> stateSplitter() default StateSplitter.class;
}
diff --git a/platform/projectModel-api/src/com/intellij/openapi/components/StorageAnnotationsDefaultValues.java b/platform/projectModel-api/src/com/intellij/openapi/components/StorageAnnotationsDefaultValues.java
deleted file mode 100644
index 5105105c4eb4..000000000000
--- a/platform/projectModel-api/src/com/intellij/openapi/components/StorageAnnotationsDefaultValues.java
+++ /dev/null
@@ -1,87 +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.openapi.components;
-
-import com.intellij.openapi.util.Pair;
-import org.jdom.Element;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.List;
-import java.util.Set;
-
-public interface StorageAnnotationsDefaultValues {
- class NullStateStorage implements StateStorage {
- @Override
- @Nullable
- public <T> T getState(final Object component, final String componentName, Class<T> stateClass, @Nullable T mergeInto)
- throws StateStorageException {
- throw new UnsupportedOperationException("Method getState is not supported in " + getClass());
- }
-
- @Override
- public boolean hasState(final Object component, final String componentName, final Class<?> aClass, final boolean reloadData) throws StateStorageException {
- throw new UnsupportedOperationException("Method hasState not implemented in " + getClass());
- }
-
- public void save() throws StateStorageException {
- throw new UnsupportedOperationException("Method save is not supported in " + getClass());
- }
-
- @Override
- @NotNull
- public ExternalizationSession startExternalization() {
- throw new UnsupportedOperationException("Method startExternalization not implemented in " + getClass());
- }
-
- @Override
- @NotNull
- public SaveSession startSave(@NotNull ExternalizationSession externalizationSession) {
- throw new UnsupportedOperationException("Method startSave not implemented in " + getClass());
- }
-
- @Override
- public void finishSave(@NotNull SaveSession saveSession) {
- throw new UnsupportedOperationException("Method finishSave not implemented in " + getClass());
- }
-
- @Override
- public void reload(@NotNull final Set<String> changedComponents) throws StateStorageException {
- throw new UnsupportedOperationException("Method reload not implemented in " + getClass());
- }
-
- }
-
- class NullStateStorageChooser implements StateStorageChooser {
- @Override
- public Storage[] selectStorages(Storage[] storages, Object component, final StateStorageOperation operation) {
- throw new UnsupportedOperationException("Method selectStorages is not supported in " + getClass());
- }
- }
-
- class NullStateSplitter implements StateSplitter {
- @Override
- public List<Pair<Element, String>> splitState(Element e) {
- throw new UnsupportedOperationException("Method splitState not implemented in " + getClass());
- }
-
- @Override
- public void mergeStatesInto(final Element target, final Element[] elements) {
- throw new UnsupportedOperationException("Method mergeStatesInto not implemented in " + getClass());
- }
- }
-}
diff --git a/platform/projectModel-api/src/com/intellij/openapi/components/StoragePathMacros.java b/platform/projectModel-api/src/com/intellij/openapi/components/StoragePathMacros.java
index 374423225694..3a292dd7175c 100644
--- a/platform/projectModel-api/src/com/intellij/openapi/components/StoragePathMacros.java
+++ b/platform/projectModel-api/src/com/intellij/openapi/components/StoragePathMacros.java
@@ -31,9 +31,14 @@ import org.jetbrains.annotations.NotNull;
* @since 5/2/12 12:57 PM
*/
public class StoragePathMacros {
+ /**
+ * Points to the application-level settings root directory.
+ */
@NonNls @NotNull public static final String ROOT_CONFIG = "$ROOT_CONFIG$";
- /** Points to the application-level settings root directory. */
+ /**
+ * Points to {@link #ROOT_CONFIG}/options by default. Should be used to store single files and {@link #ROOT_CONFIG} to store subdirectories with many files.
+ */
@NonNls @NotNull public static final String APP_CONFIG = "$APP_CONFIG$";
/** <code>'.ipr'</code> file path key. */
@@ -63,6 +68,7 @@ public class StoragePathMacros {
* @throws IllegalArgumentException if given macro definition has unexpected format
*/
@NotNull
+ @Deprecated
public static String getMacroName(@NotNull String macro) throws IllegalArgumentException {
if (macro.length() < 3 || macro.charAt(0) != '$' || macro.charAt(macro.length() - 1) != '$') {
throw new IllegalArgumentException("Malformed macro definition (" + macro + ")");
diff --git a/platform/projectModel-api/src/com/intellij/openapi/project/DefaultProjectTypeProvider.java b/platform/projectModel-api/src/com/intellij/openapi/project/DefaultProjectTypeEP.java
index 81887eba0f98..3eb65af697c0 100644
--- a/platform/projectModel-api/src/com/intellij/openapi/project/DefaultProjectTypeProvider.java
+++ b/platform/projectModel-api/src/com/intellij/openapi/project/DefaultProjectTypeEP.java
@@ -16,20 +16,21 @@
package com.intellij.openapi.project;
import com.intellij.openapi.extensions.ExtensionPointName;
+import com.intellij.util.xmlb.annotations.Attribute;
import org.jetbrains.annotations.Nullable;
/**
* @author Dmitry Avdeev
*/
-public abstract class DefaultProjectTypeProvider {
+public class DefaultProjectTypeEP {
- private final static ExtensionPointName<DefaultProjectTypeProvider> EXTENSION_POINT_NAME = ExtensionPointName.create("com.intellij.defaultProjectTypeProvider");
+ private final static ExtensionPointName<DefaultProjectTypeEP> EXTENSION_POINT_NAME = ExtensionPointName.create("com.intellij.defaultProjectTypeProvider");
+ @Attribute("type")
+ public String type;
@Nullable
public static ProjectType getDefaultProjectType() {
- DefaultProjectTypeProvider[] extensions = EXTENSION_POINT_NAME.getExtensions();
- return extensions.length > 0 ? extensions[0].getProjectType() : null;
+ DefaultProjectTypeEP[] extensions = EXTENSION_POINT_NAME.getExtensions();
+ return extensions.length > 0 ? new ProjectType(extensions[0].type) : null;
}
-
- protected abstract ProjectType getProjectType();
}
diff --git a/platform/projectModel-api/src/com/intellij/openapi/project/ProjectTypeService.java b/platform/projectModel-api/src/com/intellij/openapi/project/ProjectTypeService.java
index e43059390b19..6925a8c39c5e 100644
--- a/platform/projectModel-api/src/com/intellij/openapi/project/ProjectTypeService.java
+++ b/platform/projectModel-api/src/com/intellij/openapi/project/ProjectTypeService.java
@@ -26,8 +26,10 @@ import org.jetbrains.annotations.Nullable;
@State(
name = "ProjectType",
storages = {
- @Storage(file = StoragePathMacros.PROJECT_FILE),
- @Storage(file = StoragePathMacros.PROJECT_CONFIG_DIR + "/misc.xml", scheme = StorageScheme.DIRECTORY_BASED)
+ @Storage(
+ id = "other",
+ file = StoragePathMacros.PROJECT_FILE
+ )
}
)
public class ProjectTypeService implements PersistentStateComponent<ProjectType> {
@@ -41,10 +43,14 @@ public class ProjectTypeService implements PersistentStateComponent<ProjectType>
projectType = getInstance(project).myProjectType;
if (projectType != null) return projectType;
}
- return DefaultProjectTypeProvider.getDefaultProjectType();
+ return DefaultProjectTypeEP.getDefaultProjectType();
}
- public static ProjectTypeService getInstance(@NotNull Project project) {
+ public static void setProjectType(@NotNull Project project, @Nullable ProjectType projectType) {
+ getInstance(project).loadState(projectType);
+ }
+
+ private static ProjectTypeService getInstance(@NotNull Project project) {
return ServiceManager.getService(project, ProjectTypeService.class);
}
diff --git a/platform/projectModel-impl/src/com/intellij/application/options/PathMacrosImpl.java b/platform/projectModel-impl/src/com/intellij/application/options/PathMacrosImpl.java
index cce7a68526bd..ac70cb252f10 100644
--- a/platform/projectModel-impl/src/com/intellij/application/options/PathMacrosImpl.java
+++ b/platform/projectModel-impl/src/com/intellij/application/options/PathMacrosImpl.java
@@ -15,41 +15,40 @@
*/
package com.intellij.application.options;
-import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.PathMacros;
-import com.intellij.openapi.components.ExpandMacroToPathMap;
-import com.intellij.openapi.components.NamedComponent;
+import com.intellij.openapi.components.*;
import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.util.InvalidDataException;
-import com.intellij.openapi.util.NamedJDOMExternalizable;
-import com.intellij.openapi.util.RoamingTypeDisabled;
-import com.intellij.openapi.util.WriteExternalException;
+import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.HashMap;
+import com.intellij.util.containers.hash.LinkedHashMap;
import gnu.trove.THashSet;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.model.serialization.JpsGlobalLoader;
import org.jetbrains.jps.model.serialization.PathMacroUtil;
import java.util.*;
import java.util.concurrent.locks.ReentrantReadWriteLock;
-/**
- * @author dsl
- */
-public class PathMacrosImpl extends PathMacros implements NamedComponent, NamedJDOMExternalizable, RoamingTypeDisabled {
- private static final Logger LOG = Logger.getInstance("#com.intellij.application.options.PathMacrosImpl");
+@State(
+ name = "PathMacrosImpl",
+ storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/path.macros.xml", roamingType = RoamingType.PER_PLATFORM)}
+)
+public class PathMacrosImpl extends PathMacros implements PersistentStateComponent<Element> {
+ private static final Logger LOG = Logger.getInstance(PathMacrosImpl.class);
+
private final Map<String, String> myLegacyMacros = new HashMap<String, String>();
- private final Map<String, String> myMacros = new HashMap<String, String>();
+ private final Map<String, String> myMacros = new LinkedHashMap<String, String>();
private int myModificationStamp = 0;
private final ReentrantReadWriteLock myLock = new ReentrantReadWriteLock();
private final List<String> myIgnoredMacros = ContainerUtil.createLockFreeCopyOnWriteList();
- public static final String MACRO_ELEMENT = JpsGlobalLoader.PathVariablesSerializer.MACRO_TAG;
- public static final String NAME_ATTR = JpsGlobalLoader.PathVariablesSerializer.NAME_ATTRIBUTE;
- public static final String VALUE_ATTR = JpsGlobalLoader.PathVariablesSerializer.VALUE_ATTRIBUTE;
+ private static final String MACRO_ELEMENT = JpsGlobalLoader.PathVariablesSerializer.MACRO_TAG;
+ private static final String NAME_ATTR = JpsGlobalLoader.PathVariablesSerializer.NAME_ATTRIBUTE;
+ private static final String VALUE_ATTR = JpsGlobalLoader.PathVariablesSerializer.VALUE_ATTRIBUTE;
@NonNls
public static final String IGNORED_MACRO_ELEMENT = "ignoredMacro";
@@ -75,6 +74,7 @@ public class PathMacrosImpl extends PathMacros implements NamedComponent, NamedJ
SYSTEM_MACROS.add(USER_HOME_MACRO_NAME);
}
+ @SuppressWarnings("SpellCheckingInspection")
private static final Set<String> ourToolsMacros = ContainerUtil.immutableSet(
"ClasspathEntry",
"Classpath",
@@ -138,18 +138,7 @@ public class PathMacrosImpl extends PathMacros implements NamedComponent, NamedJ
}
public static PathMacrosImpl getInstanceEx() {
- return (PathMacrosImpl)ApplicationManager.getApplication().getComponent(PathMacros.class);
- }
-
- @Override
- @NotNull
- public String getComponentName() {
- return "PathMacrosImpl";
- }
-
- @Override
- public String getExternalFileName() {
- return EXT_FILE_NAME;
+ return (PathMacrosImpl)getInstance();
}
@Override
@@ -286,8 +275,37 @@ public class PathMacrosImpl extends PathMacros implements NamedComponent, NamedJ
}
}
+ @Nullable
+ @Override
+ public Element getState() {
+ try {
+ Element element = new Element("state");
+ myLock.writeLock().lock();
+
+ for (Map.Entry<String, String> entry : myMacros.entrySet()) {
+ String value = entry.getValue();
+ if (!StringUtil.isEmptyOrSpaces(value)) {
+ final Element macro = new Element(MACRO_ELEMENT);
+ macro.setAttribute(NAME_ATTR, entry.getKey());
+ macro.setAttribute(VALUE_ATTR, value);
+ element.addContent(macro);
+ }
+ }
+
+ for (final String macro : myIgnoredMacros) {
+ final Element macroElement = new Element(IGNORED_MACRO_ELEMENT);
+ macroElement.setAttribute(NAME_ATTR, macro);
+ element.addContent(macroElement);
+ }
+ return element;
+ }
+ finally {
+ myLock.writeLock().unlock();
+ }
+ }
+
@Override
- public void readExternal(Element element) throws InvalidDataException {
+ public void loadState(Element element) {
try {
myLock.writeLock().lock();
@@ -297,7 +315,7 @@ public class PathMacrosImpl extends PathMacros implements NamedComponent, NamedJ
final String name = macro.getAttributeValue(NAME_ATTR);
String value = macro.getAttributeValue(VALUE_ATTR);
if (name == null || value == null) {
- throw new InvalidDataException();
+ continue;
}
if (SYSTEM_MACROS.contains(name)) {
@@ -326,33 +344,6 @@ public class PathMacrosImpl extends PathMacros implements NamedComponent, NamedJ
}
}
- @Override
- public void writeExternal(Element element) throws WriteExternalException {
- try {
- myLock.writeLock().lock();
-
- final Set<Map.Entry<String, String>> entries = myMacros.entrySet();
- for (Map.Entry<String, String> entry : entries) {
- final String value = entry.getValue();
- if (value != null && !value.trim().isEmpty()) {
- final Element macro = new Element(MACRO_ELEMENT);
- macro.setAttribute(NAME_ATTR, entry.getKey());
- macro.setAttribute(VALUE_ATTR, value);
- element.addContent(macro);
- }
- }
-
- for (final String macro : myIgnoredMacros) {
- final Element macroElement = new Element(IGNORED_MACRO_ELEMENT);
- macroElement.setAttribute(NAME_ATTR, macro);
- element.addContent(macroElement);
- }
- }
- finally {
- myLock.writeLock().unlock();
- }
- }
-
public void addMacroReplacements(ReplacePathToMacroMap result) {
for (final String name : getUserMacroNames()) {
final String value = getValue(name);
@@ -360,7 +351,6 @@ public class PathMacrosImpl extends PathMacros implements NamedComponent, NamedJ
}
}
-
public void addMacroExpands(ExpandMacroToPathMap result) {
for (final String name : getUserMacroNames()) {
final String value = getValue(name);
diff --git a/platform/projectModel-impl/src/com/intellij/core/CoreModuleManager.java b/platform/projectModel-impl/src/com/intellij/core/CoreModuleManager.java
index 7f7e0df4621d..8753b73144d3 100644
--- a/platform/projectModel-impl/src/com/intellij/core/CoreModuleManager.java
+++ b/platform/projectModel-impl/src/com/intellij/core/CoreModuleManager.java
@@ -26,7 +26,6 @@ import com.intellij.openapi.roots.impl.ModuleRootManagerImpl;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.vfs.StandardFileSystems;
import com.intellij.openapi.vfs.VirtualFile;
-import org.jdom.Element;
import org.jdom.JDOMException;
import java.io.IOException;
@@ -52,10 +51,10 @@ public class CoreModuleManager extends ModuleManagerImpl {
final ModuleEx module = createModule(filePath);
VirtualFile vFile = StandardFileSystems.local().findFileByPath(filePath);
try {
+ assert vFile != null;
StorageData storageData = CoreProjectLoader.loadStorageFile(module, vFile);
- final Element element = storageData.getState("NewModuleRootManager");
ModuleRootManagerImpl.ModuleRootManagerState state = new ModuleRootManagerImpl.ModuleRootManagerState();
- state.readExternal(element);
+ state.readExternal(storageData.getState("NewModuleRootManager"));
((ModuleRootManagerImpl) ModuleRootManager.getInstance(module)).loadState(state);
}
catch (JDOMException e) {
diff --git a/platform/projectModel-impl/src/com/intellij/core/CoreProjectLoader.java b/platform/projectModel-impl/src/com/intellij/core/CoreProjectLoader.java
index 5d8ac1fd4ed2..f05983aff69a 100644
--- a/platform/projectModel-impl/src/com/intellij/core/CoreProjectLoader.java
+++ b/platform/projectModel-impl/src/com/intellij/core/CoreProjectLoader.java
@@ -27,14 +27,11 @@ import com.intellij.openapi.roots.impl.ProjectRootManagerImpl;
import com.intellij.openapi.roots.impl.libraries.LibraryTableBase;
import com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable;
import com.intellij.openapi.util.InvalidDataException;
-import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.vfs.VirtualFile;
-import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jetbrains.annotations.NotNull;
-import java.io.ByteArrayInputStream;
import java.io.IOException;
/**
@@ -56,7 +53,9 @@ public class CoreProjectLoader {
private static void loadDirectoryProject(MockProject project, VirtualFile projectDir) throws IOException, JDOMException,
InvalidDataException {
VirtualFile dotIdea = projectDir.findChild(Project.DIRECTORY_STORE_FOLDER);
+ assert dotIdea != null;
VirtualFile modulesXml = dotIdea.findChild("modules.xml");
+ assert modulesXml != null;
StorageData storageData = loadStorageFile(project, modulesXml);
final Element moduleManagerState = storageData.getState("ProjectModuleManager");
if (moduleManagerState == null) {
@@ -66,6 +65,7 @@ public class CoreProjectLoader {
moduleManager.loadState(moduleManagerState);
VirtualFile miscXml = dotIdea.findChild("misc.xml");
+ assert miscXml != null;
storageData = loadStorageFile(project, miscXml);
final Element projectRootManagerState = storageData.getState("ProjectRootManager");
if (projectRootManagerState == null) {
@@ -85,12 +85,10 @@ public class CoreProjectLoader {
project.projectOpened();
}
- public static StorageData loadStorageFile(ComponentManager componentManager, VirtualFile modulesXml) throws JDOMException, IOException {
- final Document document = JDOMUtil.loadDocument(new ByteArrayInputStream(modulesXml.contentsToByteArray()));
+ @NotNull
+ public static StorageData loadStorageFile(@NotNull ComponentManager componentManager, @NotNull VirtualFile modulesXml) throws JDOMException, IOException {
StorageData storageData = new StorageData("project");
- final Element element = document.getRootElement();
- PathMacroManager.getInstance(componentManager).expandPaths(element);
- storageData.load(element);
+ storageData.load(StorageData.load(modulesXml), PathMacroManager.getInstance(componentManager), false);
return storageData;
}
}
diff --git a/platform/projectModel-impl/src/com/intellij/openapi/components/PathMacroManager.java b/platform/projectModel-impl/src/com/intellij/openapi/components/PathMacroManager.java
index 8999bb914dea..046da9d799e6 100644
--- a/platform/projectModel-impl/src/com/intellij/openapi/components/PathMacroManager.java
+++ b/platform/projectModel-impl/src/com/intellij/openapi/components/PathMacroManager.java
@@ -25,12 +25,6 @@ public abstract class PathMacroManager implements PathMacroSubstitutor {
return component;
}
- @Override
- public abstract void expandPaths(@NotNull Element element);
-
- @Override
- public abstract void collapsePaths(@NotNull Element element);
-
public abstract void collapsePathsRecursively(@NotNull Element element);
public abstract String collapsePathsRecursively(@NotNull String text);
diff --git a/platform/projectModel-impl/src/com/intellij/openapi/components/PathMacroSubstitutor.java b/platform/projectModel-impl/src/com/intellij/openapi/components/PathMacroSubstitutor.java
index c79802533a1d..bcffa0bc34ee 100644
--- a/platform/projectModel-impl/src/com/intellij/openapi/components/PathMacroSubstitutor.java
+++ b/platform/projectModel-impl/src/com/intellij/openapi/components/PathMacroSubstitutor.java
@@ -16,6 +16,7 @@
package com.intellij.openapi.components;
import org.jdom.Element;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public interface PathMacroSubstitutor {
@@ -23,7 +24,7 @@ public interface PathMacroSubstitutor {
String collapsePath(@Nullable String path);
- void expandPaths(Element element);
+ void expandPaths(@NotNull Element element);
- void collapsePaths(Element element);
+ void collapsePaths(@NotNull Element element);
}
diff --git a/platform/projectModel-impl/src/com/intellij/openapi/components/TrackingPathMacroSubstitutor.java b/platform/projectModel-impl/src/com/intellij/openapi/components/TrackingPathMacroSubstitutor.java
index 63e3a89431d8..48f33feb7936 100644
--- a/platform/projectModel-impl/src/com/intellij/openapi/components/TrackingPathMacroSubstitutor.java
+++ b/platform/projectModel-impl/src/com/intellij/openapi/components/TrackingPathMacroSubstitutor.java
@@ -15,15 +15,22 @@
*/
package com.intellij.openapi.components;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Set;
public interface TrackingPathMacroSubstitutor extends PathMacroSubstitutor {
+ @NotNull
Collection<String> getUnknownMacros(@Nullable String componentName);
- Collection<String> getComponents(final Collection<String> macros);
- void addUnknownMacros(String componentName, Collection<String> unknownMacros);
- void invalidateUnknownMacros(Set<String> macros);
+
+ @NotNull
+ Collection<String> getComponents(@NotNull Collection<String> macros);
+
+ void addUnknownMacros(@NotNull String componentName, @NotNull Collection<String> unknownMacros);
+
+ void invalidateUnknownMacros(@NotNull Set<String> macros);
+
void reset();
}
diff --git a/platform/projectModel-impl/src/com/intellij/openapi/components/impl/BasePathMacroManager.java b/platform/projectModel-impl/src/com/intellij/openapi/components/impl/BasePathMacroManager.java
index 9707364c988b..b3d1edb42b4e 100644
--- a/platform/projectModel-impl/src/com/intellij/openapi/components/impl/BasePathMacroManager.java
+++ b/platform/projectModel-impl/src/com/intellij/openapi/components/impl/BasePathMacroManager.java
@@ -31,16 +31,22 @@ import com.intellij.openapi.vfs.StandardFileSystems;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.openapi.vfs.VirtualFileSystem;
-import com.intellij.util.containers.FactoryMap;
+import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.containers.MultiMap;
+import com.intellij.util.containers.SmartHashSet;
+import gnu.trove.THashSet;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.model.serialization.PathMacroUtil;
-import java.util.*;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
public class BasePathMacroManager extends PathMacroManager {
- private static final CompositePathMacroFilter ourFilter = new CompositePathMacroFilter(Extensions.getExtensions(PathMacrosCollector.MACRO_FILTER_EXTENSION_POINT_NAME));
+ private static final CompositePathMacroFilter FILTER = new CompositePathMacroFilter(Extensions.getExtensions(PathMacrosCollector.MACRO_FILTER_EXTENSION_POINT_NAME));
private PathMacrosImpl myPathMacros;
@@ -49,20 +55,26 @@ public class BasePathMacroManager extends PathMacroManager {
}
protected static void addFileHierarchyReplacements(ExpandMacroToPathMap result, String macroName, @Nullable String path) {
- if (path == null) return;
- addFileHierarchyReplacements(result, getLocalFileSystem().findFileByPath(path), "$" + macroName + "$");
+ if (path != null) {
+ addFileHierarchyReplacements(result, getLocalFileSystem().findFileByPath(path), '$' + macroName + '$');
+ }
}
private static void addFileHierarchyReplacements(ExpandMacroToPathMap result, @Nullable VirtualFile f, String macro) {
- if (f == null) return;
+ if (f == null) {
+ return;
+ }
+
addFileHierarchyReplacements(result, f.getParent(), macro + "/..");
result.put(macro, StringUtil.trimEnd(f.getPath(), "/"));
}
protected static void addFileHierarchyReplacements(ReplacePathToMacroMap result, String macroName, @Nullable String path, @Nullable String stopAt) {
- if (path == null) return;
+ if (path == null) {
+ return;
+ }
- String macro = "$" + macroName + "$";
+ String macro = '$' + macroName + '$';
path = StringUtil.trimEnd(FileUtil.toSystemIndependentName(path), "/");
boolean overwrite = true;
while (StringUtil.isNotEmpty(path) && path.contains("/")) {
@@ -140,25 +152,14 @@ public class BasePathMacroManager extends PathMacroManager {
if (myPathMacros == null) {
myPathMacros = PathMacrosImpl.getInstanceEx();
}
-
return myPathMacros;
}
private class MyTrackingPathMacroSubstitutor implements TrackingPathMacroSubstitutor {
private final String myLock = new String("MyTrackingPathMacroSubstitutor.lock");
- private final Map<String, Set<String>> myMacroToComponentNames = new FactoryMap<String, Set<String>>() {
- @Override
- protected Set<String> create(String key) {
- return new HashSet<String>();
- }
- };
- private final Map<String, Set<String>> myComponentNameToMacros = new FactoryMap<String, Set<String>>() {
- @Override
- protected Set<String> create(String key) {
- return new HashSet<String>();
- }
- };
+ private final MultiMap<String, String> myMacroToComponentNames = MultiMap.createSet();
+ private final MultiMap<String, String> myComponentNameToMacros = MultiMap.createSet();
public MyTrackingPathMacroSubstitutor() {
}
@@ -182,13 +183,13 @@ public class BasePathMacroManager extends PathMacroManager {
}
@Override
- public void expandPaths(final Element element) {
+ public void expandPaths(@NotNull final Element element) {
getExpandMacroMap().substitute(element, SystemInfo.isFileSystemCaseSensitive);
}
@Override
- public void collapsePaths(final Element element) {
- getReplacePathMap().substitute(element, SystemInfo.isFileSystemCaseSensitive, false, ourFilter);
+ public void collapsePaths(@NotNull final Element element) {
+ getReplacePathMap().substitute(element, SystemInfo.isFileSystemCaseSensitive, false, FILTER);
}
public int hashCode() {
@@ -196,52 +197,52 @@ public class BasePathMacroManager extends PathMacroManager {
}
@Override
- public void invalidateUnknownMacros(final Set<String> macros) {
+ public void invalidateUnknownMacros(@NotNull Set<String> macros) {
synchronized (myLock) {
- for (final String macro : macros) {
- final Set<String> components = myMacroToComponentNames.get(macro);
- for (final String component : components) {
- myComponentNameToMacros.remove(component);
+ for (String macro : macros) {
+ Collection<String> componentNames = myMacroToComponentNames.remove(macro);
+ if (!ContainerUtil.isEmpty(componentNames)) {
+ for (String component : componentNames) {
+ myComponentNameToMacros.remove(component);
+ }
}
-
- myMacroToComponentNames.remove(macro);
}
}
}
+ @NotNull
@Override
- public Collection<String> getComponents(final Collection<String> macros) {
+ public Collection<String> getComponents(@NotNull Collection<String> macros) {
synchronized (myLock) {
- final Set<String> result = new HashSet<String>();
- for (String macro : myMacroToComponentNames.keySet()) {
- if (macros.contains(macro)) {
- result.addAll(myMacroToComponentNames.get(macro));
- }
+ Set<String> result = new SmartHashSet<String>();
+ for (String macro : macros) {
+ result.addAll(myMacroToComponentNames.get(macro));
}
-
return result;
}
}
+ @NotNull
@Override
- public Collection<String> getUnknownMacros(final String componentName) {
+ public Collection<String> getUnknownMacros(@Nullable String componentName) {
synchronized (myLock) {
- final Set<String> result = new HashSet<String>();
- result.addAll(componentName == null ? myMacroToComponentNames.keySet() : myComponentNameToMacros.get(componentName));
- return Collections.unmodifiableCollection(result);
+ Collection<String> list = componentName == null ? myMacroToComponentNames.keySet() : myComponentNameToMacros.get(componentName);
+ return ContainerUtil.isEmpty(list) ? Collections.<String>emptyList() : new THashSet<String>(list);
}
}
@Override
- public void addUnknownMacros(final String componentName, final Collection<String> unknownMacros) {
- if (unknownMacros.isEmpty()) return;
+ public void addUnknownMacros(@NotNull String componentName, @NotNull Collection<String> unknownMacros) {
+ if (unknownMacros.isEmpty()) {
+ return;
+ }
synchronized (myLock) {
for (String unknownMacro : unknownMacros) {
- myMacroToComponentNames.get(unknownMacro).add(componentName);
+ myMacroToComponentNames.putValue(unknownMacro, componentName);
}
- myComponentNameToMacros.get(componentName).addAll(unknownMacros);
+ myComponentNameToMacros.putValues(componentName, unknownMacros);
}
}
}
diff --git a/platform/projectModel-impl/src/com/intellij/openapi/components/impl/ModulePathMacroManager.java b/platform/projectModel-impl/src/com/intellij/openapi/components/impl/ModulePathMacroManager.java
index 704dfec04233..e8cc7bcd040a 100644
--- a/platform/projectModel-impl/src/com/intellij/openapi/components/impl/ModulePathMacroManager.java
+++ b/platform/projectModel-impl/src/com/intellij/openapi/components/impl/ModulePathMacroManager.java
@@ -16,7 +16,6 @@
package com.intellij.openapi.components.impl;
-import com.intellij.application.options.PathMacrosImpl;
import com.intellij.application.options.ReplacePathToMacroMap;
import com.intellij.openapi.application.PathMacros;
import com.intellij.openapi.components.ExpandMacroToPathMap;
@@ -34,25 +33,21 @@ public class ModulePathMacroManager extends BasePathMacroManager {
@Override
public ExpandMacroToPathMap getExpandMacroMap() {
final ExpandMacroToPathMap result = new ExpandMacroToPathMap();
-
if (!myModule.isDisposed()) {
- addFileHierarchyReplacements(result, PathMacrosImpl.MODULE_DIR_MACRO_NAME, PathMacroUtil.getModuleDir(myModule.getModuleFilePath()));
+ addFileHierarchyReplacements(result, PathMacroUtil.MODULE_DIR_MACRO_NAME, PathMacroUtil.getModuleDir(myModule.getModuleFilePath()));
}
result.putAll(super.getExpandMacroMap());
-
return result;
}
@Override
public ReplacePathToMacroMap getReplacePathMap() {
final ReplacePathToMacroMap result = super.getReplacePathMap();
-
if (!myModule.isDisposed()) {
final String modulePath = PathMacroUtil.getModuleDir(myModule.getModuleFilePath());
- addFileHierarchyReplacements(result, PathMacrosImpl.MODULE_DIR_MACRO_NAME, modulePath, PathMacroUtil.getUserHomePath());
+ addFileHierarchyReplacements(result, PathMacroUtil.MODULE_DIR_MACRO_NAME, modulePath, PathMacroUtil.getUserHomePath());
}
-
return result;
}
}
diff --git a/platform/projectModel-impl/src/com/intellij/openapi/components/impl/stores/DefaultStateSerializer.java b/platform/projectModel-impl/src/com/intellij/openapi/components/impl/stores/DefaultStateSerializer.java
index 608a350d770c..d4f87027191d 100644
--- a/platform/projectModel-impl/src/com/intellij/openapi/components/impl/stores/DefaultStateSerializer.java
+++ b/platform/projectModel-impl/src/com/intellij/openapi/components/impl/stores/DefaultStateSerializer.java
@@ -40,6 +40,7 @@ class DefaultStateSerializer {
private DefaultStateSerializer() {
}
+ @Nullable
static Element serializeState(@NotNull Object state, final Storage storage) throws WriteExternalException {
if (state instanceof Element) {
return (Element)state;
@@ -56,12 +57,12 @@ class DefaultStateSerializer {
}
catch (Throwable e) {
LOG.info("Unable to serialize component state!", e);
- return new Element("empty");
+ return null;
}
return element;
}
else {
- return XmlSerializer.serialize(state, new SkipDefaultValuesSerializationFilters() {
+ return XmlSerializer.serialize(state, new SkipDefaultValuesSerializationFilters() {
@Override
public boolean accepts(final Accessor accessor, final Object bean) {
if (!super.accepts(accessor, bean)) return false;
diff --git a/platform/projectModel-impl/src/com/intellij/openapi/components/impl/stores/DirectoryStorageData.java b/platform/projectModel-impl/src/com/intellij/openapi/components/impl/stores/DirectoryStorageData.java
index 4a9aaed20af8..8ea0e1ef935f 100644
--- a/platform/projectModel-impl/src/com/intellij/openapi/components/impl/stores/DirectoryStorageData.java
+++ b/platform/projectModel-impl/src/com/intellij/openapi/components/impl/stores/DirectoryStorageData.java
@@ -23,8 +23,6 @@ import com.intellij.openapi.util.JDOMUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.PairConsumer;
-import com.intellij.util.io.fs.FileSystem;
-import com.intellij.util.io.fs.IFile;
import gnu.trove.THashMap;
import org.jdom.Document;
import org.jdom.Element;
@@ -37,9 +35,9 @@ import java.io.IOException;
import java.util.*;
public class DirectoryStorageData {
- private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.components.impl.stores.DirectoryStorageData");
+ private static final Logger LOG = Logger.getInstance(DirectoryStorageData.class);
- private Map<String, Map<IFile, Element>> myStates = new HashMap<String, Map<IFile, Element>>();
+ private Map<String, Map<File, Element>> myStates = new THashMap<String, Map<File, Element>>();
private long myLastTimestamp = 0;
private DirectoryStorageData myOriginalData;
@@ -79,7 +77,7 @@ public class DirectoryStorageData {
pathMacroSubstitutor.addUnknownMacros(componentName, unknownMacros);
}
- put(componentName, FileSystem.FILE_SYSTEM.createFile(file.getPath()), element, true);
+ put(componentName, new File(file.getPath()), element, true);
}
catch (IOException e) {
LOG.info("Unable to load state", e);
@@ -90,44 +88,48 @@ public class DirectoryStorageData {
}
}
- public void put(final String componentName, final IFile file, final Element element, final boolean updateTimestamp) {
+ public void put(final String componentName, File file, final Element element, final boolean updateTimestamp) {
LOG.assertTrue(componentName != null, String.format("Component name should not be null for file: %s", file == null ? "NULL!" : file.getPath()));
- Map<IFile, Element> stateMap = myStates.get(componentName);
+ Map<File, Element> stateMap = myStates.get(componentName);
if (stateMap == null) {
- stateMap = new HashMap<IFile, Element>();
+ stateMap = new THashMap<File, Element>();
myStates.put(componentName, stateMap);
}
stateMap.put(file, element);
- if (updateTimestamp) updateLastTimestamp(file);
+ if (updateTimestamp) {
+ updateLastTimestamp(file);
+ }
}
- public void updateLastTimestamp(final IFile file) {
- myLastTimestamp = Math.max(myLastTimestamp, file.getTimeStamp());
- if (myOriginalData != null) myOriginalData.myLastTimestamp = myLastTimestamp;
+ public void updateLastTimestamp(File file) {
+ myLastTimestamp = Math.max(myLastTimestamp, file.lastModified());
+ if (myOriginalData != null) {
+ myOriginalData.myLastTimestamp = myLastTimestamp;
+ }
}
public long getLastTimeStamp() {
return myLastTimestamp;
}
- public Map<IFile, Long> getAllStorageFiles() {
- final Map<IFile, Long> allStorageFiles = new THashMap<IFile, Long>();
+ public Map<File, Long> getAllStorageFiles() {
+ final Map<File, Long> allStorageFiles = new THashMap<File, Long>();
process(new StorageDataProcessor() {
@Override
- public void process(final String componentName, final IFile file, final Element element) {
- allStorageFiles.put(file, file.getTimeStamp());
+ public void process(final String componentName, final File file, final Element element) {
+ allStorageFiles.put(file, file.lastModified());
}
});
return allStorageFiles;
}
- public void processComponent(@NotNull final String componentName, @NotNull final PairConsumer<IFile, Element> consumer) {
- final Map<IFile, Element> map = myStates.get(componentName);
+ public void processComponent(@NotNull final String componentName, @NotNull final PairConsumer<File, Element> consumer) {
+ final Map<File, Element> map = myStates.get(componentName);
if (map != null) {
- for (IFile file : map.keySet()) {
+ for (File file : map.keySet()) {
consumer.consume(file, map.get(file));
}
}
@@ -135,10 +137,10 @@ public class DirectoryStorageData {
public void process(@NotNull final StorageDataProcessor processor) {
for (final String componentName : myStates.keySet()) {
- processComponent(componentName, new PairConsumer<IFile, Element>() {
+ processComponent(componentName, new PairConsumer<File, Element>() {
@Override
- public void consume(final IFile iFile, final Element element) {
- processor.process(componentName, iFile, element);
+ public void consume(File file, Element element) {
+ processor.process(componentName, file, element);
}
});
}
@@ -147,7 +149,7 @@ public class DirectoryStorageData {
@Override
protected DirectoryStorageData clone() {
final DirectoryStorageData result = new DirectoryStorageData();
- result.myStates = new HashMap<String, Map<IFile, Element>>(myStates);
+ result.myStates = new HashMap<String, Map<File, Element>>(myStates);
result.myLastTimestamp = myLastTimestamp;
result.myOriginalData = this;
return result;
@@ -169,9 +171,9 @@ public class DirectoryStorageData {
@Nullable
public <T> T getMergedState(String componentName, Class<T> stateClass, StateSplitter splitter, @Nullable T mergeInto) {
final List<Element> subElements = new ArrayList<Element>();
- processComponent(componentName, new PairConsumer<IFile, Element>() {
+ processComponent(componentName, new PairConsumer<File, Element>() {
@Override
- public void consume(final IFile iFile, final Element element) {
+ public void consume(File file, Element element) {
final List children = element.getChildren();
assert children.size() == 1 : JDOMUtil.writeElement(element, File.separator);
final Element subElement = (Element)children.get(0);
@@ -188,6 +190,6 @@ public class DirectoryStorageData {
}
interface StorageDataProcessor {
- void process(String componentName, IFile file, Element element);
+ void process(String componentName, File file, Element element);
}
}
diff --git a/platform/projectModel-impl/src/com/intellij/openapi/components/impl/stores/StorageData.java b/platform/projectModel-impl/src/com/intellij/openapi/components/impl/stores/StorageData.java
index 82dece3ba5e1..699440e22b54 100644
--- a/platform/projectModel-impl/src/com/intellij/openapi/components/impl/stores/StorageData.java
+++ b/platform/projectModel-impl/src/com/intellij/openapi/components/impl/stores/StorageData.java
@@ -16,6 +16,7 @@
package com.intellij.openapi.components.impl.stores;
import com.intellij.application.options.PathMacrosCollector;
+import com.intellij.ide.plugins.IdeaPluginDescriptorImpl;
import com.intellij.openapi.components.PathMacroSubstitutor;
import com.intellij.openapi.components.TrackingPathMacroSubstitutor;
import com.intellij.openapi.components.XmlConfigurationMerger;
@@ -23,20 +24,23 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.ExtensionPoint;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.util.JDOMUtil;
+import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ArrayUtil;
import gnu.trove.THashMap;
import gnu.trove.THashSet;
import org.jdom.Attribute;
import org.jdom.Element;
+import org.jdom.JDOMException;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
+import java.io.InputStream;
import java.util.*;
public class StorageData {
- private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.components.impl.stores.StorageData");
+ private static final Logger LOG = Logger.getInstance(StorageData.class);
@NonNls public static final String COMPONENT = "component";
@NonNls public static final String NAME = "name";
@@ -44,17 +48,21 @@ public class StorageData {
protected final String myRootElementName;
private int myHash = -1;
- public StorageData(final String rootElementName) {
+ public StorageData(@NotNull String rootElementName) {
myComponentStates = new THashMap<String, Element>();
myRootElementName = rootElementName;
}
- StorageData(StorageData storageData) {
+ StorageData(@NotNull StorageData storageData) {
myRootElementName = storageData.myRootElementName;
myComponentStates = new THashMap<String, Element>(storageData.myComponentStates);
}
- public void load(@NotNull Element rootElement) throws IOException {
+ public void load(@NotNull Element rootElement, @Nullable PathMacroSubstitutor pathMacroSubstitutor, boolean intern) {
+ if (pathMacroSubstitutor != null) {
+ pathMacroSubstitutor.expandPaths(rootElement);
+ }
+
for (Iterator<Element> iterator = rootElement.getChildren(COMPONENT).iterator(); iterator.hasNext(); ) {
Element element = iterator.next();
String name = element.getAttributeValue(NAME);
@@ -63,33 +71,47 @@ public class StorageData {
continue;
}
- iterator.remove();
-
if (element.getAttributes().size() > 1 || !element.getChildren().isEmpty()) {
assert element.getAttributeValue(NAME) != null : "No name attribute for component: " + name + " in " + this;
- Element existingElement = myComponentStates.get(name);
- if (existingElement != null) {
- element = mergeElements(name, element, existingElement);
+ iterator.remove();
+ if (intern) {
+ IdeaPluginDescriptorImpl.internJDOMElement(element);
+ }
+
+ Element serverElement = myComponentStates.get(name);
+ if (serverElement != null) {
+ element = mergeElements(name, element, serverElement);
}
myComponentStates.put(name, element);
}
}
+
+ if (pathMacroSubstitutor instanceof TrackingPathMacroSubstitutor) {
+ for (String componentName : myComponentStates.keySet()) {
+ ((TrackingPathMacroSubstitutor)pathMacroSubstitutor).addUnknownMacros(componentName, PathMacrosCollector.getMacroNames(myComponentStates.get(componentName)));
+ }
+ }
}
- private static Element mergeElements(final String name, final Element element1, final Element element2) {
+ @NotNull
+ private static Element mergeElements(@NotNull String name, @NotNull Element localElement, @NotNull Element serverElement) {
ExtensionPoint<XmlConfigurationMerger> point = Extensions.getRootArea().getExtensionPoint("com.intellij.componentConfigurationMerger");
for (XmlConfigurationMerger merger : point.getExtensions()) {
if (merger.getComponentName().equals(name)) {
- return merger.merge(element1, element2);
+ return merger.merge(serverElement, localElement);
}
}
- return element1;
+ return serverElement;
}
- @NotNull
+ @Nullable
protected Element save() {
+ if (myComponentStates.isEmpty()) {
+ return null;
+ }
+
Element rootElement = new Element(myRootElementName);
String[] componentNames = ArrayUtil.toStringArray(myComponentStates.keySet());
Arrays.sort(componentNames);
@@ -101,7 +123,6 @@ public class StorageData {
rootElement.addContent(element.clone());
}
-
return rootElement;
}
@@ -197,20 +218,18 @@ public class StorageData {
return myComponentStates.isEmpty();
}
- public boolean hasState(final String componentName) {
+ public boolean hasState(@NotNull String componentName) {
return myComponentStates.containsKey(componentName);
}
- public void checkUnknownMacros(TrackingPathMacroSubstitutor pathMacroSubstitutor) {
- if (pathMacroSubstitutor == null) {
- return;
+ @NotNull
+ public static Element load(@NotNull VirtualFile file) throws IOException, JDOMException {
+ InputStream stream = file.getInputStream();
+ try {
+ return JDOMUtil.loadDocument(stream).getRootElement();
}
-
- for (String componentName : myComponentStates.keySet()) {
- final Set<String> unknownMacros = PathMacrosCollector.getMacroNames(myComponentStates.get(componentName));
- if (!unknownMacros.isEmpty()) {
- pathMacroSubstitutor.addUnknownMacros(componentName, unknownMacros);
- }
+ finally {
+ stream.close();
}
}
}
diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/RootIndex.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/RootIndex.java
index bd9531a2d888..a55f2a1e0b00 100644
--- a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/RootIndex.java
+++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/RootIndex.java
@@ -71,6 +71,13 @@ public class RootIndex {
private final TObjectIntHashMap<JpsModuleSourceRootType<?>> myRootTypeId = new TObjectIntHashMap<JpsModuleSourceRootType<?>>();
@NotNull private final Project myProject;
private volatile Map<VirtualFile, OrderEntry[]> myOrderEntries;
+ @SuppressWarnings("UnusedDeclaration")
+ private final LowMemoryWatcher myLowMemoryWatcher = LowMemoryWatcher.register(new Runnable() {
+ @Override
+ public void run() {
+ myNonExistentPackages.clear();
+ }
+ });
// made public for Upsource
public RootIndex(@NotNull Project project, @NotNull InfoCache cache) {
@@ -90,12 +97,6 @@ public class RootIndex {
myProjectExcludedRoots.add(root);
}
}
- LowMemoryWatcher.register(new Runnable() {
- @Override
- public void run() {
- myNonExistentPackages.clear();
- }
- }, project);
}
@NotNull
diff --git a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/JarDirectories.java b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/JarDirectories.java
index e9e4da53dddd..c4903098fa87 100644
--- a/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/JarDirectories.java
+++ b/platform/projectModel-impl/src/com/intellij/openapi/roots/impl/libraries/JarDirectories.java
@@ -106,7 +106,7 @@ public class JarDirectories implements JDOMExternalizable {
@Override
public String toString() {
- return "Jar dirs: " + myDirectories.values();
+ return "JAR dirs: " + myDirectories.values();
}
diff --git a/platform/projectModel-impl/src/messages/ProjectBundle.properties b/platform/projectModel-impl/src/messages/ProjectBundle.properties
index a0fe65ad981a..956bb8a0d2d2 100644
--- a/platform/projectModel-impl/src/messages/ProjectBundle.properties
+++ b/platform/projectModel-impl/src/messages/ProjectBundle.properties
@@ -112,7 +112,7 @@ module.paths.edit.properties.title=Edit Root Properties
module.javadoc.title=JavaDoc
module.javadoc.add.url.button=Add JavaDoc URL...
module.javadoc.add.path.title=Add Path To JavaDoc
-module.javadoc.add.path.prompt=Select jar/zip files or directories in which module javadoc documentation is located
+module.javadoc.add.path.prompt=Select JAR/zip files or directories in which module javadoc documentation is located
jdk.combo.box.project.item=<No Project SDK>
jdk.combo.box.none.item=<None>
jdk.combo.box.invalid.item={0} [Invalid]
@@ -134,7 +134,7 @@ library.sources.not.found=Sources not found
library.sources.not.attached=Sources not attached
library.attach.sources.action=Attach Sources
library.attach.sources.action.busy.text=Attaching...
-library.attach.sources.description=Select jar/zip files or directories in which library sources are located
+library.attach.sources.description=Select JAR/zip files or directories in which library sources are located
project.sdk.not.defined=Project SDK is not defined
project.sdk.setup=Setup SDK
diff --git a/platform/remote-servers/agent-rt/src/com/intellij/remoteServer/agent/util/CloudAgentLoggingHandler.java b/platform/remote-servers/agent-rt/src/com/intellij/remoteServer/agent/util/CloudAgentLoggingHandler.java
index 7055bace613b..029909ad9259 100644
--- a/platform/remote-servers/agent-rt/src/com/intellij/remoteServer/agent/util/CloudAgentLoggingHandler.java
+++ b/platform/remote-servers/agent-rt/src/com/intellij/remoteServer/agent/util/CloudAgentLoggingHandler.java
@@ -17,6 +17,8 @@ package com.intellij.remoteServer.agent.util;
import com.intellij.remoteServer.agent.util.log.LogListener;
+import java.io.OutputStream;
+
/**
* @author michael.golubev
*/
@@ -25,4 +27,6 @@ public interface CloudAgentLoggingHandler {
void println(String message);
LogListener getOrCreateLogListener(String pipeName);
+
+ LogListener createConsole(String pipeName, OutputStream consoleInput);
}
diff --git a/platform/remote-servers/api/remote-servers-api.iml b/platform/remote-servers/api/remote-servers-api.iml
index f5559bb8e730..4f23c02e26b7 100644
--- a/platform/remote-servers/api/remote-servers-api.iml
+++ b/platform/remote-servers/api/remote-servers-api.iml
@@ -8,7 +8,6 @@
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="core-api" />
- <orderEntry type="module" module-name="compiler-openapi" />
<orderEntry type="module" module-name="lang-api" />
<orderEntry type="module" module-name="remote-servers-agent-rt" exported="" />
</component>
diff --git a/platform/remote-servers/impl/src/com/intellij/remoteServer/util/CloudConfigurableBase.java b/platform/remote-servers/impl/src/com/intellij/remoteServer/util/CloudConfigurableBase.java
index 4fb4bed03d1e..2e0797f01ee5 100644
--- a/platform/remote-servers/impl/src/com/intellij/remoteServer/util/CloudConfigurableBase.java
+++ b/platform/remote-servers/impl/src/com/intellij/remoteServer/util/CloudConfigurableBase.java
@@ -3,7 +3,13 @@ package com.intellij.remoteServer.util;
import com.intellij.execution.configurations.RuntimeConfigurationError;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.UnnamedConfigurable;
+import com.intellij.openapi.util.Comparing;
+import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.remoteServer.ServerType;
+import com.intellij.remoteServer.configuration.RemoteServer;
+import com.intellij.remoteServer.configuration.RemoteServersManager;
+import com.intellij.util.text.UniqueNameGenerator;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
@@ -13,12 +19,18 @@ import javax.swing.*;
*/
public abstract class CloudConfigurableBase<SC extends CloudConfigurationBase> implements UnnamedConfigurable {
+ private final ServerType<SC> myCloudType;
protected final SC myConfiguration;
- public CloudConfigurableBase(SC configuration) {
+ public CloudConfigurableBase(ServerType<SC> cloudType, SC configuration) {
+ myCloudType = cloudType;
myConfiguration = configuration;
}
+ protected final ServerType<SC> getCloudType() {
+ return myCloudType;
+ }
+
@Nullable
@Override
public JComponent createComponent() {
@@ -33,6 +45,20 @@ public abstract class CloudConfigurableBase<SC extends CloudConfigurationBase> i
@Override
public void apply() throws ConfigurationException {
+ applyCoreTo(myConfiguration);
+ }
+
+ @Override
+ public void reset() {
+ getEmailTextField().setText(myConfiguration.getEmail());
+ getPasswordField().setText(myConfiguration.getPassword());
+ }
+
+ @Override
+ public void disposeUIResources() {
+ }
+
+ protected void applyCoreTo(SC configuration) throws ConfigurationException {
String email = getEmailTextField().getText();
if (StringUtil.isEmpty(email)) {
throw new RuntimeConfigurationError("Email required");
@@ -42,18 +68,40 @@ public abstract class CloudConfigurableBase<SC extends CloudConfigurationBase> i
throw new RuntimeConfigurationError("Password required");
}
- myConfiguration.setEmail(email);
- myConfiguration.setPassword(password);
+ configuration.setEmail(email);
+ configuration.setPassword(password);
}
- @Override
- public void reset() {
- getEmailTextField().setText(myConfiguration.getEmail());
- getPasswordField().setText(myConfiguration.getPassword());
+ protected boolean isCoreConfigEqual(SC configuration1, SC configuration2) {
+ return Comparing.equal(configuration1.getEmail(), configuration2.getEmail())
+ && Comparing.equal(configuration1.getPassword(), configuration2.getPassword());
}
- @Override
- public void disposeUIResources() {
+ private String generateServerName() {
+ return UniqueNameGenerator.generateUniqueName(myCloudType.getPresentableName(), new Condition<String>() {
+
+ @Override
+ public boolean value(String s) {
+ for (RemoteServer<?> server : RemoteServersManager.getInstance().getServers()) {
+ if (server.getName().equals(s)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ });
+ }
+
+ protected final RemoteServer<SC> createTempServer() {
+ RemoteServer<SC> tempServer = RemoteServersManager.getInstance().createServer(myCloudType, generateServerName());
+ SC newConfiguration = tempServer.getConfiguration();
+ try {
+ applyCoreTo(newConfiguration);
+ }
+ catch (ConfigurationException e) {
+ return null;
+ }
+ return tempServer;
}
protected abstract JComponent getMainPanel();
diff --git a/platform/remote-servers/impl/src/com/intellij/remoteServer/util/CloudGitApplicationRuntime.java b/platform/remote-servers/impl/src/com/intellij/remoteServer/util/CloudGitApplicationRuntime.java
index 5f40b5ac4257..3a34bb456ad6 100644
--- a/platform/remote-servers/impl/src/com/intellij/remoteServer/util/CloudGitApplicationRuntime.java
+++ b/platform/remote-servers/impl/src/com/intellij/remoteServer/util/CloudGitApplicationRuntime.java
@@ -45,11 +45,11 @@ public class CloudGitApplicationRuntime extends CloudApplicationRuntime {
myDeployment = serverRuntime.getAgent().createDeployment(applicationName, myLoggingHandler);
}
- protected CloudMultiSourceServerRuntimeInstance getServerRuntime() {
+ public CloudMultiSourceServerRuntimeInstance getServerRuntime() {
return myServerRuntime;
}
- protected DeploymentLogManager getLogManager() {
+ public DeploymentLogManager getLogManager() {
return myLogManager;
}
diff --git a/platform/remote-servers/impl/src/com/intellij/remoteServer/util/CloudLoggingHandlerImpl.java b/platform/remote-servers/impl/src/com/intellij/remoteServer/util/CloudLoggingHandlerImpl.java
index 346bd0af3046..89535ab6b8e6 100644
--- a/platform/remote-servers/impl/src/com/intellij/remoteServer/util/CloudLoggingHandlerImpl.java
+++ b/platform/remote-servers/impl/src/com/intellij/remoteServer/util/CloudLoggingHandlerImpl.java
@@ -15,11 +15,14 @@
*/
package com.intellij.remoteServer.util;
+import com.intellij.execution.process.ProcessHandler;
import com.intellij.remoteServer.agent.util.CloudAgentLoggingHandler;
import com.intellij.remoteServer.agent.util.log.LogListener;
import com.intellij.remoteServer.runtime.deployment.DeploymentLogManager;
import com.intellij.remoteServer.runtime.log.LoggingHandler;
+import org.jetbrains.annotations.Nullable;
+import java.io.OutputStream;
import java.util.HashMap;
/**
@@ -60,4 +63,40 @@ public class CloudLoggingHandlerImpl implements CloudAgentLoggingHandler {
}
return logListener;
}
+
+ @Override
+ public LogListener createConsole(String pipeName, final OutputStream consoleInput) {
+ final LoggingHandler loggingHandler = myLogManager.addAdditionalLog(pipeName);
+ loggingHandler.attachToProcess(new ProcessHandler() {
+
+ @Override
+ protected void destroyProcessImpl() {
+
+ }
+
+ @Override
+ protected void detachProcessImpl() {
+
+ }
+
+ @Override
+ public boolean detachIsDefault() {
+ return false;
+ }
+
+ @Nullable
+ @Override
+ public OutputStream getProcessInput() {
+ return consoleInput;
+ }
+ });
+
+ return new LogListener() {
+
+ @Override
+ public void lineLogged(String line) {
+ loggingHandler.print(line);
+ }
+ };
+ }
}
diff --git a/platform/remote-servers/impl/src/com/intellij/remoteServer/util/CloudSilentLoggingHandlerImpl.java b/platform/remote-servers/impl/src/com/intellij/remoteServer/util/CloudSilentLoggingHandlerImpl.java
index 49321fdfc398..31825120100a 100644
--- a/platform/remote-servers/impl/src/com/intellij/remoteServer/util/CloudSilentLoggingHandlerImpl.java
+++ b/platform/remote-servers/impl/src/com/intellij/remoteServer/util/CloudSilentLoggingHandlerImpl.java
@@ -4,6 +4,8 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.remoteServer.agent.util.CloudAgentLoggingHandler;
import com.intellij.remoteServer.agent.util.log.LogListener;
+import java.io.OutputStream;
+
/**
* @author michael.golubev
*/
@@ -20,4 +22,9 @@ public class CloudSilentLoggingHandlerImpl implements CloudAgentLoggingHandler {
public LogListener getOrCreateLogListener(String pipeName) {
return LogListener.NULL;
}
+
+ @Override
+ public LogListener createConsole(String pipeName, OutputStream consoleInput) {
+ return LogListener.NULL;
+ }
}
diff --git a/platform/script-debugger/backend/src/org/jetbrains/debugger/sourcemap/SourceMap.java b/platform/script-debugger/backend/src/org/jetbrains/debugger/sourcemap/SourceMap.java
index a69b3af26f69..057d96fd01eb 100644
--- a/platform/script-debugger/backend/src/org/jetbrains/debugger/sourcemap/SourceMap.java
+++ b/platform/script-debugger/backend/src/org/jetbrains/debugger/sourcemap/SourceMap.java
@@ -16,16 +16,23 @@ public class SourceMap {
private final String outFile;
private final SourceResolver sourceResolver;
+ private final boolean hasNameMappings;
// sources - is not originally specified, but canonicalized/normalized
public SourceMap(@Nullable String outFile,
@NotNull MappingList mappings,
@NotNull MappingList[] sourceIndexToMappings,
- @NotNull SourceResolver sourceResolver) {
+ @NotNull SourceResolver sourceResolver,
+ boolean hasNameMappings) {
this.outFile = outFile;
this.mappings = mappings;
this.sourceIndexToMappings = sourceIndexToMappings;
this.sourceResolver = sourceResolver;
+ this.hasNameMappings = hasNameMappings;
+ }
+
+ public boolean hasNameMappings() {
+ return hasNameMappings;
}
@NotNull
diff --git a/platform/script-debugger/backend/src/org/jetbrains/debugger/sourcemap/SourceMapDecoder.java b/platform/script-debugger/backend/src/org/jetbrains/debugger/sourcemap/SourceMapDecoder.java
index 27bd8abfe0ce..88ed91ce0580 100644
--- a/platform/script-debugger/backend/src/org/jetbrains/debugger/sourcemap/SourceMapDecoder.java
+++ b/platform/script-debugger/backend/src/org/jetbrains/debugger/sourcemap/SourceMapDecoder.java
@@ -5,6 +5,7 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.util.text.StringUtilRt;
import com.intellij.util.PathUtil;
import com.intellij.util.SmartList;
+import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.text.CharSequenceSubSequence;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -131,7 +132,12 @@ public final class SourceMapDecoder {
if (reader.peek() != JsonToken.END_ARRAY) {
sourcesContent = new SmartList<String>();
do {
- sourcesContent.add(StringUtilRt.convertLineSeparators(reader.nextString()));
+ if (reader.peek() == JsonToken.STRING) {
+ sourcesContent.add(StringUtilRt.convertLineSeparators(reader.nextString()));
+ }
+ else {
+ reader.skipValue();
+ }
}
while (reader.hasNext());
}
@@ -176,7 +182,7 @@ public final class SourceMapDecoder {
sourceToEntries[i] = new SourceMappingList(entries);
}
}
- return new SourceMap(file, new GeneratedMappingList(mappings), sourceToEntries, sourceResolverFactory.create(sources, sourcesContent));
+ return new SourceMap(file, new GeneratedMappingList(mappings), sourceToEntries, sourceResolverFactory.create(sources, sourcesContent), !ContainerUtil.isEmpty(names));
}
@Nullable
@@ -429,4 +435,4 @@ public final class SourceMapDecoder {
return MAPPING_COMPARATOR_BY_GENERATED_POSITION;
}
}
-} \ No newline at end of file
+}
diff --git a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/BasicDebuggerViewSupport.java b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/BasicDebuggerViewSupport.java
index a5cf778db7e2..b2fd544d0b86 100644
--- a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/BasicDebuggerViewSupport.java
+++ b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/BasicDebuggerViewSupport.java
@@ -97,6 +97,17 @@ public class BasicDebuggerViewSupport implements DebuggerViewSupport, MemberFilt
@NotNull
@Override
+ public String getName(@NotNull Variable variable) {
+ return variable.getName();
+ }
+
+ @Override
+ public boolean hasNameMappings() {
+ return false;
+ }
+
+ @NotNull
+ @Override
public String normalizeMemberName(@NotNull Variable variable) {
return variable.getName();
}
diff --git a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/LazyVariablesGroup.java b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/LazyVariablesGroup.java
index 25b8b3e11ee5..c00f6727203d 100644
--- a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/LazyVariablesGroup.java
+++ b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/LazyVariablesGroup.java
@@ -71,7 +71,7 @@ public final class LazyVariablesGroup extends XValueGroup {
@Override
public void consumeVariables(@NotNull List<Variable> variables) {
- node.addChildren(Variables.createVariablesList(variables, context), true);
+ node.addChildren(Variables.createVariablesList(variables, context, null), true);
}
}, componentType);
}
diff --git a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/MemberFilter.java b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/MemberFilter.java
index fb3a7c1f175c..b9b60178e5ff 100644
--- a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/MemberFilter.java
+++ b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/MemberFilter.java
@@ -9,4 +9,9 @@ public interface MemberFilter {
@NotNull
Collection<Variable> getAdditionalVariables();
+
+ @NotNull
+ String getName(@NotNull Variable variable);
+
+ boolean hasNameMappings();
} \ No newline at end of file
diff --git a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/VariableView.java b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/VariableView.java
index ada850da074b..9ee54199ff8c 100644
--- a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/VariableView.java
+++ b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/VariableView.java
@@ -57,7 +57,11 @@ public final class VariableView extends XNamedValue implements VariableContext {
private volatile int remainingChildrenOffset;
public VariableView(@NotNull Variable variable, @NotNull VariableContext context) {
- super(context.getViewSupport().normalizeMemberName(variable));
+ this(context.getViewSupport().normalizeMemberName(variable), variable, context);
+ }
+
+ public VariableView(@NotNull String name, @NotNull Variable variable, @NotNull VariableContext context) {
+ super(name);
this.context = context;
this.variable = variable;
@@ -162,14 +166,7 @@ public final class VariableView extends XNamedValue implements VariableContext {
@Override
public void consume(Value value, String error) {
if (!node.isObsolete()) {
- value = getViewSupport().transformErrorOnGetUsedReferenceValue(value, error);
- if (value == null) {
- node.setPresentation(AllIcons.Debugger.Db_primitive, null, error, false);
- }
- else {
- VariableView.this.value = value;
- computePresentation(value, node);
- }
+ setEvaluatedValue(getViewSupport().transformErrorOnGetUsedReferenceValue(value, error), error, node);
}
}
});
@@ -187,18 +184,29 @@ public final class VariableView extends XNamedValue implements VariableContext {
public void startEvaluation(@NotNull final XFullValueEvaluationCallback callback) {
ValueModifier valueModifier = variable.getValueModifier();
assert valueModifier != null;
- ObsolescentAsyncResults.consume(valueModifier.evaluateGet(variable, getEvaluateContext()), node, new PairConsumer<Value, XValueNode>() {
+ valueModifier.evaluateGet(variable, getEvaluateContext()).doWhenProcessed(new Consumer<Value>() {
@Override
- public void consume(Value value, XValueNode node) {
- callback.evaluated("");
- VariableView.this.value = value;
- computePresentation(value, node);
+ public void consume(Value value) {
+ if (!node.isObsolete()) {
+ callback.evaluated("");
+ setEvaluatedValue(value, null, node);
+ }
}
});
}
}.setShowValuePopup(false));
}
+ private void setEvaluatedValue(@Nullable Value value, @Nullable String error, @NotNull XValueNode node) {
+ if (value == null) {
+ node.setPresentation(AllIcons.Debugger.Db_primitive, null, error == null ? "Internal Error" : error, false);
+ }
+ else {
+ this.value = value;
+ computePresentation(value, node);
+ }
+ }
+
@NotNull
static String trimFunctionDescription(@NotNull Value value) {
String presentableValue = value.getValueString();
@@ -358,7 +366,7 @@ public final class VariableView extends XNamedValue implements VariableContext {
@Override
public void consumeVariables(@NotNull List<Variable> variables) {
- node.addChildren(Variables.createVariablesList(variables, VariableView.this), isLastChildren);
+ node.addChildren(Variables.createVariablesList(variables, VariableView.this, null), isLastChildren);
}
}, null);
}
@@ -395,7 +403,7 @@ public final class VariableView extends XNamedValue implements VariableContext {
int count = variables.size();
int bucketSize = XCompositeNode.MAX_CHILDREN_TO_SHOW;
if (count <= bucketSize) {
- node.addChildren(Variables.createVariablesList(variables, this), true);
+ node.addChildren(Variables.createVariablesList(variables, this, null), true);
return;
}
@@ -413,7 +421,7 @@ public final class VariableView extends XNamedValue implements VariableContext {
int notGroupedVariablesOffset;
if ((variables.size() - count) > bucketSize) {
for (notGroupedVariablesOffset = variables.size(); notGroupedVariablesOffset > 0; notGroupedVariablesOffset--) {
- if (!variables.get(notGroupedVariablesOffset - 1).getName().startsWith(Variables.SPECIAL_PROPERTY_PREFIX)) {
+ if (!variables.get(notGroupedVariablesOffset - 1).getName().startsWith("__")) {
break;
}
}
diff --git a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/Variables.java b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/Variables.java
index b71914443eef..e85091320bfb 100644
--- a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/Variables.java
+++ b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/Variables.java
@@ -18,13 +18,11 @@ import java.util.*;
import java.util.regex.Pattern;
public final class Variables {
- static final String SPECIAL_PROPERTY_PREFIX = "__";
-
private static final Pattern UNNAMED_FUNCTION_PATTERN = Pattern.compile("^function[\\t ]*\\(");
private static final Comparator<Variable> NATURAL_NAME_COMPARATOR = new Comparator<Variable>() {
@Override
- public int compare(Variable o1, Variable o2) {
+ public int compare(@NotNull Variable o1, @NotNull Variable o2) {
return naturalCompare(o1.getName(), o2.getName());
}
};
@@ -37,7 +35,7 @@ public final class Variables {
AsyncResult<?> result = ObsolescentAsyncResults.consume(scope.getVariables(), node, new PairConsumer<List<Variable>, XCompositeNode>() {
@Override
public void consume(List<Variable> variables, XCompositeNode node) {
- MemberFilter memberFilter = context.createMemberFilter();
+ final MemberFilter memberFilter = context.createMemberFilter();
Collection<Variable> additionalVariables = memberFilter.getAdditionalVariables();
List<Variable> properties = new ArrayList<Variable>(variables.size() + additionalVariables.size());
List<Variable> functions = new SmartList<Variable>();
@@ -56,7 +54,12 @@ public final class Variables {
}
}
- sort(properties);
+ ContainerUtil.sort(properties, memberFilter.hasNameMappings() ? new Comparator<Variable>() {
+ @Override
+ public int compare(@NotNull Variable o1, @NotNull Variable o2) {
+ return naturalCompare(memberFilter.getName(o1), memberFilter.getName(o2));
+ }
+ } : NATURAL_NAME_COMPARATOR);
sort(functions);
for (Variable variable : additionalVariables) {
@@ -64,7 +67,7 @@ public final class Variables {
}
if (!properties.isEmpty()) {
- node.addChildren(createVariablesList(properties, context), functions.isEmpty() && isLast);
+ node.addChildren(createVariablesList(properties, context, memberFilter), functions.isEmpty() && isLast);
}
if (!functions.isEmpty()) {
@@ -110,6 +113,7 @@ public final class Variables {
}
}
+ @NotNull
public static List<Variable> filterAndSort(@NotNull List<? extends Variable> variables, @NotNull VariableContext context, boolean filterFunctions) {
if (variables.isEmpty()) {
return Collections.emptyList();
@@ -219,16 +223,28 @@ public final class Variables {
return string1Length - string2Length;
}
+ @NotNull
public static XValueChildrenList createVariablesList(@NotNull List<Variable> variables, @NotNull VariableContext variableContext) {
- return createVariablesList(variables, 0, variables.size(), variableContext);
+ return createVariablesList(variables, variableContext, null);
+ }
+
+ @NotNull
+ public static XValueChildrenList createVariablesList(@NotNull List<Variable> variables, @NotNull VariableContext variableContext, @Nullable MemberFilter memberFilter) {
+ return createVariablesList(variables, 0, variables.size(), variableContext, memberFilter);
}
+ @NotNull
public static XValueChildrenList createVariablesList(@NotNull List<Variable> variables, int from, int to, @NotNull VariableContext variableContext) {
+ return createVariablesList(variables, from, to, variableContext, null);
+ }
+
+ @NotNull
+ public static XValueChildrenList createVariablesList(@NotNull List<Variable> variables, int from, int to, @NotNull VariableContext variableContext, @Nullable MemberFilter memberFilter) {
XValueChildrenList list = new XValueChildrenList(to - from);
VariableContext getterOrSetterContext = null;
for (int i = from; i < to; i++) {
Variable variable = variables.get(i);
- list.add(new VariableView(variable, variableContext));
+ list.add(memberFilter == null ? new VariableView(variable, variableContext) : new VariableView(memberFilter.getName(variable), variable, variableContext));
if (variable instanceof ObjectProperty) {
ObjectProperty property = (ObjectProperty)variable;
if (property.getGetter() != null) {
diff --git a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/frame/CallFrameView.java b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/frame/CallFrameView.java
index 3cb993a01194..03d960362183 100644
--- a/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/frame/CallFrameView.java
+++ b/platform/script-debugger/debugger-ui/src/org/jetbrains/debugger/frame/CallFrameView.java
@@ -36,6 +36,11 @@ public final class CallFrameView extends StackFrameImplBase implements VariableC
inLibraryContent = sourceInfo != null && debugProcess.isInLibraryContent(sourceInfo, script);
}
+ @Nullable
+ public Script getScript() {
+ return script;
+ }
+
@Override
protected boolean isInFileScope() {
List<Scope> scopes = callFrame.getVariableScopes();
diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralTestEventsProcessor.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralTestEventsProcessor.java
index 23145d52702f..a2f594d04cb2 100644
--- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralTestEventsProcessor.java
+++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/GeneralTestEventsProcessor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@ import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.util.Condition;
+import com.intellij.openapi.util.Conditions;
import com.intellij.openapi.util.Key;
import com.intellij.testIntegration.TestLocationProvider;
import com.intellij.util.Processor;
@@ -110,7 +111,7 @@ public abstract class GeneralTestEventsProcessor implements Disposable {
}
public Condition getDisposedCondition() {
- return Condition.FALSE;
+ return Conditions.alwaysFalse();
}
/**
diff --git a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/states/TestComparisionFailedState.java b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/states/TestComparisionFailedState.java
index 2d500115c038..461001d3b111 100644
--- a/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/states/TestComparisionFailedState.java
+++ b/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/states/TestComparisionFailedState.java
@@ -30,7 +30,7 @@ import org.jetbrains.annotations.Nullable;
/**
* @author Roman.Chernyatchik
*/
-public class TestComparisionFailedState extends TestFailedState implements AbstractTestProxy.AssertEqualsDiffViewerProvider {
+public class TestComparisionFailedState extends TestFailedState implements AbstractTestProxy.AssertEqualsMultiDiffViewProvider {
private final String myErrorMsgPresentation;
private final String myStacktracePresentation;
private DiffHyperlink myHyperlink;
@@ -77,4 +77,14 @@ public class TestComparisionFailedState extends TestFailedState implements Abstr
public String getActual() {
return myHyperlink.getRight();
}
+
+ @Override
+ public void openMultiDiff(Project project, AbstractTestProxy.AssertEqualsDiffChain chain) {
+ myHyperlink.openMultiDiff(project, chain);
+ }
+
+ @Override
+ public String getFilePath() {
+ return myHyperlink.getFilePath();
+ }
}
diff --git a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralReplaceTest.java b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralReplaceTest.java
index fe1b6e09d99f..ffdc2fb3459c 100644
--- a/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralReplaceTest.java
+++ b/platform/structuralsearch/testSource/com/intellij/structuralsearch/StructuralReplaceTest.java
@@ -1810,13 +1810,17 @@ public class StructuralReplaceTest extends StructuralReplaceTestCase {
}
public void testUseStaticImport() {
- final String in = "class X {{ Math.abs(-1); }}";
+ String in = "class X {{ Math.abs(-1); }}";
final String what = "Math.abs('a)";
final String by = "Math.abs($a$)";
options.setToUseStaticImport(true);
- final String expected = "import static java.lang.Math.abs;class X {{ abs(-1); }}";
+ String expected = "import static java.lang.Math.abs;class X {{ abs(-1); }}";
assertEquals("Replacing with static import", expected, replacer.testReplace(in, what, by, options, true));
+
+ in = "class X { void m(java.util.Random r) { Math.abs(r.nextInt()); }}";
+ expected = "import static java.lang.Math.abs;class X { void m(java.util.Random r) { abs(r.nextInt()); }}";
+ assertEquals("don't add broken static imports", expected, replacer.testReplace(in, what, by, options, true));
}
public void testUseStaticStarImport() {
diff --git a/platform/testFramework/src/com/intellij/mock/Mock.java b/platform/testFramework/src/com/intellij/mock/Mock.java
index 73d6538c52b9..a2768f2e1851 100644
--- a/platform/testFramework/src/com/intellij/mock/Mock.java
+++ b/platform/testFramework/src/com/intellij/mock/Mock.java
@@ -435,7 +435,7 @@ public class Mock {
}
@Override
- public void setSelectedEditor(@NotNull VirtualFile file, String fileEditorProviderId) {
+ public void setSelectedEditor(@NotNull VirtualFile file, @NotNull String fileEditorProviderId) {
}
}
diff --git a/platform/testFramework/src/com/intellij/mock/MockVirtualFileSystem.java b/platform/testFramework/src/com/intellij/mock/MockVirtualFileSystem.java
index 8550f973a8ea..9854cea82835 100644
--- a/platform/testFramework/src/com/intellij/mock/MockVirtualFileSystem.java
+++ b/platform/testFramework/src/com/intellij/mock/MockVirtualFileSystem.java
@@ -20,30 +20,37 @@ import com.intellij.openapi.vfs.DeprecatedVirtualFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileSystem;
import com.intellij.testFramework.LightVirtualFile;
+import gnu.trove.THashMap;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
-import java.util.HashMap;
+import java.util.Map;
public class MockVirtualFileSystem extends DeprecatedVirtualFileSystem {
private final MyVirtualFile myRoot = new MyVirtualFile("", null);
public static final String PROTOCOL = "mock";
@Override
+ @NotNull
public VirtualFile findFileByPath(@NotNull String path) {
path = path.replace(File.separatorChar, '/');
path = path.replace('/', ':');
if (StringUtil.startsWithChar(path, ':')) path = path.substring(1);
- String[] components = path.split(":");
MyVirtualFile file = myRoot;
- for (String component : components) {
+ for (String component : StringUtil.split(path, ":")) {
file = file.getOrCreate(component);
}
return file;
}
+ @NotNull
+ public VirtualFile getRoot() {
+ return myRoot;
+ }
+
@Override
@NotNull
public String getProtocol() {
@@ -93,11 +100,12 @@ public class MockVirtualFileSystem extends DeprecatedVirtualFileSystem {
}
public class MyVirtualFile extends LightVirtualFile {
- private final HashMap<String, MyVirtualFile> myChildren = new HashMap<String, MyVirtualFile>();
+ private final Map<String, MyVirtualFile> myChildren = new THashMap<String, MyVirtualFile>();
private final MyVirtualFile myParent;
- public MyVirtualFile(String name, MyVirtualFile parent) {
+ public MyVirtualFile(@NotNull String name, @Nullable MyVirtualFile parent) {
super(name);
+
myParent = parent;
}
@@ -107,7 +115,8 @@ public class MockVirtualFileSystem extends DeprecatedVirtualFileSystem {
return MockVirtualFileSystem.this;
}
- public MyVirtualFile getOrCreate(String name) {
+ @NotNull
+ public MyVirtualFile getOrCreate(@NotNull String name) {
MyVirtualFile file = myChildren.get(name);
if (file == null) {
file = new MyVirtualFile(name, this);
diff --git a/platform/testFramework/src/com/intellij/testFramework/FlyIdeaTestCase.java b/platform/testFramework/src/com/intellij/testFramework/FlyIdeaTestCase.java
index 02a39f148e24..098d76599f5b 100644
--- a/platform/testFramework/src/com/intellij/testFramework/FlyIdeaTestCase.java
+++ b/platform/testFramework/src/com/intellij/testFramework/FlyIdeaTestCase.java
@@ -1,36 +1,35 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package com.intellij.testFramework;
-import com.intellij.mock.MockApplicationEx;
import com.intellij.openapi.Disposable;
-import com.intellij.openapi.application.Application;
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.application.ex.ApplicationManagerEx;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.io.FileUtil;
import junit.framework.TestCase;
-import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
-import java.util.concurrent.Future;
public abstract class FlyIdeaTestCase extends TestCase {
-
- private Disposable myRootDisposable;
+ private final Disposable myRootDisposable = Disposer.newDisposable();
private File myTempDir;
@Override
protected void setUp() throws Exception {
- final Application old = ApplicationManagerEx.getApplication();
- myRootDisposable = Disposer.newDisposable();
- MockApplicationEx app = new MockApplicationEx(getRootDisposable()) {
- @NotNull
- @Override
- public Future<?> executeOnPooledThread(@NotNull Runnable action) {
- return old != null ? old.executeOnPooledThread(action) : super.executeOnPooledThread(action);
- }
- };
- ApplicationManager.setApplication(app, myRootDisposable);
+ LightPlatformTestCase.initApplication();
}
public File getTempDir() throws IOException {
diff --git a/platform/testFramework/src/com/intellij/testFramework/PlatformTestUtil.java b/platform/testFramework/src/com/intellij/testFramework/PlatformTestUtil.java
index ee6e519cb583..fcf0e225ea5f 100644
--- a/platform/testFramework/src/com/intellij/testFramework/PlatformTestUtil.java
+++ b/platform/testFramework/src/com/intellij/testFramework/PlatformTestUtil.java
@@ -413,7 +413,8 @@ public class PlatformTestUtil {
for (int i= n /2- n / part /2; i< n /2+ n / part /2; i++) {
total += time[i];
}
- return total/(n / part);
+ int middlePartLength = n / part;
+ return middlePartLength == 0 ? 0 : total / middlePartLength;
}
public static boolean canRunTest(@NotNull Class testCaseClass) {
diff --git a/platform/testFramework/src/com/intellij/testFramework/TestActionEvent.java b/platform/testFramework/src/com/intellij/testFramework/TestActionEvent.java
index 764e80453ad6..0f5ab8b3c8ae 100644
--- a/platform/testFramework/src/com/intellij/testFramework/TestActionEvent.java
+++ b/platform/testFramework/src/com/intellij/testFramework/TestActionEvent.java
@@ -16,10 +16,7 @@
package com.intellij.testFramework;
import com.intellij.ide.DataManager;
-import com.intellij.openapi.actionSystem.ActionManager;
-import com.intellij.openapi.actionSystem.AnAction;
-import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.actionSystem.*;
import org.jetbrains.annotations.NotNull;
/**
@@ -35,4 +32,8 @@ public class TestActionEvent extends AnActionEvent {
public TestActionEvent(@NotNull AnAction action) {
this(DataManager.getInstance().getDataContext(), action);
}
+
+ public TestActionEvent() {
+ super(null, DataManager.getInstance().getDataContext(), "", new Presentation(), ActionManager.getInstance(), 0);
+ }
}
diff --git a/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java b/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java
index 6deda3d4b70a..6f03fd02446e 100644
--- a/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java
+++ b/platform/testFramework/src/com/intellij/testFramework/UsefulTestCase.java
@@ -224,7 +224,7 @@ public abstract class UsefulTestCase extends TestCase {
}
public static CompositeException doCheckForSettingsDamage(@NotNull CodeStyleSettings oldCodeStyleSettings,
- @NotNull CodeStyleSettings currentCodeStyleSettings) throws Exception {
+ @NotNull CodeStyleSettings currentCodeStyleSettings) throws Exception {
CompositeException result = new CompositeException();
final CodeInsightSettings settings = CodeInsightSettings.getInstance();
try {
@@ -234,9 +234,13 @@ public abstract class UsefulTestCase extends TestCase {
}
catch (AssertionError error) {
CodeInsightSettings clean = new CodeInsightSettings();
- Element temp = new Element("temp");
- clean.writeExternal(temp);
- settings.loadState(temp);
+ for (Field field : clean.getClass().getFields()) {
+ try {
+ ReflectionUtil.copyFieldValue(clean, settings, field);
+ }
+ catch (Exception ignored) {
+ }
+ }
result.add(error);
}
diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/IdeaTestFixtureFactory.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/IdeaTestFixtureFactory.java
index 010caad8fcd2..ecc5bff4dc50 100644
--- a/platform/testFramework/src/com/intellij/testFramework/fixtures/IdeaTestFixtureFactory.java
+++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/IdeaTestFixtureFactory.java
@@ -37,6 +37,7 @@ public abstract class IdeaTestFixtureFactory {
}
}
+ @NotNull
public static IdeaTestFixtureFactory getFixtureFactory() {
return ourInstance;
}
@@ -59,6 +60,7 @@ public abstract class IdeaTestFixtureFactory {
public abstract TestFixtureBuilder<IdeaProjectTestFixture> createFixtureBuilder(@NotNull String name);
+ @NotNull
public abstract TestFixtureBuilder<IdeaProjectTestFixture> createLightFixtureBuilder();
public abstract TestFixtureBuilder<IdeaProjectTestFixture> createLightFixtureBuilder(@Nullable LightProjectDescriptor projectDescriptor);
diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/TestFixtureBuilder.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/TestFixtureBuilder.java
index b275ec521c8c..1d0e648611ef 100644
--- a/platform/testFramework/src/com/intellij/testFramework/fixtures/TestFixtureBuilder.java
+++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/TestFixtureBuilder.java
@@ -17,11 +17,13 @@
package com.intellij.testFramework.fixtures;
import com.intellij.testFramework.builders.ModuleFixtureBuilder;
+import org.jetbrains.annotations.NotNull;
/**
* @author mike
*/
public interface TestFixtureBuilder<T extends IdeaTestFixture> {
+ @NotNull
T getFixture();
<M extends ModuleFixtureBuilder> M addModule(Class<M> builderClass);
diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java
index 8aafb17da1de..f4264f760cd9 100644
--- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java
+++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java
@@ -185,7 +185,7 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig
}
VirtualFile result;
- final String path = fromFile.getPath();
+ final String path = fromFile.getAbsolutePath();
if (myTempDirFixture instanceof LightTempDirTestFixtureImpl) {
VfsRootAccess.allowRootAccess(path);
Disposer.register(myTestRootDisposable, new Disposable() {
@@ -1025,13 +1025,9 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig
final CodeCompletionHandlerBase handler = new CodeCompletionHandlerBase(type) {
@Override
- protected void completionFinished(int offset1,
- int offset2,
- CompletionProgressIndicator indicator,
- LookupElement[] items,
- boolean hasModifiers) {
- myEmptyLookup = items.length == 0;
- super.completionFinished(offset1, offset2, indicator, items, hasModifiers);
+ protected void completionFinished(CompletionProgressIndicator indicator, boolean hasModifiers) {
+ myEmptyLookup = indicator.getLookup().getItems().isEmpty();
+ super.completionFinished(indicator, hasModifiers);
}
};
Editor editor = getCompletionEditor();
diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/HeavyTestFixtureBuilderImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/HeavyTestFixtureBuilderImpl.java
index c7b7779fe92a..412c87ee5bce 100644
--- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/HeavyTestFixtureBuilderImpl.java
+++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/HeavyTestFixtureBuilderImpl.java
@@ -22,6 +22,7 @@ import com.intellij.testFramework.fixtures.IdeaProjectTestFixture;
import com.intellij.testFramework.fixtures.TestFixtureBuilder;
import com.intellij.util.pico.ConstructorInjectionComponentAdapter;
import com.intellij.util.pico.IdeaPicoContainer;
+import org.jetbrains.annotations.NotNull;
import org.picocontainer.MutablePicoContainer;
import java.lang.reflect.Field;
@@ -50,6 +51,7 @@ class HeavyTestFixtureBuilderImpl implements TestFixtureBuilder<IdeaProjectTestF
return (M)adapter.getComponentInstance(myContainer);
}
+ @NotNull
@Override
public HeavyIdeaTestFixture getFixture() {
return myFixture;
diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/IdeaTestFixtureFactoryImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/IdeaTestFixtureFactoryImpl.java
index ce73993b60a7..1b375d401d0e 100644
--- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/IdeaTestFixtureFactoryImpl.java
+++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/IdeaTestFixtureFactoryImpl.java
@@ -62,6 +62,7 @@ public class IdeaTestFixtureFactoryImpl extends IdeaTestFixtureFactory {
return new HeavyTestFixtureBuilderImpl(new HeavyIdeaTestFixtureImpl(name), myFixtureBuilderProviders);
}
+ @NotNull
@Override
public TestFixtureBuilder<IdeaProjectTestFixture> createLightFixtureBuilder() {
return new LightTestFixtureBuilderImpl<IdeaProjectTestFixture>(new LightIdeaTestFixtureImpl(
diff --git a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/LightTestFixtureBuilderImpl.java b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/LightTestFixtureBuilderImpl.java
index 43a2ee7c031c..a196e4211649 100644
--- a/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/LightTestFixtureBuilderImpl.java
+++ b/platform/testFramework/src/com/intellij/testFramework/fixtures/impl/LightTestFixtureBuilderImpl.java
@@ -19,6 +19,7 @@ package com.intellij.testFramework.fixtures.impl;
import com.intellij.testFramework.builders.ModuleFixtureBuilder;
import com.intellij.testFramework.fixtures.IdeaProjectTestFixture;
import com.intellij.testFramework.fixtures.TestFixtureBuilder;
+import org.jetbrains.annotations.NotNull;
/**
* @author mike
@@ -31,6 +32,7 @@ class LightTestFixtureBuilderImpl<F extends IdeaProjectTestFixture> implements T
myFixture = fixture;
}
+ @NotNull
@Override
public F getFixture() {
return myFixture;
diff --git a/platform/testFramework/testFramework.iml b/platform/testFramework/testFramework.iml
index 7985252e6abc..19a4097b1f15 100644
--- a/platform/testFramework/testFramework.iml
+++ b/platform/testFramework/testFramework.iml
@@ -20,7 +20,7 @@
<orderEntry type="library" exported="" scope="TEST" name="Mocks" level="project" />
<orderEntry type="module" module-name="java-runtime" exported="" />
<orderEntry type="module" module-name="vcs-impl" />
- <orderEntry type="library" name="Groovy" level="project" />
+ <orderEntry type="library" exported="" name="Groovy" level="project" />
<orderEntry type="module" module-name="platform-resources" exported="" scope="RUNTIME" />
<orderEntry type="module" module-name="dom-impl" exported="" scope="RUNTIME" />
<orderEntry type="module" module-name="relaxng" exported="" scope="RUNTIME" />
diff --git a/platform/testRunner/src/com/intellij/execution/testframework/AbstractTestProxy.java b/platform/testRunner/src/com/intellij/execution/testframework/AbstractTestProxy.java
index 73ecdb2ddd8c..7b84c66ae2ac 100644
--- a/platform/testRunner/src/com/intellij/execution/testframework/AbstractTestProxy.java
+++ b/platform/testRunner/src/com/intellij/execution/testframework/AbstractTestProxy.java
@@ -143,4 +143,16 @@ public abstract class AbstractTestProxy extends CompositePrintable {
String getExpected();
String getActual();
}
+
+ public interface AssertEqualsDiffChain {
+ AssertEqualsMultiDiffViewProvider getPrevious();
+ AssertEqualsMultiDiffViewProvider getCurrent();
+ AssertEqualsMultiDiffViewProvider getNext();
+ void setCurrent(AssertEqualsMultiDiffViewProvider provider);
+ }
+
+ public interface AssertEqualsMultiDiffViewProvider extends AssertEqualsDiffViewerProvider {
+ void openMultiDiff(Project project, AssertEqualsDiffChain chain);
+ String getFilePath();
+ }
}
diff --git a/platform/testRunner/src/com/intellij/execution/testframework/Filter.java b/platform/testRunner/src/com/intellij/execution/testframework/Filter.java
index 7d43fcd2a7e1..8dd6363c5940 100644
--- a/platform/testRunner/src/com/intellij/execution/testframework/Filter.java
+++ b/platform/testRunner/src/com/intellij/execution/testframework/Filter.java
@@ -61,42 +61,49 @@ public abstract class Filter<T extends AbstractTestProxy> {
}
public static final Filter NO_FILTER = new Filter() {
+ @Override
public boolean shouldAccept(final AbstractTestProxy test) {
return true;
}
};
public static final Filter DEFECT = new Filter() {
+ @Override
public boolean shouldAccept(final AbstractTestProxy test) {
return test.isDefect();
}
};
public static final Filter IGNORED = new Filter() {
+ @Override
public boolean shouldAccept(final AbstractTestProxy test) {
return test.isIgnored();
}
};
public static final Filter NOT_PASSED = new Filter() {
+ @Override
public boolean shouldAccept(final AbstractTestProxy test) {
return !test.isPassed();
}
};
public static final Filter PASSED = new Filter() {
+ @Override
public boolean shouldAccept(final AbstractTestProxy test) {
return test.isPassed();
}
};
public static final Filter FAILED_OR_INTERRUPTED = new Filter() {
+ @Override
public boolean shouldAccept(final AbstractTestProxy test) {
return test.isInterrupted() || test.isDefect();
}
};
public static final Filter LEAF = new Filter() {
+ @Override
public boolean shouldAccept(final AbstractTestProxy test) {
return test.isLeaf();
}
@@ -122,6 +129,7 @@ public abstract class Filter<T extends AbstractTestProxy> {
myFilter2 = filter2;
}
+ @Override
public boolean shouldAccept(final AbstractTestProxy test) {
return myFilter1.shouldAccept(test) && myFilter2.shouldAccept(test);
}
@@ -134,6 +142,7 @@ public abstract class Filter<T extends AbstractTestProxy> {
myFilter = filter;
}
+ @Override
public boolean shouldAccept(final AbstractTestProxy test) {
return !myFilter.shouldAccept(test);
}
@@ -148,6 +157,7 @@ public abstract class Filter<T extends AbstractTestProxy> {
myFilter2 = filter2;
}
+ @Override
public boolean shouldAccept(final AbstractTestProxy test) {
return myFilter1.shouldAccept(test) || myFilter2.shouldAccept(test);
}
diff --git a/platform/testRunner/src/com/intellij/execution/testframework/TestTreeView.java b/platform/testRunner/src/com/intellij/execution/testframework/TestTreeView.java
index 839568b4c2a9..5d1d2b346a85 100644
--- a/platform/testRunner/src/com/intellij/execution/testframework/TestTreeView.java
+++ b/platform/testRunner/src/com/intellij/execution/testframework/TestTreeView.java
@@ -46,6 +46,8 @@ import java.util.ArrayList;
import java.util.List;
public abstract class TestTreeView extends Tree implements DataProvider, CopyProvider {
+ public static final DataKey<TestFrameworkRunningModel> MODEL_DATA_KEY = DataKey.create("testFrameworkModel.dataId");
+
private TestFrameworkRunningModel myModel;
protected abstract TreeCellRenderer getRenderer(TestConsoleProperties properties);
@@ -127,7 +129,11 @@ public abstract class TestTreeView extends Tree implements DataProvider, CopyPro
return locations.isEmpty() ? null : locations.toArray(new Location[locations.size()]);
}
}
-
+
+ if (MODEL_DATA_KEY.is(dataId)) {
+ return myModel;
+ }
+
final TreePath selectionPath = getSelectionPath();
if (selectionPath == null) return null;
final AbstractTestProxy testProxy = getSelectedTest(selectionPath);
@@ -162,7 +168,6 @@ public abstract class TestTreeView extends Tree implements DataProvider, CopyPro
});
TreeUtil.installActions(this);
PopupHandler.installPopupHandler(this, IdeActions.GROUP_TESTTREE_POPUP, ActionPlaces.TESTTREE_VIEW_POPUP);
- ViewAssertEqualsDiffAction.registerShortcut(this);
}
@JdkConstants.TreeSelectionMode
diff --git a/platform/testRunner/src/com/intellij/execution/testframework/TestTreeViewAction.java b/platform/testRunner/src/com/intellij/execution/testframework/TestTreeViewAction.java
new file mode 100644
index 000000000000..8a700d1b5dbd
--- /dev/null
+++ b/platform/testRunner/src/com/intellij/execution/testframework/TestTreeViewAction.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.execution.testframework;
+
+public interface TestTreeViewAction {
+}
diff --git a/platform/testRunner/src/com/intellij/execution/testframework/TestTreeViewActionsPromoter.java b/platform/testRunner/src/com/intellij/execution/testframework/TestTreeViewActionsPromoter.java
new file mode 100644
index 000000000000..445c33c682be
--- /dev/null
+++ b/platform/testRunner/src/com/intellij/execution/testframework/TestTreeViewActionsPromoter.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.execution.testframework;
+
+import com.intellij.openapi.actionSystem.ActionPromoter;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.DataContext;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+public class TestTreeViewActionsPromoter implements ActionPromoter {
+ @Override
+ public List<AnAction> promote(List<AnAction> actions, DataContext context) {
+ if (AbstractTestProxy.DATA_KEY.getData(context) != null) {
+ for (AnAction action : actions) {
+ if (action instanceof TestTreeViewAction) {
+ return Arrays.asList(action);
+ }
+ }
+ }
+ return Collections.emptyList();
+ }
+}
diff --git a/platform/testRunner/src/com/intellij/execution/testframework/TestsUIUtil.java b/platform/testRunner/src/com/intellij/execution/testframework/TestsUIUtil.java
index 836635a58b0e..cbb0373f34c1 100644
--- a/platform/testRunner/src/com/intellij/execution/testframework/TestsUIUtil.java
+++ b/platform/testRunner/src/com/intellij/execution/testframework/TestsUIUtil.java
@@ -86,7 +86,7 @@ public class TestsUIUtil {
}
return false;
}
-
+
public static Navigatable getOpenFileDescriptor(final AbstractTestProxy testProxy, final TestFrameworkRunningModel model) {
final TestConsoleProperties testConsoleProperties = model.getProperties();
return getOpenFileDescriptor(testProxy, testConsoleProperties,
@@ -114,7 +114,7 @@ public class TestsUIUtil {
public static void notifyByBalloon(@NotNull final Project project,
boolean started,
final AbstractTestProxy root,
- final TestConsoleProperties properties,
+ final TestConsoleProperties properties,
@Nullable final String comment) {
if (project.isDisposed()) return;
if (properties == null) return;
@@ -231,7 +231,7 @@ public class TestsUIUtil {
myType = MessageType.ERROR;
}
else if (notStartedCount > 0) {
- myTitle = !notStarted.isEmpty() ? ExecutionBundle.message("junit.runing.info.failed.to.start.error.message") : "Tests Ignored";
+ myTitle = !notStarted.isEmpty() ? ExecutionBundle.message("junit.running.info.failed.to.start.error.message") : "Tests Ignored";
myText = passedCount + " passed, " + notStartedCount + (!notStarted.isEmpty() ? " not started" : " ignored");
myType = notStarted.isEmpty() ? MessageType.WARNING : MessageType.ERROR;
}
diff --git a/platform/testRunner/src/com/intellij/execution/testframework/actions/AbstractRerunFailedTestsAction.java b/platform/testRunner/src/com/intellij/execution/testframework/actions/AbstractRerunFailedTestsAction.java
index 30f8599e2aaf..a7d036b33ef7 100644
--- a/platform/testRunner/src/com/intellij/execution/testframework/actions/AbstractRerunFailedTestsAction.java
+++ b/platform/testRunner/src/com/intellij/execution/testframework/actions/AbstractRerunFailedTestsAction.java
@@ -34,20 +34,20 @@ import com.intellij.execution.testframework.Filter;
import com.intellij.execution.testframework.TestConsoleProperties;
import com.intellij.execution.testframework.TestFrameworkRunningModel;
import com.intellij.idea.ActionsBundle;
-import com.intellij.openapi.Disposable;
-import com.intellij.openapi.actionSystem.*;
+import com.intellij.openapi.actionSystem.ActionManager;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.options.SettingsEditor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.ComponentContainer;
import com.intellij.openapi.ui.popup.JBPopupFactory;
-import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Getter;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.ui.components.JBList;
-import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.UIUtil;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
@@ -57,40 +57,24 @@ import javax.swing.*;
import java.awt.*;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashMap;
import java.util.List;
-public class AbstractRerunFailedTestsAction extends AnAction implements AnAction.TransparentUpdate, Disposable {
- private static final List<AbstractRerunFailedTestsAction> registry = ContainerUtil.createLockFreeCopyOnWriteList();
- private static final Logger LOG = Logger.getInstance("#com.intellij.execution.junit2.ui.actions.RerunFailedTestsAction");
+public class AbstractRerunFailedTestsAction extends AnAction implements AnAction.TransparentUpdate {
+ private static final Logger LOG = Logger.getInstance(AbstractRerunFailedTestsAction.class);
+
private TestFrameworkRunningModel myModel;
private Getter<TestFrameworkRunningModel> myModelProvider;
protected TestConsoleProperties myConsoleProperties;
- protected ExecutionEnvironment myEnvironment;
- private final JComponent myParent;
-
- @SuppressWarnings("UnusedDeclaration")
- public AbstractRerunFailedTestsAction() {
- //We call this constructor with a little help from reflection.
- myParent = null;
- }
protected AbstractRerunFailedTestsAction(@NotNull ComponentContainer componentContainer) {
- myParent = componentContainer.getComponent();
- registry.add(this);
- Disposer.register(componentContainer, this);
copyFrom(ActionManager.getInstance().getAction("RerunFailedTests"));
- registerCustomShortcutSet(getShortcutSet(), myParent);
+ registerCustomShortcutSet(getShortcutSet(), componentContainer.getComponent());
}
- @Override
- public void dispose() {
- registry.remove(this);
- }
-
- public void init(final TestConsoleProperties consoleProperties,
- final ExecutionEnvironment environment) {
- myEnvironment = environment;
+ public void init(TestConsoleProperties consoleProperties) {
myConsoleProperties = consoleProperties;
}
@@ -102,48 +86,27 @@ public class AbstractRerunFailedTestsAction extends AnAction implements AnAction
myModelProvider = modelProvider;
}
- @NotNull
- private AbstractRerunFailedTestsAction findActualAction() {
- if (myParent != null || registry.isEmpty())
- return this;
- List<AbstractRerunFailedTestsAction> candidates = new ArrayList<AbstractRerunFailedTestsAction>(registry);
- Collections.sort(candidates, new Comparator<AbstractRerunFailedTestsAction>() {
- @Override
- public int compare(AbstractRerunFailedTestsAction action1, AbstractRerunFailedTestsAction action2) {
- Window window1 = SwingUtilities.windowForComponent(action1.myParent);
- Window window2 = SwingUtilities.windowForComponent(action2.myParent);
- if (window1 == null)
- return 1;
- if (window2 == null)
- return -1;
- boolean showing1 = action1.myParent.isShowing();
- boolean showing2 = action2.myParent.isShowing();
- if (showing1 && !showing2)
- return -1;
- if (showing2 && !showing1)
- return 1;
- return (window1.isActive() ? -1 : 1);
- }
- });
- return candidates.get(0);
- }
-
@Override
- public final void update(AnActionEvent e) {
- AbstractRerunFailedTestsAction action = findActualAction();
- e.getPresentation().setEnabled(action.isActive(e));
+ public final void update(@NotNull AnActionEvent e) {
+ e.getPresentation().setEnabled(isActive(e));
}
private boolean isActive(AnActionEvent e) {
- DataContext dataContext = e.getDataContext();
- Project project = CommonDataKeys.PROJECT.getData(dataContext);
- if (project == null) return false;
+ Project project = e.getProject();
+ if (project == null) {
+ return false;
+ }
+
TestFrameworkRunningModel model = getModel();
- if (model == null || model.getRoot() == null) return false;
- final List<? extends AbstractTestProxy> myAllTests = model.getRoot().getAllTests();
- final Filter filter = getFailuresFilter();
- for (Object test : myAllTests) {
- if (filter.shouldAccept((AbstractTestProxy)test)) return true;
+ if (model == null || model.getRoot() == null) {
+ return false;
+ }
+ Filter filter = getFailuresFilter();
+ for (AbstractTestProxy test : model.getRoot().getAllTests()) {
+ //noinspection unchecked
+ if (filter.shouldAccept(test)) {
+ return true;
+ }
}
return false;
}
@@ -151,10 +114,10 @@ public class AbstractRerunFailedTestsAction extends AnAction implements AnAction
@NotNull
protected List<AbstractTestProxy> getFailedTests(Project project) {
TestFrameworkRunningModel model = getModel();
- final List<? extends AbstractTestProxy> myAllTests = model != null
- ? model.getRoot().getAllTests()
- : Collections.<AbstractTestProxy>emptyList();
- return getFilter(project, model != null ? model.getProperties().getScope() : GlobalSearchScope.allScope(project)).select(myAllTests);
+ //noinspection unchecked
+ return getFilter(project, model != null ? model.getProperties().getScope() : GlobalSearchScope.allScope(project)).select(model != null
+ ? model.getRoot().getAllTests()
+ : Collections.<AbstractTestProxy>emptyList());
}
@NotNull
@@ -162,7 +125,7 @@ public class AbstractRerunFailedTestsAction extends AnAction implements AnAction
return getFailuresFilter();
}
- protected Filter getFailuresFilter() {
+ protected Filter<?> getFailuresFilter() {
if (TestConsoleProperties.INCLUDE_NON_STARTED_IN_RERUN_FAILED.value(myConsoleProperties)) {
return Filter.NOT_PASSED.and(Filter.IGNORED.not()).or(Filter.FAILED_OR_INTERRUPTED);
}
@@ -170,30 +133,27 @@ public class AbstractRerunFailedTestsAction extends AnAction implements AnAction
}
@Override
- public void actionPerformed(AnActionEvent e) {
- findActualAction().showPopup(e);
- }
+ public void actionPerformed(@NotNull AnActionEvent e) {
+ ExecutionEnvironment environment = e.getData(LangDataKeys.EXECUTION_ENVIRONMENT);
+ if (environment == null) {
+ return;
+ }
- private void showPopup(AnActionEvent e) {
- boolean isDebug = myConsoleProperties.isDebug();
- final MyRunProfile profile = getRunProfile();
+ MyRunProfile profile = getRunProfile(environment);
if (profile == null) {
return;
}
- final Executor executor = isDebug ? DefaultDebugExecutor.getDebugExecutorInstance() : DefaultRunExecutor.getRunExecutorInstance();
+ final ExecutionEnvironmentBuilder environmentBuilder = new ExecutionEnvironmentBuilder(environment).runProfile(profile);
final InputEvent event = e.getInputEvent();
if (!(event instanceof MouseEvent) || !event.isShiftDown()) {
- final ProgramRunner runner = RunnerRegistry.getInstance().getRunner(executor.getId(), profile);
- LOG.assertTrue(runner != null);
- performAction(runner, profile, myEnvironment.getExecutor());
+ performAction(environmentBuilder);
return;
}
final LinkedHashMap<Executor, ProgramRunner> availableRunners = new LinkedHashMap<Executor, ProgramRunner>();
- final Executor[] executors = new Executor[] {DefaultRunExecutor.getRunExecutorInstance(), DefaultDebugExecutor.getDebugExecutorInstance()};
- for (Executor ex : executors) {
+ for (Executor ex : new Executor[] {DefaultRunExecutor.getRunExecutorInstance(), DefaultDebugExecutor.getDebugExecutorInstance()}) {
final ProgramRunner runner = RunnerRegistry.getInstance().getRunner(ex.getId(), profile);
if (runner != null) {
availableRunners.put(ex, runner);
@@ -201,19 +161,20 @@ public class AbstractRerunFailedTestsAction extends AnAction implements AnAction
}
if (availableRunners.isEmpty()) {
- LOG.error(executor.getActionName() + " is not available now");
- return;
+ LOG.error(environment.getExecutor().getActionName() + " is not available now");
}
-
- if (availableRunners.size() == 1) {
- performAction(availableRunners.get(executor), profile, executor);
- } else {
+ else if (availableRunners.size() == 1) {
+ //noinspection ConstantConditions
+ performAction(environmentBuilder.runner(availableRunners.get(environment.getExecutor())));
+ }
+ else {
final JBList list = new JBList(availableRunners.keySet());
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
- list.setSelectedValue(executor, true);
+ list.setSelectedValue(environment.getExecutor(), true);
list.setCellRenderer(new DefaultListCellRenderer() {
+ @NotNull
@Override
- public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+ public Component getListCellRendererComponent(@NotNull JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
final Component component = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (value instanceof Executor) {
setText(UIUtil.removeMnemonic(((Executor)value).getStartActionText()));
@@ -222,6 +183,7 @@ public class AbstractRerunFailedTestsAction extends AnAction implements AnAction
return component;
}
});
+ //noinspection ConstantConditions
JBPopupFactory.getInstance().createListPopupBuilder(list)
.setTitle("Restart Failed Tests")
.setMovable(false)
@@ -232,35 +194,39 @@ public class AbstractRerunFailedTestsAction extends AnAction implements AnAction
public void run() {
final Object value = list.getSelectedValue();
if (value instanceof Executor) {
- performAction(availableRunners.get(value), profile, (Executor)value);
+ //noinspection ConstantConditions
+ performAction(environmentBuilder.runner(availableRunners.get(value)).executor((Executor)value));
}
}
}).createPopup().showUnderneathOf(event.getComponent());
}
}
- private void performAction(ProgramRunner runner, MyRunProfile profile, Executor executor) {
+ private static void performAction(@NotNull ExecutionEnvironmentBuilder builder) {
+ ExecutionEnvironment environment = builder.build();
try {
- new ExecutionEnvironmentBuilder(myEnvironment)
- .runner(runner)
- .executor(executor)
- .runProfile(profile)
- .buildAndExecute();
+ environment.getRunner().execute(environment);
}
- catch (ExecutionException e1) {
- LOG.error(e1);
+ catch (ExecutionException e) {
+ LOG.error(e);
}
finally {
- profile.clear();
+ ((MyRunProfile)environment.getRunProfile()).clear();
}
}
- @Nullable
+ @Deprecated
public MyRunProfile getRunProfile() {
return null;
}
@Nullable
+ protected MyRunProfile getRunProfile(@NotNull ExecutionEnvironment environment) {
+ //noinspection deprecation
+ return getRunProfile();
+ }
+
+ @Nullable
public TestFrameworkRunningModel getModel() {
if (myModel != null) {
return myModel;
@@ -293,7 +259,6 @@ public class AbstractRerunFailedTestsAction extends AnAction implements AnAction
public void clear() {
}
-
@Override
public void checkConfiguration() throws RuntimeConfigurationException {
}
@@ -351,6 +316,7 @@ public class AbstractRerunFailedTestsAction extends AnAction implements AnAction
return myConfiguration.getPredefinedLogFiles();
}
+ @NotNull
@Override
public ArrayList<LogFileOptions> getAllLogFiles() {
return myConfiguration.getAllLogFiles();
diff --git a/platform/testRunner/src/com/intellij/execution/testframework/actions/RerunFailedTestsAction.java b/platform/testRunner/src/com/intellij/execution/testframework/actions/RerunFailedTestsAction.java
new file mode 100644
index 000000000000..af15e3c14ce1
--- /dev/null
+++ b/platform/testRunner/src/com/intellij/execution/testframework/actions/RerunFailedTestsAction.java
@@ -0,0 +1,12 @@
+package com.intellij.execution.testframework.actions;
+
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import org.jetbrains.annotations.NotNull;
+
+class RerunFailedTestsAction extends AnAction {
+ @Override
+ public void actionPerformed(@NotNull AnActionEvent e) {
+ throw new IllegalStateException("Action only as template");
+ }
+}
diff --git a/platform/testRunner/src/com/intellij/execution/testframework/actions/ViewAssertEqualsDiffAction.java b/platform/testRunner/src/com/intellij/execution/testframework/actions/ViewAssertEqualsDiffAction.java
index fd80ea0154db..5d19c5ee0877 100644
--- a/platform/testRunner/src/com/intellij/execution/testframework/actions/ViewAssertEqualsDiffAction.java
+++ b/platform/testRunner/src/com/intellij/execution/testframework/actions/ViewAssertEqualsDiffAction.java
@@ -16,13 +16,15 @@
package com.intellij.execution.testframework.actions;
-import com.intellij.execution.testframework.AbstractTestProxy;
+import com.intellij.execution.testframework.*;
import com.intellij.openapi.actionSystem.*;
+import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NonNls;
-import javax.swing.*;
+import java.util.ArrayList;
+import java.util.List;
-public class ViewAssertEqualsDiffAction extends AnAction {
+public class ViewAssertEqualsDiffAction extends AnAction implements TestTreeViewAction {
@NonNls public static final String ACTION_ID = "openAssertEqualsDiff";
public void actionPerformed(final AnActionEvent e) {
@@ -30,11 +32,35 @@ public class ViewAssertEqualsDiffAction extends AnAction {
if (testProxy != null) {
final AbstractTestProxy.AssertEqualsDiffViewerProvider diffViewerProvider = testProxy.getDiffViewerProvider();
if (diffViewerProvider != null) {
- diffViewerProvider.openDiff(CommonDataKeys.PROJECT.getData(e.getDataContext()));
+ final Project project = CommonDataKeys.PROJECT.getData(e.getDataContext());
+ if (diffViewerProvider instanceof AbstractTestProxy.AssertEqualsMultiDiffViewProvider) {
+ final TestFrameworkRunningModel runningModel = TestTreeView.MODEL_DATA_KEY.getData(e.getDataContext());
+ final List<AbstractTestProxy.AssertEqualsMultiDiffViewProvider> providers = collectAvailableProviders(runningModel);
+ final MyAssertEqualsDiffChain diffChain =
+ providers.size() > 1 ? new MyAssertEqualsDiffChain(providers, (AbstractTestProxy.AssertEqualsMultiDiffViewProvider)diffViewerProvider) : null;
+ ((AbstractTestProxy.AssertEqualsMultiDiffViewProvider)diffViewerProvider).openMultiDiff(project, diffChain);
+ } else {
+ diffViewerProvider.openDiff(project);
+ }
}
}
}
+ private static List<AbstractTestProxy.AssertEqualsMultiDiffViewProvider> collectAvailableProviders(TestFrameworkRunningModel model) {
+ final List<AbstractTestProxy.AssertEqualsMultiDiffViewProvider> providers = new ArrayList<AbstractTestProxy.AssertEqualsMultiDiffViewProvider>();
+ if (model != null) {
+ final AbstractTestProxy root = model.getRoot();
+ final List<? extends AbstractTestProxy> allTests = root.getAllTests();
+ for (AbstractTestProxy test : allTests) {
+ final AbstractTestProxy.AssertEqualsDiffViewerProvider provider = test.getDiffViewerProvider();
+ if (provider instanceof AbstractTestProxy.AssertEqualsMultiDiffViewProvider) {
+ providers.add((AbstractTestProxy.AssertEqualsMultiDiffViewProvider)provider);
+ }
+ }
+ }
+ return providers;
+ }
+
public void update(final AnActionEvent e) {
final Presentation presentation = e.getPresentation();
final boolean enabled;
@@ -55,7 +81,38 @@ public class ViewAssertEqualsDiffAction extends AnAction {
presentation.setVisible(enabled);
}
- public static void registerShortcut(final JComponent component) {
- ActionManager.getInstance().getAction(ACTION_ID).registerCustomShortcutSet(CommonShortcuts.ALT_ENTER, component);
+ private static class MyAssertEqualsDiffChain implements AbstractTestProxy.AssertEqualsDiffChain {
+
+
+ private final List<AbstractTestProxy.AssertEqualsMultiDiffViewProvider> myProviders;
+ private AbstractTestProxy.AssertEqualsMultiDiffViewProvider myProvider;
+
+ public MyAssertEqualsDiffChain(List<AbstractTestProxy.AssertEqualsMultiDiffViewProvider> providers,
+ AbstractTestProxy.AssertEqualsMultiDiffViewProvider provider) {
+ myProviders = providers;
+ myProvider = provider;
+ }
+
+ @Override
+ public AbstractTestProxy.AssertEqualsMultiDiffViewProvider getPrevious() {
+ final int prevIdx = (myProviders.size() + myProviders.indexOf(myProvider) - 1) % myProviders.size();
+ return myProviders.get(prevIdx);
+ }
+
+ @Override
+ public AbstractTestProxy.AssertEqualsMultiDiffViewProvider getCurrent() {
+ return myProvider;
+ }
+
+ @Override
+ public AbstractTestProxy.AssertEqualsMultiDiffViewProvider getNext() {
+ final int nextIdx = (myProviders.indexOf(myProvider) + 1) % myProviders.size();
+ return myProviders.get(nextIdx);
+ }
+
+ @Override
+ public void setCurrent(AbstractTestProxy.AssertEqualsMultiDiffViewProvider provider) {
+ myProvider = provider;
+ }
}
}
diff --git a/platform/testRunner/src/com/intellij/execution/testframework/stacktrace/DiffHyperlink.java b/platform/testRunner/src/com/intellij/execution/testframework/stacktrace/DiffHyperlink.java
index b60770692d9b..f8ff62996eca 100644
--- a/platform/testRunner/src/com/intellij/execution/testframework/stacktrace/DiffHyperlink.java
+++ b/platform/testRunner/src/com/intellij/execution/testframework/stacktrace/DiffHyperlink.java
@@ -22,14 +22,20 @@ package com.intellij.execution.testframework.stacktrace;
import com.intellij.execution.ExecutionBundle;
import com.intellij.execution.filters.HyperlinkInfo;
+import com.intellij.execution.testframework.AbstractTestProxy;
import com.intellij.execution.testframework.Printable;
import com.intellij.execution.testframework.Printer;
import com.intellij.execution.ui.ConsoleViewContentType;
+import com.intellij.icons.AllIcons;
+import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.diff.*;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import javax.swing.*;
import java.io.File;
public class DiffHyperlink implements Printable {
@@ -56,21 +62,93 @@ public class DiffHyperlink implements Printable {
myPrintOneLine = printOneLine;
}
- public void openDiff(final Project project) {
+ public void openDiff(Project project) {
+ openMultiDiff(project, null);
+ }
+
+ public void openMultiDiff(final Project project,
+ final AbstractTestProxy.AssertEqualsDiffChain chain) {
+ final SimpleDiffRequest diffData = createRequest(project, chain, myFilePath, myExpected, myActual);
+ DiffManager.getInstance().getIdeaDiffTool().show(diffData);
+ }
+
+ private SimpleDiffRequest createRequest(final Project project,
+ final AbstractTestProxy.AssertEqualsDiffChain chain,
+ String filePath, String expected, String actual) {
String expectedTitle = ExecutionBundle.message("diff.content.expected.title");
final DiffContent expectedContent;
final VirtualFile vFile;
- if (myFilePath != null && (vFile = LocalFileSystem.getInstance().findFileByPath(myFilePath)) != null) {
+ if (filePath != null && (vFile = LocalFileSystem.getInstance().findFileByPath(filePath)) != null) {
expectedContent = DiffContent.fromFile(project, vFile);
expectedTitle += " (" + vFile.getPresentableUrl() + ")";
- } else expectedContent = new SimpleContent(myExpected);
+ } else {
+ expectedContent = new SimpleContent(expected);
+ }
final SimpleDiffRequest diffData = new SimpleDiffRequest(project, getTitle());
- diffData.setContents(expectedContent, new SimpleContent(myActual));
+ if (chain != null) {
+ diffData.setToolbarAddons(new DiffRequest.ToolbarAddons() {
+ @Override
+ public void customize(DiffToolbar toolbar) {
+ toolbar.addAction(new NextPrevAction("Compare Previous Failure", AllIcons.Actions.Prevfile, chain) {
+ {
+ registerCustomShortcutSet(ActionManager.getInstance().getAction("PreviousTab").getShortcutSet(), null);
+ }
+
+ @Override
+ protected AbstractTestProxy.AssertEqualsMultiDiffViewProvider getNextId() {
+ return chain.getPrevious();
+ }
+ });
+ toolbar.addAction(new NextPrevAction("Compare Next Failure", AllIcons.Actions.Nextfile, chain) {
+ {
+ registerCustomShortcutSet(ActionManager.getInstance().getAction("NextTab").getShortcutSet(), null);
+ }
+
+ @Override
+ protected AbstractTestProxy.AssertEqualsMultiDiffViewProvider getNextId() {
+ return chain.getNext();
+ }
+ });
+ }
+ });
+ }
+ diffData.setContents(expectedContent, new SimpleContent(actual));
diffData.setContentTitles(expectedTitle, ExecutionBundle.message("diff.content.actual.title"));
diffData.addHint(DiffTool.HINT_SHOW_FRAME);
diffData.addHint(DiffTool.HINT_DO_NOT_IGNORE_WHITESPACES);
diffData.setGroupKey("#com.intellij.execution.junit2.states.ComparisonFailureState$DiffDialog");
- DiffManager.getInstance().getIdeaDiffTool().show(diffData);
+ return diffData;
+ }
+
+ abstract class NextPrevAction extends AnAction {
+
+ private final AbstractTestProxy.AssertEqualsDiffChain myChain;
+
+ public NextPrevAction(@Nullable String text, @Nullable Icon icon,
+ final AbstractTestProxy.AssertEqualsDiffChain chain) {
+ super(text, text, icon);
+ myChain = chain;
+ }
+
+ @Override
+ public void actionPerformed(@NotNull AnActionEvent e) {
+ final DiffViewer viewer = e.getData(PlatformDataKeys.DIFF_VIEWER);
+ final Project project = e.getData(CommonDataKeys.PROJECT);
+ final AbstractTestProxy.AssertEqualsMultiDiffViewProvider nextProvider = getNextId();
+ myChain.setCurrent(nextProvider);
+ final SimpleDiffRequest nextRequest =
+ createRequest(project, myChain, nextProvider.getFilePath(), nextProvider.getExpected(), nextProvider.getActual());
+ viewer.setDiffRequest(nextRequest);
+ }
+
+ @Override
+ public void update(@NotNull AnActionEvent e) {
+ final DiffViewer viewer = e.getData(PlatformDataKeys.DIFF_VIEWER);
+ final Project project = e.getData(CommonDataKeys.PROJECT);
+ e.getPresentation().setEnabled(project != null && viewer != null);
+ }
+
+ protected abstract AbstractTestProxy.AssertEqualsMultiDiffViewProvider getNextId();
}
protected String getTitle() {
diff --git a/platform/testRunner/src/com/intellij/execution/testframework/ui/TestResultsPanel.java b/platform/testRunner/src/com/intellij/execution/testframework/ui/TestResultsPanel.java
index a7519429381d..1f4b93238f9c 100644
--- a/platform/testRunner/src/com/intellij/execution/testframework/ui/TestResultsPanel.java
+++ b/platform/testRunner/src/com/intellij/execution/testframework/ui/TestResultsPanel.java
@@ -75,6 +75,7 @@ public abstract class TestResultsPanel extends JPanel implements Disposable {
Disposer.register(this, myToolbarPanel);
final Splitter splitter = createSplitter(mySplitterProportionProperty, mySplitterDefaultProportion);
Disposer.register(this, new Disposable(){
+ @Override
public void dispose() {
remove(splitter);
splitter.dispose();
@@ -91,6 +92,7 @@ public abstract class TestResultsPanel extends JPanel implements Disposable {
rightPanel.add(SameHeightPanel.wrap(myStatusLine, myToolbarPanel), BorderLayout.NORTH);
myStatisticsSplitter = createSplitter(myStatisticsSplitterProportionProperty, 0.5f);
new AwtVisitor(myConsole) {
+ @Override
public boolean visit(Component component) {
if (component instanceof JScrollPane) {
((JScrollPane) component).putClientProperty(UIUtil.KEEP_BORDER_SIDES, SideBorder.TOP | SideBorder.LEFT);
@@ -104,6 +106,7 @@ public abstract class TestResultsPanel extends JPanel implements Disposable {
showStatistics();
}
myProperties.addListener(TestConsoleProperties.SHOW_STATISTICS, new TestFrameworkPropertyListener<Boolean>() {
+ @Override
public void onChanged(Boolean value) {
if (value.booleanValue()) {
showStatistics();
@@ -145,6 +148,7 @@ public abstract class TestResultsPanel extends JPanel implements Disposable {
return outputTab;
}
+ @Override
public void dispose() {
}
@@ -167,9 +171,9 @@ public abstract class TestResultsPanel extends JPanel implements Disposable {
}
splitter.addPropertyChangeListener(new PropertyChangeListener() {
- public void propertyChange(final PropertyChangeEvent evt) {
- if (propertiesComponent == null) return;
- if (evt.getPropertyName().equals(Splitter.PROP_PROPORTION)) {
+ @Override
+ public void propertyChange(@NotNull final PropertyChangeEvent event) {
+ if (event.getPropertyName().equals(Splitter.PROP_PROPORTION)) {
propertiesComponent.setValue(proportionProperty, String.valueOf(splitter.getProportion()));
}
}
diff --git a/platform/usageView/src/com/intellij/usages/ChunkExtractor.java b/platform/usageView/src/com/intellij/usages/ChunkExtractor.java
index dbbaeb48b72f..b9db68c69ce3 100644
--- a/platform/usageView/src/com/intellij/usages/ChunkExtractor.java
+++ b/platform/usageView/src/com/intellij/usages/ChunkExtractor.java
@@ -203,7 +203,7 @@ public class ChunkExtractor {
if (myDocumentStamp != myDocument.getModificationStamp()) {
highlighter.restart(chars);
myDocumentStamp = myDocument.getModificationStamp();
- } else if(lexer.getTokenStart() > start) {
+ } else if(lexer.getTokenType() == null || lexer.getTokenStart() > start) {
highlighter.resetPosition(0); // todo restart from nearest position with initial state
}
diff --git a/platform/usageView/src/com/intellij/usages/FindUsagesProcessPresentation.java b/platform/usageView/src/com/intellij/usages/FindUsagesProcessPresentation.java
index 2248182a3c5c..c303c7fd0496 100644
--- a/platform/usageView/src/com/intellij/usages/FindUsagesProcessPresentation.java
+++ b/platform/usageView/src/com/intellij/usages/FindUsagesProcessPresentation.java
@@ -43,6 +43,7 @@ public class FindUsagesProcessPresentation {
private Collection<PsiFile> myLargeFiles;
private boolean myShowFindOptionsPrompt = true;
private Runnable mySearchWithProjectFiles;
+ private boolean myCanceled;
public FindUsagesProcessPresentation(@NotNull UsageViewPresentation presentation) {
myUsageViewPresentation = presentation;
@@ -112,6 +113,15 @@ public class FindUsagesProcessPresentation {
public void setShowFindOptionsPrompt(boolean showFindOptionsPrompt) {
myShowFindOptionsPrompt = showFindOptionsPrompt;
}
+
+
+ public void setCanceled(boolean canceled) {
+ myCanceled = canceled;
+ }
+
+ public boolean isCanceled() {
+ return myCanceled;
+ }
}
diff --git a/platform/usageView/src/com/intellij/usages/impl/SearchForUsagesRunnable.java b/platform/usageView/src/com/intellij/usages/impl/SearchForUsagesRunnable.java
index 8771ef75502b..6e5e93f3ed96 100644
--- a/platform/usageView/src/com/intellij/usages/impl/SearchForUsagesRunnable.java
+++ b/platform/usageView/src/com/intellij/usages/impl/SearchForUsagesRunnable.java
@@ -122,7 +122,7 @@ class SearchForUsagesRunnable implements Runnable {
return "<a href='" + SEARCH_IN_PROJECT_HREF_TARGET + "'>Search in Project</a>";
}
- private static void notifyByFindBalloon(final HyperlinkListener listener,
+ private static void notifyByFindBalloon(@Nullable final HyperlinkListener listener,
@NotNull final MessageType info,
@NotNull FindUsagesProcessPresentation processPresentation,
@NotNull final Project project,
@@ -400,6 +400,12 @@ class SearchForUsagesRunnable implements Runnable {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
+ if (myProcessPresentation.isCanceled()) {
+ notifyByFindBalloon(null, MessageType.WARNING, myProcessPresentation, myProject, Arrays.asList("Usage search was canceled"));
+ findStartedBalloonShown.set(false);
+ return;
+ }
+
final List<Action> notFoundActions = myProcessPresentation.getNotFoundActions();
final String message = UsageViewBundle.message("dialog.no.usages.found.in",
StringUtil.decapitalize(myPresentation.getUsagesString()),
diff --git a/platform/util-rt/src/com/intellij/openapi/util/Condition.java b/platform/util-rt/src/com/intellij/openapi/util/Condition.java
index 7eb9c1c7a8f6..d75ec46aa8cc 100644
--- a/platform/util-rt/src/com/intellij/openapi/util/Condition.java
+++ b/platform/util-rt/src/com/intellij/openapi/util/Condition.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2010 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,6 +28,7 @@ public interface Condition<T> {
boolean value(T t);
Condition<Object> NOT_NULL = new Condition<Object>() {
+ @Override
public boolean value(final Object object) {
return object != null;
}
@@ -43,6 +44,7 @@ public interface Condition<T> {
* @see com.intellij.openapi.util.Conditions#alwaysTrue()
*/
Condition TRUE = new Condition() {
+ @Override
public boolean value(final Object object) {
return true;
}
@@ -57,6 +59,7 @@ public interface Condition<T> {
* @see com.intellij.openapi.util.Conditions#alwaysFalse()
*/
Condition FALSE = new Condition() {
+ @Override
public boolean value(final Object object) {
return false;
}
diff --git a/platform/util-rt/src/com/intellij/openapi/util/Conditions.java b/platform/util-rt/src/com/intellij/openapi/util/Conditions.java
index 48bb06ad8b8e..ef3c0d2acbf6 100644
--- a/platform/util-rt/src/com/intellij/openapi/util/Conditions.java
+++ b/platform/util-rt/src/com/intellij/openapi/util/Conditions.java
@@ -18,6 +18,7 @@ package com.intellij.openapi.util;
import com.intellij.reference.SoftReference;
import com.intellij.util.ArrayUtilRt;
+import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
@@ -27,15 +28,18 @@ import java.util.HashMap;
public class Conditions {
private Conditions() {}
+ @NotNull
public static <T> Condition<T> alwaysTrue() {
return (Condition<T>)TRUE;
}
+ @NotNull
public static <T> Condition<T> alwaysFalse() {
return (Condition<T>)FALSE;
}
public static <T> Condition<T> instanceOf(final Class<?> clazz) {
return new Condition<T>() {
+ @Override
public boolean value(T t) {
return clazz.isInstance(t);
}
@@ -44,6 +48,7 @@ public class Conditions {
public static <T> Condition<T> is(final T option) {
return new Condition<T>() {
+ @Override
public boolean value(T t) {
return Comparing.equal(t, option);
}
@@ -52,6 +57,7 @@ public class Conditions {
public static <T> Condition<T> oneOf(final T... options) {
return new Condition<T>() {
+ @Override
public boolean value(T t) {
return ArrayUtilRt.find(options, t) >= 0;
}
@@ -78,6 +84,7 @@ public class Conditions {
myCondition = condition;
}
+ @Override
public boolean value(T value) {
return !myCondition.value(value);
}
@@ -91,6 +98,7 @@ public class Conditions {
this.t2 = t2;
}
+ @Override
public boolean value(final T object) {
return t1.value(object) && t2.value(object);
}
@@ -104,17 +112,20 @@ public class Conditions {
this.t2 = t2;
}
+ @Override
public boolean value(final T object) {
return t1.value(object) || t2.value(object);
}
}
public static Condition<Object> TRUE = new Condition<Object>() {
+ @Override
public boolean value(final Object object) {
return true;
}
};
public static Condition<Object> FALSE = new Condition<Object>() {
+ @Override
public boolean value(final Object object) {
return false;
}
@@ -128,6 +139,7 @@ public class Conditions {
myCondition = condition;
}
+ @Override
public final boolean value(T object) {
final int key = object.hashCode();
final Pair<SoftReference<T>, Boolean> entry = myCache.get(key);
diff --git a/platform/util-rt/src/com/intellij/openapi/util/text/StringUtilRt.java b/platform/util-rt/src/com/intellij/openapi/util/text/StringUtilRt.java
index 8b6e353fdbea..cc667ba8a80d 100644
--- a/platform/util-rt/src/com/intellij/openapi/util/text/StringUtilRt.java
+++ b/platform/util-rt/src/com/intellij/openapi/util/text/StringUtilRt.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,6 +15,7 @@
*/
package com.intellij.openapi.util.text;
+import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -27,11 +28,13 @@ import org.jetbrains.annotations.Nullable;
*/
@SuppressWarnings({"UtilityClassWithoutPrivateConstructor"})
public class StringUtilRt {
+ @Contract(pure = true)
public static boolean charsEqualIgnoreCase(char a, char b) {
return a == b || toUpperCase(a) == toUpperCase(b) || toLowerCase(a) == toLowerCase(b);
}
@NotNull
+ @Contract(pure = true)
public static String toUpperCase(@NotNull String s) {
StringBuilder answer = null;
@@ -51,6 +54,7 @@ public class StringUtilRt {
return answer == null ? s : answer.toString();
}
+ @Contract(pure = true)
public static char toUpperCase(char a) {
if (a < 'a') {
return a;
@@ -61,6 +65,7 @@ public class StringUtilRt {
return Character.toUpperCase(a);
}
+ @Contract(pure = true)
public static char toLowerCase(char a) {
if (a < 'A' || a >= 'a' && a <= 'z') {
return a;
@@ -77,21 +82,25 @@ public class StringUtilRt {
* Converts line separators to <code>"\n"</code>
*/
@NotNull
+ @Contract(pure = true)
public static String convertLineSeparators(@NotNull String text) {
return convertLineSeparators(text, false);
}
@NotNull
+ @Contract(pure = true)
public static String convertLineSeparators(@NotNull String text, boolean keepCarriageReturn) {
return convertLineSeparators(text, "\n", null, keepCarriageReturn);
}
@NotNull
+ @Contract(pure = true)
public static String convertLineSeparators(@NotNull String text, @NotNull String newSeparator) {
return convertLineSeparators(text, newSeparator, null);
}
@NotNull
+ @Contract(pure = true)
public static CharSequence convertLineSeparators(@NotNull CharSequence text, @NotNull String newSeparator) {
return unifyLineSeparators(text, newSeparator, null, false);
}
@@ -110,6 +119,7 @@ public class StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static CharSequence unifyLineSeparators(@NotNull CharSequence text) {
return unifyLineSeparators(text, "\n", null, false);
}
@@ -189,6 +199,7 @@ public class StringUtilRt {
}
}
+ @Contract(pure = true)
public static int parseInt(final String string, final int defaultValue) {
try {
return Integer.parseInt(string);
@@ -198,6 +209,7 @@ public class StringUtilRt {
}
}
+ @Contract(pure = true)
public static double parseDouble(final String string, final double defaultValue) {
try {
return Double.parseDouble(string);
@@ -207,6 +219,7 @@ public class StringUtilRt {
}
}
+ @Contract(pure = true)
public static boolean parseBoolean(final String string, final boolean defaultValue) {
try {
return Boolean.parseBoolean(string);
@@ -217,16 +230,19 @@ public class StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static String getShortName(@NotNull Class aClass) {
return getShortName(aClass.getName());
}
@NotNull
+ @Contract(pure = true)
public static String getShortName(@NotNull String fqName) {
return getShortName(fqName, '.');
}
@NotNull
+ @Contract(pure = true)
public static String getShortName(@NotNull String fqName, char separator) {
int lastPointIdx = fqName.lastIndexOf(separator);
if (lastPointIdx >= 0) {
@@ -235,16 +251,19 @@ public class StringUtilRt {
return fqName;
}
+ @Contract(pure = true)
public static boolean endsWithChar(@Nullable CharSequence s, char suffix) {
return s != null && s.length() != 0 && s.charAt(s.length() - 1) == suffix;
}
+ @Contract(pure = true)
public static boolean startsWithIgnoreCase(@NonNls @NotNull String str, @NonNls @NotNull String prefix) {
final int stringLength = str.length();
final int prefixLength = prefix.length();
return stringLength >= prefixLength && str.regionMatches(true, 0, prefix, 0, prefixLength);
}
+ @Contract(pure = true)
public static boolean endsWithIgnoreCase(@NonNls @NotNull CharSequence text, @NonNls @NotNull CharSequence suffix) {
int l1 = text.length();
int l2 = suffix.length();
@@ -269,6 +288,7 @@ public class StringUtilRt {
* @return index of the last occurrence of the given symbol at the target sub-sequence of the given text if any;
* <code>-1</code> otherwise
*/
+ @Contract(pure = true)
public static int lastIndexOf(@NotNull CharSequence s, char c, int start, int end) {
for (int i = end - 1; i >= start; i--) {
if (s.charAt(i) == c) return i;
diff --git a/platform/util-rt/src/com/intellij/util/ArrayUtilRt.java b/platform/util-rt/src/com/intellij/util/ArrayUtilRt.java
index b18b62889623..115a6ceba1e5 100644
--- a/platform/util-rt/src/com/intellij/util/ArrayUtilRt.java
+++ b/platform/util-rt/src/com/intellij/util/ArrayUtilRt.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,8 +15,9 @@
*/
package com.intellij.util;
-import org.jetbrains.annotations.NotNull;
import com.intellij.util.containers.ContainerUtilRt;
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
@@ -44,6 +45,7 @@ public class ArrayUtilRt {
public static final Runnable[] EMPTY_RUNNABLE_ARRAY = new Runnable[0];
@NotNull
+ @Contract(pure=true)
public static String[] toStringArray(@Nullable Collection<String> collection) {
return collection == null || collection.isEmpty()
? EMPTY_STRING_ARRAY : ContainerUtilRt.toArray(collection, new String[collection.size()]);
@@ -57,6 +59,7 @@ public class ArrayUtilRt {
* <code>equals</code> of arrays elements to compare <code>obj</code> with
* these elements.
*/
+ @Contract(pure=true)
public static <T> int find(@NotNull final T[] src, final T obj) {
for (int i = 0; i < src.length; i++) {
final T o = src[i];
diff --git a/platform/util-rt/src/com/intellij/util/containers/ContainerUtilRt.java b/platform/util-rt/src/com/intellij/util/containers/ContainerUtilRt.java
index e4b3153917f7..a89de17fe6fe 100644
--- a/platform/util-rt/src/com/intellij/util/containers/ContainerUtilRt.java
+++ b/platform/util-rt/src/com/intellij/util/containers/ContainerUtilRt.java
@@ -18,6 +18,7 @@ package com.intellij.util.containers;
import com.intellij.openapi.util.Pair;
import com.intellij.util.ArrayUtilRt;
import com.intellij.util.Function;
+import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -40,16 +41,19 @@ public class ContainerUtilRt {
private static final int ARRAY_COPY_THRESHOLD = 20;
@NotNull
+ @Contract(pure=true)
public static <K, V> HashMap<K, V> newHashMap() {
return new com.intellij.util.containers.HashMap<K, V>();
}
@NotNull
+ @Contract(pure=true)
public static <K, V> HashMap<K, V> newHashMap(@NotNull Map<K, V> map) {
return new com.intellij.util.containers.HashMap<K, V>(map);
}
@NotNull
+ @Contract(pure=true)
public static <K, V> Map<K, V> newHashMap(@NotNull List<K> keys, @NotNull List<V> values) {
if (keys.size() != values.size()) {
throw new IllegalArgumentException(keys + " should have same length as " + values);
@@ -63,6 +67,7 @@ public class ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <K, V> Map<K,V> newHashMap(@NotNull Pair<K, V> first, Pair<K, V>[] entries) {
Map<K, V> map = newHashMap();
map.put(first.getFirst(), first.getSecond());
@@ -73,26 +78,43 @@ public class ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
+ public static <K, V> Map<K, V> newHashMap(int initialCapacity) {
+ return new com.intellij.util.containers.HashMap<K, V>(initialCapacity);
+ }
+
+ @NotNull
+ @Contract(pure=true)
public static <K extends Comparable, V> TreeMap<K, V> newTreeMap() {
return new TreeMap<K, V>();
}
@NotNull
+ @Contract(pure=true)
public static <K extends Comparable, V> TreeMap<K, V> newTreeMap(@NotNull Map<K, V> map) {
return new TreeMap<K, V>(map);
}
@NotNull
+ @Contract(pure=true)
public static <K, V> LinkedHashMap<K, V> newLinkedHashMap() {
return new com.intellij.util.containers.LinkedHashMap<K, V>();
}
@NotNull
+ @Contract(pure=true)
+ public static <K, V> LinkedHashMap<K, V> newLinkedHashMap(int capacity) {
+ return new com.intellij.util.containers.LinkedHashMap<K, V>(capacity);
+ }
+
+ @NotNull
+ @Contract(pure=true)
public static <K, V> LinkedHashMap<K, V> newLinkedHashMap(@NotNull Map<K, V> map) {
return new com.intellij.util.containers.LinkedHashMap<K, V>(map);
}
@NotNull
+ @Contract(pure=true)
public static <K, V> LinkedHashMap<K,V> newLinkedHashMap(@NotNull Pair<K, V> first, Pair<K, V>[] entries) {
LinkedHashMap<K, V> map = newLinkedHashMap();
map.put(first.getFirst(), first.getSecond());
@@ -103,11 +125,13 @@ public class ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> LinkedList<T> newLinkedList() {
return new LinkedList<T>();
}
@NotNull
+ @Contract(pure=true)
public static <T> LinkedList<T> newLinkedList(@NotNull T... elements) {
final LinkedList<T> list = newLinkedList();
Collections.addAll(list, elements);
@@ -115,16 +139,19 @@ public class ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> LinkedList<T> newLinkedList(@NotNull Iterable<? extends T> elements) {
return copy(ContainerUtilRt.<T>newLinkedList(), elements);
}
@NotNull
+ @Contract(pure=true)
public static <T> ArrayList<T> newArrayList() {
return new ArrayList<T>();
}
@NotNull
+ @Contract(pure=true)
public static <T> ArrayList<T> newArrayList(@NotNull T... elements) {
ArrayList<T> list = newArrayListWithCapacity(elements.length);
Collections.addAll(list, elements);
@@ -132,6 +159,7 @@ public class ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> ArrayList<T> newArrayList(@NotNull Iterable<? extends T> elements) {
if (elements instanceof Collection) {
@SuppressWarnings("unchecked") Collection<? extends T> collection = (Collection<? extends T>)elements;
@@ -141,11 +169,13 @@ public class ContainerUtilRt {
}
/** @deprecated Use {@link #newArrayListWithCapacity(int)} (to remove in IDEA 15) */
+ @Contract(pure=true)
public static <T> ArrayList<T> newArrayListWithExpectedSize(int size) {
return newArrayListWithCapacity(size);
}
@NotNull
+ @Contract(pure=true)
public static <T> ArrayList<T> newArrayListWithCapacity(int size) {
return new ArrayList<T>(size);
}
@@ -159,21 +189,25 @@ public class ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> HashSet<T> newHashSet() {
return new com.intellij.util.containers.HashSet<T>();
}
@NotNull
+ @Contract(pure=true)
public static <T> HashSet<T> newHashSet(int initialCapacity) {
return new com.intellij.util.containers.HashSet<T>(initialCapacity);
}
@NotNull
+ @Contract(pure=true)
public static <T> HashSet<T> newHashSet(@NotNull T... elements) {
return new com.intellij.util.containers.HashSet<T>(Arrays.asList(elements));
}
@NotNull
+ @Contract(pure=true)
public static <T> HashSet<T> newHashSet(@NotNull Iterable<? extends T> elements) {
if (elements instanceof Collection) {
@SuppressWarnings("unchecked") Collection<? extends T> collection = (Collection<? extends T>)elements;
@@ -183,6 +217,7 @@ public class ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> HashSet<T> newHashSet(@NotNull Iterator<? extends T> iterator) {
HashSet<T> set = newHashSet();
while (iterator.hasNext()) set.add(iterator.next());
@@ -190,16 +225,19 @@ public class ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> LinkedHashSet<T> newLinkedHashSet() {
return new com.intellij.util.containers.LinkedHashSet<T>();
}
@NotNull
+ @Contract(pure=true)
public static <T> LinkedHashSet<T> newLinkedHashSet(@NotNull T... elements) {
return newLinkedHashSet(Arrays.asList(elements));
}
@NotNull
+ @Contract(pure=true)
public static <T> LinkedHashSet<T> newLinkedHashSet(@NotNull Iterable<? extends T> elements) {
if (elements instanceof Collection) {
@SuppressWarnings("unchecked") Collection<? extends T> collection = (Collection<? extends T>)elements;
@@ -209,11 +247,13 @@ public class ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> TreeSet<T> newTreeSet() {
return new TreeSet<T>();
}
@NotNull
+ @Contract(pure=true)
public static <T> TreeSet<T> newTreeSet(@NotNull T... elements) {
TreeSet<T> set = newTreeSet();
Collections.addAll(set, elements);
@@ -221,26 +261,31 @@ public class ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> TreeSet<T> newTreeSet(@NotNull Iterable<? extends T> elements) {
return copy(ContainerUtilRt.<T>newTreeSet(), elements);
}
@NotNull
+ @Contract(pure=true)
public static <T> TreeSet<T> newTreeSet(@Nullable Comparator<? super T> comparator) {
return new TreeSet<T>(comparator);
}
@NotNull
+ @Contract(pure=true)
public static <T> Stack<T> newStack() {
return new Stack<T>();
}
@NotNull
+ @Contract(pure=true)
public static <T> Stack<T> newStack(@NotNull Collection<T> elements) {
return new Stack<T>(elements);
}
@NotNull
+ @Contract(pure=true)
public static <T> Stack<T> newStack(@NotNull T... initial) {
return new Stack<T>(Arrays.asList(initial));
}
@@ -292,12 +337,14 @@ public class ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> List<T> emptyList() {
//noinspection unchecked
return (List<T>)EmptyList.INSTANCE;
}
@NotNull
+ @Contract(pure=true)
public static <T> CopyOnWriteArrayList<T> createEmptyCOWList() {
// does not create garbage new Object[0]
return new CopyOnWriteArrayList<T>(ContainerUtilRt.<T>emptyList());
@@ -319,6 +366,7 @@ public class ContainerUtilRt {
* @return read-only list consisting of the elements from array converted by mapper
*/
@NotNull
+ @Contract(pure=true)
public static <T, V> List<V> map2List(@NotNull T[] array, @NotNull Function<T, V> mapper) {
return map2List(Arrays.asList(array), mapper);
}
@@ -327,6 +375,7 @@ public class ContainerUtilRt {
* @return read-only list consisting of the elements from collection converted by mapper
*/
@NotNull
+ @Contract(pure=true)
public static <T, V> List<V> map2List(@NotNull Collection<? extends T> collection, @NotNull Function<T, V> mapper) {
if (collection.isEmpty()) return emptyList();
List<V> list = new ArrayList<V>(collection.size());
@@ -340,6 +389,7 @@ public class ContainerUtilRt {
* @return read-only set consisting of the elements from collection converted by mapper
*/
@NotNull
+ @Contract(pure=true)
public static <T, V> Set<V> map2Set(@NotNull T[] collection, @NotNull Function<T, V> mapper) {
return map2Set(Arrays.asList(collection), mapper);
}
@@ -348,6 +398,7 @@ public class ContainerUtilRt {
* @return read-only set consisting of the elements from collection converted by mapper
*/
@NotNull
+ @Contract(pure=true)
public static <T, V> Set<V> map2Set(@NotNull Collection<? extends T> collection, @NotNull Function<T, V> mapper) {
if (collection.isEmpty()) return Collections.emptySet();
Set <V> set = new HashSet<V>(collection.size());
diff --git a/platform/util-rt/src/com/intellij/util/containers/HashMap.java b/platform/util-rt/src/com/intellij/util/containers/HashMap.java
index af41488814d0..fa8608f50bf8 100644
--- a/platform/util-rt/src/com/intellij/util/containers/HashMap.java
+++ b/platform/util-rt/src/com/intellij/util/containers/HashMap.java
@@ -21,12 +21,12 @@ import java.util.Map;
public class HashMap<K, V> extends java.util.HashMap<K, V> {
public HashMap() { }
- public HashMap(int i, float v) {
- super(i, v);
+ public HashMap(int initialCapacity, float loadFactor) {
+ super(initialCapacity, loadFactor);
}
- public HashMap(int i) {
- super(i);
+ public HashMap(int initialCapacity) {
+ super(initialCapacity);
}
public <K1 extends K, V1 extends V> HashMap(Map<K1, V1> map) {
diff --git a/platform/util-rt/src/com/intellij/util/containers/Stack.java b/platform/util-rt/src/com/intellij/util/containers/Stack.java
index 29337c9c99b1..f1a0e37b1967 100644
--- a/platform/util-rt/src/com/intellij/util/containers/Stack.java
+++ b/platform/util-rt/src/com/intellij/util/containers/Stack.java
@@ -15,6 +15,7 @@
*/
package com.intellij.util.containers;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
@@ -32,11 +33,11 @@ public class Stack<T> extends ArrayList<T> {
super(initialCapacity);
}
- public Stack(Collection<T> init) {
+ public Stack(@NotNull Collection<T> init) {
super(init);
}
- public Stack(T... items) {
+ public Stack(@NotNull T... items) {
for (T item : items) {
push(item);
}
diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties
index 11ace8a42cad..5b37906c82ec 100644
--- a/platform/util/resources/misc/registry.properties
+++ b/platform/util/resources/misc/registry.properties
@@ -45,6 +45,15 @@ ide.firstStartup=true
ide.debugMode=false
ide.debugger.inline=false
ide.debugger.inline.description=Enables variables view in editor
+ide.debugger.inline.fg.color=61,128,101
+ide.debugger.inline.fg.color.description=Inline values foreground
+ide.debugger.inline.dark.fg.color=61,128,101
+ide.debugger.inline.dark.fg.color.description=Inline values foreground for dark editor scheme
+ide.debugger.inline.fg.modified.color=202,128,33
+ide.debugger.inline.fg.modified.color.description=Inline modified values foreground
+ide.debugger.inline.dark.fg.modified.color=161,131,10
+ide.debugger.inline.dark.fg.modified.color.description=Inline modified values foreground for dark editor scheme
+
ide.debugMode.description=Record additional information to make bug reports more informative.
ide.debug.minProgressTime=0
ide.forcedShowTooltip=alt
@@ -122,7 +131,6 @@ editor.use.scrollable.tabs=true
editor.smarterSelectionQuoting=true
editor.skip.copy.and.cut.for.empty.selection=false
editor.distraction.free.mode=false
-editor.use.preview=false
editor.add.carets.on.double.control.arrows=true
ide.showIndexRebuildMessage=false
@@ -183,9 +191,6 @@ compiler.process.use.memory.temp.cache=true
compiler.process.use.memory.temp.cache.description=Store temporary data in memory for faster compilation;\
requires larger heap size for the build process. If parallel build is enabled, the option is ignored and temp data is always stored in memory.
-compiler.process.use.external.javac=false
-compiler.process.use.external.javac.description=Run javac compiler in a separate process (allows to run build process with smaller heap size).
-
compiler.process.debug.port=-1
compiler.automake.trigger.delay=300
@@ -233,6 +238,9 @@ ide.completion.autopopup.choose.by.enter=true
java.completion.make.outer.variables.final=true
java.completion.make.outer.variables.final.description=Make variables accessed from inner class final automatically
+java.annotations.inference.nullable.method.transitivity=true
+java.annotations.inference.nullable.method.transitivity.description=Restart is required; if a method result is a call to a @Nullable method, reports the caller as @Nullable as well
+
documentation.component.editor.font=false
ide.completion.show.better.matching.classes=true
@@ -414,3 +422,5 @@ ide.new.markup.markers.description=New error stripe markers
spy.js.realtime.evaluation=false
spy.js.realtime.evaluation.description=Enables spy-js autocomplete and realtime evaluation
+
+new.css.schema.enabled=false
diff --git a/platform/util/src/com/intellij/execution/configurations/CommandLineTokenizer.java b/platform/util/src/com/intellij/execution/configurations/CommandLineTokenizer.java
index a62af9aa62dc..3f351b9a573e 100644
--- a/platform/util/src/com/intellij/execution/configurations/CommandLineTokenizer.java
+++ b/platform/util/src/com/intellij/execution/configurations/CommandLineTokenizer.java
@@ -20,9 +20,9 @@ import java.util.List;
import java.util.StringTokenizer;
/**
- * Splits input String to tokens being aware of quoted tokens ("foo bar") and escaped spaces (foo\ bar),
+ * Splits input String to tokens being aware of quoted tokens ("foo bar") and escaped spaces & quotes (\"foo\ bar\"),
* usually used for splitting command line to separate arguments that may contain space symbols.
- * Escaped symbols are not handled so there's no way to get token that itself contains quotation mark.
+ * Space and quote are the only symbols that can be escaped
*/
public class CommandLineTokenizer extends StringTokenizer {
@@ -103,8 +103,10 @@ public class CommandLineTokenizer extends StringTokenizer {
do {
while ((i = nextToken.indexOf('"')) >= 0) {
- quotationMarks++;
- buffer.append(nextToken.substring(0, i));
+ boolean isEscapedQuote = i > 0 && nextToken.charAt(i - 1) == '\\';
+ if (!isEscapedQuote) quotationMarks++;
+ buffer.append(nextToken.substring(0, isEscapedQuote ? i - 1 : i));
+ if (isEscapedQuote) buffer.append('"');
nextToken = nextToken.substring(i + 1);
}
diff --git a/platform/util/src/com/intellij/icons/AllIcons.java b/platform/util/src/com/intellij/icons/AllIcons.java
index a80ffccdd58e..f31f9b94b058 100644
--- a/platform/util/src/com/intellij/icons/AllIcons.java
+++ b/platform/util/src/com/intellij/icons/AllIcons.java
@@ -204,6 +204,7 @@ public class AllIcons {
public static final Icon AutoVariablesMode = IconLoader.getIcon("/debugger/autoVariablesMode.png"); // 16x16
public static final Icon BreakpointAlert = IconLoader.getIcon("/debugger/breakpointAlert.png"); // 16x16
public static final Icon Class_filter = IconLoader.getIcon("/debugger/class_filter.png"); // 16x16
+ public static final Icon CommandLine = IconLoader.getIcon("/debugger/commandLine.png"); // 16x16
public static final Icon Console = IconLoader.getIcon("/debugger/console.png"); // 16x16
public static final Icon Db_array = IconLoader.getIcon("/debugger/db_array.png"); // 16x16
public static final Icon Db_db_object = IconLoader.getIcon("/debugger/db_db_object.png"); // 16x16
diff --git a/platform/util/src/com/intellij/openapi/application/PathManager.java b/platform/util/src/com/intellij/openapi/application/PathManager.java
index 9956959f0e22..0188203cde33 100644
--- a/platform/util/src/com/intellij/openapi/application/PathManager.java
+++ b/platform/util/src/com/intellij/openapi/application/PathManager.java
@@ -45,7 +45,6 @@ public class PathManager {
@NonNls public static final String PROPERTY_HOME_PATH = "idea.home.path";
@NonNls public static final String PROPERTY_LOG_PATH = "idea.log.path";
@NonNls public static final String PROPERTY_PATHS_SELECTOR = "idea.paths.selector";
- @NonNls public static final String PROPERTY_ORIGINAL_WORKING_DIR = "original.working.dir";
@NonNls public static final String DEFAULT_OPTIONS_FILE_NAME = "other";
@NonNls private static final String LIB_FOLDER = "lib";
@@ -253,11 +252,6 @@ public class PathManager {
// misc stuff
- @Nullable
- public static String getOriginalWorkingDir() {
- return System.getProperty(PROPERTY_ORIGINAL_WORKING_DIR);
- }
-
/**
* Attempts to detect classpath entry which contains given resource.
*/
@@ -418,7 +412,7 @@ public class PathManager {
private static String getAbsolutePath(String path) {
path = FileUtil.expandUserHome(path);
- return FileUtil.toCanonicalPath(new File(FileUtil.toCanonicalPath(path)).getAbsolutePath());
+ return FileUtil.toCanonicalPath(new File(path).getAbsolutePath());
}
private static String trimPathQuotes(String path){
diff --git a/platform/util/src/com/intellij/openapi/util/JDOMExternalizer.java b/platform/util/src/com/intellij/openapi/util/JDOMExternalizer.java
index 909c44db199b..cd5e8630a087 100644
--- a/platform/util/src/com/intellij/openapi/util/JDOMExternalizer.java
+++ b/platform/util/src/com/intellij/openapi/util/JDOMExternalizer.java
@@ -22,7 +22,10 @@ import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import java.util.*;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
public class JDOMExternalizer {
private JDOMExternalizer() {
@@ -66,7 +69,7 @@ public class JDOMExternalizer {
return null;
}
- public static void writeMap(Element root, Map<String, String>map, @NonNls @Nullable String rootName, @NonNls String entryName) {
+ public static void writeMap(Element root, Map<String, String> map, @NonNls @Nullable String rootName, @NonNls String entryName) {
Element mapRoot;
if (StringUtil.isNotEmpty(rootName)) {
mapRoot = new Element(rootName);
@@ -106,6 +109,26 @@ public class JDOMExternalizer {
}
}
+ /**
+ * Saves a pack of strings to some attribte. I.e: [tag attr="value"]
+ * @param parent parent element (where to add newly created tags)
+ * @param nodeName node name (tag, in our example)
+ * @param attrName attribute name (attr, in our example)
+ * @param values a pack of values to add
+ * @see #loadStringsList(org.jdom.Element, String, String)
+ */
+ public static void saveStringsList(@NotNull final Element parent,
+ @NotNull final String nodeName,
+ @NotNull final String attrName,
+ @NotNull final String... values) {
+ for (final String value : values) {
+ final Element node = new Element(nodeName);
+ node.setAttribute(attrName, value);
+ parent.addContent(node);
+ }
+ }
+
+ @NotNull
public static List<String> loadStringsList(Element element, String rootName, String attrName) {
final List<String> paths = new LinkedList<String>();
if (element != null) {
diff --git a/platform/util/src/com/intellij/openapi/util/JDOMUtil.java b/platform/util/src/com/intellij/openapi/util/JDOMUtil.java
index c82ee6df346b..dfee1dbed2df 100644
--- a/platform/util/src/com/intellij/openapi/util/JDOMUtil.java
+++ b/platform/util/src/com/intellij/openapi/util/JDOMUtil.java
@@ -398,9 +398,13 @@ public class JDOMUtil {
}
public static void writeDocument(@NotNull Document document, @NotNull File file, String lineSeparator) throws IOException {
+ writeParent(document, file, lineSeparator);
+ }
+
+ public static void writeParent(@NotNull Parent element, @NotNull File file, String lineSeparator) throws IOException {
OutputStream stream = new BufferedOutputStream(new FileOutputStream(file));
try {
- writeDocument(document, stream, lineSeparator);
+ writeParent(element, stream, lineSeparator);
}
finally {
stream.close();
@@ -408,9 +412,23 @@ public class JDOMUtil {
}
public static void writeDocument(@NotNull Document document, @NotNull OutputStream stream, String lineSeparator) throws IOException {
- writeDocument(document, new OutputStreamWriter(stream, CharsetToolkit.UTF8_CHARSET), lineSeparator);
+ writeParent(document, stream, lineSeparator);
}
+ public static void writeParent(@NotNull Parent element, @NotNull OutputStream stream, @NotNull String lineSeparator) throws IOException {
+ OutputStreamWriter writer = new OutputStreamWriter(stream, CharsetToolkit.UTF8_CHARSET);
+ try {
+ if (element instanceof Document) {
+ writeDocument((Document)element, writer, lineSeparator);
+ }
+ else {
+ writeElement((Element) element, writer, lineSeparator);
+ }
+ }
+ finally {
+ writer.close();
+ }
+ }
@NotNull
public static byte[] printDocument(@NotNull Document document, String lineSeparator) throws IOException {
diff --git a/platform/util/src/com/intellij/openapi/util/io/FileUtil.java b/platform/util/src/com/intellij/openapi/util/io/FileUtil.java
index 7d3d6f557249..bc41f70e933a 100644
--- a/platform/util/src/com/intellij/openapi/util/io/FileUtil.java
+++ b/platform/util/src/com/intellij/openapi/util/io/FileUtil.java
@@ -1249,18 +1249,15 @@ public class FileUtil extends FileUtilRt {
}
public static boolean isWindowsAbsolutePath(@NotNull String pathString) {
- if (pathString.length() >= 2 && Character.isLetter(pathString.charAt(0)) && pathString.charAt(1) == ':') {
- return true;
- }
- return false;
+ return pathString.length() >= 2 && Character.isLetter(pathString.charAt(0)) && pathString.charAt(1) == ':';
}
- @Contract("null -> null")
+ @Contract("null -> null; !null -> !null")
public static String getLocationRelativeToUserHome(@Nullable String path) {
return getLocationRelativeToUserHome(path, true);
}
- @Contract("null,_ -> null")
+ @Contract("null,_ -> null; !null,_ -> !null")
public static String getLocationRelativeToUserHome(@Nullable String path, boolean unixOnly) {
if (path == null) return null;
diff --git a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java
index af2b3dd4293e..c2b7de8ba7ed 100644
--- a/platform/util/src/com/intellij/openapi/util/text/StringUtil.java
+++ b/platform/util/src/com/intellij/openapi/util/text/StringUtil.java
@@ -64,6 +64,7 @@ public class StringUtil extends StringUtilRt {
};
@NotNull
+ @Contract(pure = true)
public static List<String> getWordsInStringLongestFirst(@NotNull String find) {
List<String> words = getWordsIn(find);
// hope long words are rare
@@ -77,11 +78,13 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static String escapePattern(@NotNull final String text) {
return replace(replace(text, "'", "''"), "{", "'{'");
}
@NotNull
+ @Contract(pure = true)
public static <T> Function<T, String> createToStringFunction(@NotNull Class<T> cls) {
return new Function<T, String>() {
@Override
@@ -101,11 +104,13 @@ public class StringUtil extends StringUtilRt {
};
@NotNull
+ @Contract(pure = true)
public static String replace(@NonNls @NotNull String text, @NonNls @NotNull String oldS, @NonNls @NotNull String newS) {
return replace(text, oldS, newS, false);
}
@NotNull
+ @Contract(pure = true)
public static String replaceIgnoreCase(@NonNls @NotNull String text, @NonNls @NotNull String oldS, @NonNls @NotNull String newS) {
return replace(text, oldS, newS, true);
}
@@ -120,6 +125,7 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static String replaceChar(@NotNull String buffer, char oldChar, char newChar) {
StringBuilder newBuffer = null;
for (int i = 0; i < buffer.length(); i++) {
@@ -139,6 +145,7 @@ public class StringUtil extends StringUtilRt {
return newBuffer == null ? buffer : newBuffer.toString();
}
+ @Contract(pure = true)
public static String replace(@NonNls @NotNull final String text, @NonNls @NotNull final String oldS, @NonNls @NotNull final String newS, final boolean ignoreCase) {
if (text.length() < oldS.length()) return text;
@@ -146,17 +153,26 @@ public class StringUtil extends StringUtilRt {
int i = 0;
while (i < text.length()) {
- final int i1 = ignoreCase? indexOfIgnoreCase(text, oldS, i) : text.indexOf(oldS, i);
- if (i1 < 0) {
- if (i == 0) return text;
+ final int index = ignoreCase? indexOfIgnoreCase(text, oldS, i) : text.indexOf(oldS, i);
+ if (index < 0) {
+ if (i == 0) {
+ return text;
+ }
+
newText.append(text, i, text.length());
break;
}
else {
- if (newText == null) newText = new StringBuilder(text.length() - i);
- newText.append(text, i, i1);
+ if (newText == null) {
+ if (text.length() == oldS.length()) {
+ return newS;
+ }
+ newText = new StringBuilder(text.length() - i);
+ }
+
+ newText.append(text, i, index);
newText.append(newS);
- i = i1 + oldS.length();
+ i = index + oldS.length();
}
}
return newText != null ? newText.toString() : "";
@@ -165,6 +181,7 @@ public class StringUtil extends StringUtilRt {
/**
* Implementation copied from {@link String#indexOf(String, int)} except character comparisons made case insensitive
*/
+ @Contract(pure = true)
public static int indexOfIgnoreCase(@NotNull String where, @NotNull String what, int fromIndex) {
int targetCount = what.length();
int sourceCount = where.length();
@@ -206,6 +223,7 @@ public class StringUtil extends StringUtilRt {
return -1;
}
+ @Contract(pure = true)
public static int indexOfIgnoreCase(@NotNull String where, char what, int fromIndex) {
int sourceCount = where.length();
@@ -226,18 +244,22 @@ public class StringUtil extends StringUtilRt {
return -1;
}
+ @Contract(pure = true)
public static boolean containsIgnoreCase(@NotNull String where, @NotNull String what) {
return indexOfIgnoreCase(where, what, 0) >= 0;
}
+ @Contract(pure = true)
public static boolean endsWithIgnoreCase(@NonNls @NotNull String str, @NonNls @NotNull String suffix) {
return StringUtilRt.endsWithIgnoreCase(str, suffix);
}
+ @Contract(pure = true)
public static boolean startsWithIgnoreCase(@NonNls @NotNull String str, @NonNls @NotNull String prefix) {
return StringUtilRt.startsWithIgnoreCase(str, prefix);
}
+ @Contract(pure = true)
public static String stripHtml(@NotNull String html, boolean convertBreaks) {
if (convertBreaks) {
html = html.replaceAll("<br/?>", "\n\n");
@@ -246,18 +268,20 @@ public class StringUtil extends StringUtilRt {
return html.replaceAll("<(.|\n)*?>", "");
}
- @Contract("null -> null; !null -> !null")
+ @Contract(value = "null -> null; !null -> !null", pure = true)
public static String toLowerCase(@Nullable final String str) {
//noinspection ConstantConditions
return str == null ? null : str.toLowerCase();
}
@NotNull
+ @Contract(pure = true)
public static String getPackageName(@NotNull String fqName) {
return getPackageName(fqName, '.');
}
@NotNull
+ @Contract(pure = true)
public static String getPackageName(@NotNull String fqName, char separator) {
int lastPointIdx = fqName.lastIndexOf(separator);
if (lastPointIdx >= 0) {
@@ -266,6 +290,7 @@ public class StringUtil extends StringUtilRt {
return "";
}
+ @Contract(pure = true)
public static int getLineBreakCount(@NotNull CharSequence text) {
int count = 0;
for (int i = 0; i < text.length(); i++) {
@@ -287,6 +312,7 @@ public class StringUtil extends StringUtilRt {
return count;
}
+ @Contract(pure = true)
public static boolean containsLineBreak(@NotNull CharSequence text) {
for (int i = 0; i < text.length(); i++) {
char c = text.charAt(i);
@@ -295,11 +321,13 @@ public class StringUtil extends StringUtilRt {
return false;
}
+ @Contract(pure = true)
public static boolean isLineBreak(char c) {
return c == '\n' || c == '\r';
}
@NotNull
+ @Contract(pure = true)
public static String escapeLineBreak(@NotNull String text) {
StringBuilder buffer = new StringBuilder(text.length());
for (int i = 0; i < text.length(); i++) {
@@ -318,11 +346,13 @@ public class StringUtil extends StringUtilRt {
return buffer.toString();
}
+ @Contract(pure = true)
public static boolean endsWithLineBreak(@NotNull CharSequence text) {
int len = text.length();
return len > 0 && isLineBreak(text.charAt(len - 1));
}
+ @Contract(pure = true)
public static int lineColToOffset(@NotNull CharSequence text, int line, int col) {
int curLine = 0;
int offset = 0;
@@ -343,6 +373,7 @@ public class StringUtil extends StringUtilRt {
return offset + col;
}
+ @Contract(pure = true)
public static int offsetToLineNumber(@NotNull CharSequence text, int offset) {
int curLine = 0;
int curOffset = 0;
@@ -366,6 +397,7 @@ public class StringUtil extends StringUtilRt {
/**
* Classic dynamic programming algorithm for string differences.
*/
+ @Contract(pure = true)
public static int difference(@NotNull String s1, @NotNull String s2) {
int[][] a = new int[s1.length()][s2.length()];
@@ -388,11 +420,13 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static String wordsToBeginFromUpperCase(@NotNull String s) {
return toTitleCase(s, ourPrepositions);
}
@NotNull
+ @Contract(pure = true)
public static String toTitleCase(@NotNull String s) {
return toTitleCase(s, ArrayUtil.EMPTY_STRING_ARRAY);
}
@@ -435,10 +469,12 @@ public class StringUtil extends StringUtilRt {
"per", "nor", "the", "to", "up", "upon", "via", "with"
};
+ @Contract(pure = true)
public static boolean isPreposition(@NotNull String s, int firstChar, int lastChar) {
return isPreposition(s, firstChar, lastChar, ourPrepositions);
}
+ @Contract(pure = true)
public static boolean isPreposition(@NotNull String s, int firstChar, int lastChar, @NotNull String[] prepositions) {
for (String preposition : prepositions) {
boolean found = false;
@@ -458,6 +494,7 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static NotNullFunction<String, String> escaper(final boolean escapeSlash, @Nullable final String additionalChars) {
return new NotNullFunction<String, String>() {
@NotNull
@@ -538,6 +575,7 @@ public class StringUtil extends StringUtilRt {
return buffer;
}
+ @Contract(pure = true)
private static boolean isPrintableUnicode(char c) {
int t = Character.getType(c);
return t != Character.UNASSIGNED && t != Character.LINE_SEPARATOR && t != Character.PARAGRAPH_SEPARATOR &&
@@ -545,6 +583,7 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static String escapeStringCharacters(@NotNull String s) {
StringBuilder buffer = new StringBuilder(s.length());
escapeStringCharacters(s.length(), s, "\"", buffer);
@@ -552,6 +591,7 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static String escapeCharCharacters(@NotNull String s) {
StringBuilder buffer = new StringBuilder(s.length());
escapeStringCharacters(s.length(), s, "\'", buffer);
@@ -559,6 +599,7 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static String unescapeStringCharacters(@NotNull String s) {
StringBuilder buffer = new StringBuilder(s.length());
unescapeStringCharacters(s.length(), s, buffer);
@@ -566,6 +607,7 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static String unquoteString(@NotNull String s) {
char c;
if (s.length() <= 1 || (c = s.charAt(0)) != '"' && c != '\'' || s.charAt(s.length() - 1) != c) {
@@ -575,6 +617,7 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static String unquoteString(@NotNull String s, char quotationChar) {
char c;
if (s.length() <= 1 || (c = s.charAt(0)) != quotationChar || s.charAt(s.length() - 1) != c) {
@@ -587,6 +630,7 @@ public class StringUtil extends StringUtilRt {
* This is just an optimized version of Matcher.quoteReplacement
*/
@NotNull
+ @Contract(pure = true)
public static String quoteReplacement(@NotNull String s) {
boolean needReplacements = false;
@@ -693,6 +737,7 @@ public class StringUtil extends StringUtilRt {
@SuppressWarnings({"HardCodedStringLiteral"})
@NotNull
+ @Contract(pure = true)
public static String pluralize(@NotNull String suggestion) {
if (suggestion.endsWith("Child") || suggestion.endsWith("child")) {
return suggestion + "ren";
@@ -718,12 +763,14 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static String capitalizeWords(@NotNull String text,
boolean allWords) {
return capitalizeWords(text, " \t\n\r\f", allWords, false);
}
@NotNull
+ @Contract(pure = true)
public static String capitalizeWords(@NotNull String text,
@NotNull String tokenizerDelim,
boolean allWords,
@@ -744,15 +791,18 @@ public class StringUtil extends StringUtilRt {
return out.toString();
}
+ @Contract(pure = true)
public static String decapitalize(String s) {
return Introspector.decapitalize(s);
}
+ @Contract(pure = true)
public static boolean isVowel(char c) {
return VOWELS.indexOf(c) >= 0;
}
@NotNull
+ @Contract(pure = true)
public static String capitalize(@NotNull String s) {
if (s.isEmpty()) return s;
if (s.length() == 1) return StringUtilRt.toUpperCase(s);
@@ -762,12 +812,13 @@ public class StringUtil extends StringUtilRt {
return toUpperCase(s.charAt(0)) + s.substring(1);
}
- @Contract("null -> false")
+ @Contract(value = "null -> false", pure = true)
public static boolean isCapitalized(@Nullable String s) {
return s != null && !s.isEmpty() && Character.isUpperCase(s.charAt(0));
}
@NotNull
+ @Contract(pure = true)
public static String capitalizeWithJavaBeanConvention(@NotNull String s) {
if (s.length() > 1 && Character.isUpperCase(s.charAt(1))) {
return s;
@@ -775,6 +826,7 @@ public class StringUtil extends StringUtilRt {
return capitalize(s);
}
+ @Contract(pure = true)
public static int stringHashCode(@NotNull CharSequence chars) {
if (chars instanceof String) return chars.hashCode();
if (chars instanceof CharSequenceWithStringHash) return chars.hashCode();
@@ -783,6 +835,7 @@ public class StringUtil extends StringUtilRt {
return stringHashCode(chars, 0, chars.length());
}
+ @Contract(pure = true)
public static int stringHashCode(@NotNull CharSequence chars, int from, int to) {
int h = 0;
for (int off = from; off < to; off++) {
@@ -791,6 +844,7 @@ public class StringUtil extends StringUtilRt {
return h;
}
+ @Contract(pure = true)
public static int stringHashCode(char[] chars, int from, int to) {
int h = 0;
for (int off = from; off < to; off++) {
@@ -799,6 +853,7 @@ public class StringUtil extends StringUtilRt {
return h;
}
+ @Contract(pure = true)
public static int stringHashCodeInsensitive(@NotNull char[] chars, int from, int to) {
int h = 0;
for (int off = from; off < to; off++) {
@@ -807,6 +862,7 @@ public class StringUtil extends StringUtilRt {
return h;
}
+ @Contract(pure = true)
public static int stringHashCodeInsensitive(@NotNull CharSequence chars, int from, int to) {
int h = 0;
for (int off = from; off < to; off++) {
@@ -815,6 +871,7 @@ public class StringUtil extends StringUtilRt {
return h;
}
+ @Contract(pure = true)
public static int stringHashCodeInsensitive(@NotNull CharSequence chars) {
return stringHashCodeInsensitive(chars, 0, chars.length());
}
@@ -822,6 +879,7 @@ public class StringUtil extends StringUtilRt {
/**
* Equivalent to string.startsWith(prefixes[0] + prefixes[1] + ...) but avoids creating an object for concatenation.
*/
+ @Contract(pure = true)
public static boolean startsWithConcatenation(@NotNull String string, @NotNull String... prefixes) {
int offset = 0;
for (String prefix : prefixes) {
@@ -838,6 +896,7 @@ public class StringUtil extends StringUtilRt {
* @deprecated use {@link #startsWithConcatenation(String, String...)} (to remove in IDEA 14).
*/
@SuppressWarnings("UnusedDeclaration")
+ @Contract(pure = true)
public static boolean startsWithConcatenationOf(@NotNull String string, @NotNull String firstPrefix, @NotNull String secondPrefix) {
return startsWithConcatenation(string, firstPrefix, secondPrefix);
}
@@ -846,6 +905,7 @@ public class StringUtil extends StringUtilRt {
* @deprecated use {@link #startsWithConcatenation(String, String...)} (to remove in IDEA 14).
*/
@SuppressWarnings("UnusedDeclaration")
+ @Contract(pure = true)
public static boolean startsWithConcatenationOf(@NotNull String string,
@NotNull String firstPrefix,
@NotNull String secondPrefix,
@@ -853,12 +913,13 @@ public class StringUtil extends StringUtilRt {
return startsWithConcatenation(string, firstPrefix, secondPrefix, thirdPrefix);
}
- @Contract("null -> null; !null -> !null")
+ @Contract(value = "null -> null; !null -> !null", pure = true)
public static String trim(@Nullable String s) {
return s == null ? null : s.trim();
}
@NotNull
+ @Contract(pure = true)
public static String trimEnd(@NotNull String s, @NonNls @NotNull String suffix) {
if (s.endsWith(suffix)) {
return s.substring(0, s.length() - suffix.length());
@@ -867,6 +928,7 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static String trimLog(@NotNull final String text, final int limit) {
if (limit > 5 && text.length() > limit) {
return text.substring(0, limit - 5) + " ...\n";
@@ -875,6 +937,7 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static String trimLeading(@NotNull String string) {
int index = 0;
while (index < string.length() && Character.isWhitespace(string.charAt(index))) index++;
@@ -882,6 +945,7 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static String trimLeading(@NotNull String string, char symbol) {
int index = 0;
while (index < string.length() && string.charAt(index) == symbol) index++;
@@ -889,21 +953,25 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static String trimTrailing(@NotNull String string) {
int index = string.length() - 1;
while (index >= 0 && Character.isWhitespace(string.charAt(index))) index--;
return string.substring(0, index + 1);
}
+ @Contract(pure = true)
public static boolean startsWithChar(@Nullable CharSequence s, char prefix) {
return s != null && s.length() != 0 && s.charAt(0) == prefix;
}
+ @Contract(pure = true)
public static boolean endsWithChar(@Nullable CharSequence s, char suffix) {
return StringUtilRt.endsWithChar(s, suffix);
}
@NotNull
+ @Contract(pure = true)
public static String trimStart(@NotNull String s, @NonNls @NotNull String prefix) {
if (s.startsWith(prefix)) {
return s.substring(prefix.length());
@@ -912,6 +980,7 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static String pluralize(@NotNull String base, int n) {
if (n == 1) return base;
return pluralize(base);
@@ -929,45 +998,51 @@ public class StringUtil extends StringUtilRt {
}
}
+ @Contract(pure = true)
public static String defaultIfEmpty(@Nullable String value, String defaultValue) {
return isEmpty(value) ? defaultValue : value;
}
- @Contract("null -> false")
+ @Contract(value = "null -> false", pure = true)
public static boolean isNotEmpty(@Nullable String s) {
return s != null && !s.isEmpty();
}
- @Contract("null -> true")
+ @Contract(value = "null -> true", pure=true)
public static boolean isEmpty(@Nullable String s) {
return s == null || s.isEmpty();
}
- @Contract("null -> true")
+ @Contract(value = "null -> true",pure = true)
public static boolean isEmpty(@Nullable CharSequence cs) {
return cs == null || cs.length() == 0;
}
+ @Contract(pure = true)
public static int length(@Nullable CharSequence cs) {
return cs == null ? 0 : cs.length();
}
@NotNull
+ @Contract(pure = true)
public static String notNullize(@Nullable final String s) {
return notNullize(s, "");
}
@NotNull
+ @Contract(pure = true)
public static String notNullize(@Nullable final String s, @NotNull String defaultValue) {
return s == null ? defaultValue : s;
}
@Nullable
+ @Contract(pure = true)
public static String nullize(@Nullable final String s) {
return nullize(s, false);
}
@Nullable
+ @Contract(pure = true)
public static String nullize(@Nullable final String s, boolean nullizeSpaces) {
if (nullizeSpaces) {
if (isEmptyOrSpaces(s)) return null;
@@ -978,13 +1053,13 @@ public class StringUtil extends StringUtilRt {
return s;
}
- @Contract("null -> true")
+ @Contract(value = "null -> true",pure = true)
// we need to keep this method to preserve backward compatibility
public static boolean isEmptyOrSpaces(@Nullable String s) {
return isEmptyOrSpaces(((CharSequence)s));
}
- @Contract("null -> true")
+ @Contract(value = "null -> true", pure = true)
public static boolean isEmptyOrSpaces(@Nullable CharSequence s) {
if (isEmpty(s)) {
return true;
@@ -1003,26 +1078,31 @@ public class StringUtil extends StringUtilRt {
* @param c symbol to check
* @return <code>true</code> if given symbol is white space, tabulation or line feed; <code>false</code> otherwise
*/
+ @Contract(pure = true)
public static boolean isWhiteSpace(char c) {
return c == '\n' || c == '\t' || c == ' ';
}
@NotNull
+ @Contract(pure = true)
public static String getThrowableText(@NotNull Throwable aThrowable) {
return ExceptionUtil.getThrowableText(aThrowable);
}
@NotNull
+ @Contract(pure = true)
public static String getThrowableText(@NotNull Throwable aThrowable, @NonNls @NotNull final String stackFrameSkipPattern) {
return ExceptionUtil.getThrowableText(aThrowable, stackFrameSkipPattern);
}
@Nullable
+ @Contract(pure = true)
public static String getMessage(@NotNull Throwable e) {
return ExceptionUtil.getMessage(e);
}
@NotNull
+ @Contract(pure = true)
public static String repeatSymbol(final char aChar, final int count) {
char[] buffer = new char[count];
Arrays.fill(buffer, aChar);
@@ -1030,6 +1110,7 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static String repeat(@NotNull String s, int count) {
assert count >= 0 : count;
StringBuilder sb = new StringBuilder(s.length() * count);
@@ -1040,6 +1121,7 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static List<String> splitHonorQuotes(@NotNull String s, char separator) {
final List<String> result = new ArrayList<String>();
final StringBuilder builder = new StringBuilder(s.length());
@@ -1068,17 +1150,20 @@ public class StringUtil extends StringUtilRt {
@NotNull
+ @Contract(pure = true)
public static List<String> split(@NotNull String s, @NotNull String separator) {
return split(s, separator, true);
}
@NotNull
+ @Contract(pure = true)
public static List<String> split(@NotNull String s, @NotNull String separator,
boolean excludeSeparator) {
return split(s, separator, excludeSeparator, true);
}
@NotNull
+ @Contract(pure = true)
public static List<String> split(@NotNull String s, @NotNull String separator,
boolean excludeSeparator, boolean excludeEmptyStrings) {
if (separator.isEmpty()) {
@@ -1103,6 +1188,7 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static Iterable<String> tokenize(@NotNull String s, @NotNull String separators) {
final com.intellij.util.text.StringTokenizer tokenizer = new com.intellij.util.text.StringTokenizer(s, separators);
return new Iterable<String>() {
@@ -1130,6 +1216,7 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static Iterable<String> tokenize(@NotNull final StringTokenizer tokenizer) {
return new Iterable<String>() {
@NotNull
@@ -1160,6 +1247,7 @@ public class StringUtil extends StringUtilRt {
* The <b>word</b> here means the maximum sub-string consisting entirely of characters which are <code>Character.isJavaIdentifierPart(c)</code>.
*/
@NotNull
+ @Contract(pure = true)
public static List<String> getWordsIn(@NotNull String text) {
List<String> result = null;
int start = -1;
@@ -1190,6 +1278,7 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static List<TextRange> getWordIndicesIn(@NotNull String text) {
List<TextRange> result = new SmartList<TextRange>();
int start = -1;
@@ -1211,11 +1300,13 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static String join(@NotNull final String[] strings, @NotNull final String separator) {
return join(strings, 0, strings.length, separator);
}
@NotNull
+ @Contract(pure = true)
public static String join(@NotNull final String[] strings, int startIndex, int endIndex, @NotNull final String separator) {
final StringBuilder result = new StringBuilder();
for (int i = startIndex; i < endIndex; i++) {
@@ -1226,6 +1317,7 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static String[] zip(@NotNull String[] strings1, @NotNull String[] strings2, String separator) {
if (strings1.length != strings2.length) throw new IllegalArgumentException();
@@ -1238,6 +1330,7 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static String[] surround(@NotNull String[] strings1, String prefix, String suffix) {
String[] result = ArrayUtil.newStringArray(strings1.length);
for (int i = 0; i < result.length; i++) {
@@ -1248,11 +1341,13 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static <T> String join(@NotNull T[] items, @NotNull Function<T, String> f, @NotNull @NonNls String separator) {
return join(Arrays.asList(items), f, separator);
}
@NotNull
+ @Contract(pure = true)
public static <T> String join(@NotNull Collection<? extends T> items,
@NotNull Function<? super T, String> f,
@NotNull @NonNls String separator) {
@@ -1260,6 +1355,7 @@ public class StringUtil extends StringUtilRt {
return join((Iterable<? extends T>)items, f, separator);
}
+ @Contract(pure = true)
public static String join(@NotNull Iterable<?> items, @NotNull @NonNls String separator) {
StringBuilder result = new StringBuilder();
for (Object item : items) {
@@ -1272,6 +1368,7 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static <T> String join(@NotNull Iterable<? extends T> items,
@NotNull Function<? super T, String> f,
@NotNull @NonNls String separator) {
@@ -1287,6 +1384,7 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static String join(@NotNull Collection<? extends String> strings, @NotNull String separator) {
StringBuilder result = new StringBuilder();
join(strings, separator, result);
@@ -1309,6 +1407,7 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static String join(@NotNull final int[] strings, @NotNull final String separator) {
final StringBuilder result = new StringBuilder();
for (int i = 0; i < strings.length; i++) {
@@ -1319,6 +1418,7 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static String join(@Nullable final String... strings) {
if (strings == null || strings.length == 0) return "";
@@ -1330,12 +1430,14 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static String stripQuotesAroundValue(@NotNull String text) {
if (startsWithChar(text, '\"') || startsWithChar(text, '\'')) text = text.substring(1);
if (endsWithChar(text, '\"') || endsWithChar(text, '\'')) text = text.substring(0, text.length() - 1);
return text;
}
+ @Contract(pure = true)
public static boolean isQuotedString(@NotNull String text) {
if (text.length() < 2) return false;
return startsWithChar(text, '\"') && endsWithChar(text, '\"')
@@ -1350,6 +1452,7 @@ public class StringUtil extends StringUtilRt {
* @since 5.0.1
*/
@NotNull
+ @Contract(pure = true)
public static String formatFileSize(final long fileSize) {
if (fileSize < 0x400) {
return CommonBundle.message("format.file.size.bytes", fileSize);
@@ -1365,6 +1468,7 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static String formatDuration(long duration) {
final long minutes = duration / 60000;
final long seconds = ((duration + 500L) % 60000) / 1000;
@@ -1375,6 +1479,7 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
private static String formatMinor(long number) {
if (number > 0L && number <= 9L) {
return "0" + number;
@@ -1391,6 +1496,7 @@ public class StringUtil extends StringUtilRt {
*/
@SuppressWarnings({"HardCodedStringLiteral"})
@Nullable
+ @Contract(pure = true)
public static String unpluralize(@NotNull final String name) {
if (name.endsWith("sses") || name.endsWith("shes") || name.endsWith("ches") || name.endsWith("xes")) { //?
return name.substring(0, name.length() - 2);
@@ -1430,6 +1536,7 @@ public class StringUtil extends StringUtilRt {
}
@Nullable
+ @Contract(pure = true)
private static String stripEnding(@NotNull String name, @NotNull String ending) {
if (name.endsWith(ending)) {
if (name.equals(ending)) return name; // do not return empty string
@@ -1438,6 +1545,7 @@ public class StringUtil extends StringUtilRt {
return null;
}
+ @Contract(pure = true)
public static boolean containsAlphaCharacters(@NotNull String value) {
for (int i = 0; i < value.length(); i++) {
if (Character.isLetter(value.charAt(i))) return true;
@@ -1445,6 +1553,7 @@ public class StringUtil extends StringUtilRt {
return false;
}
+ @Contract(pure = true)
public static boolean containsAnyChar(@NotNull final String value, @NotNull final String chars) {
if (chars.length() > value.length()) {
return containsAnyChar(value, chars, 0, value.length());
@@ -1454,6 +1563,7 @@ public class StringUtil extends StringUtilRt {
}
}
+ @Contract(pure = true)
public static boolean containsAnyChar(@NotNull final String value,
@NotNull final String chars,
final int start, final int end) {
@@ -1466,6 +1576,7 @@ public class StringUtil extends StringUtilRt {
return false;
}
+ @Contract(pure = true)
public static boolean containsChar(@NotNull final String value, final char ch) {
return value.indexOf(ch) >= 0;
}
@@ -1473,7 +1584,7 @@ public class StringUtil extends StringUtilRt {
/**
* @deprecated use #capitalize(String)
*/
- @Contract("null -> null; !null -> !null")
+ @Contract(value = "null -> null; !null -> !null", pure = true)
public static String firstLetterToUpperCase(@Nullable final String displayString) {
if (displayString == null || displayString.isEmpty()) return displayString;
char firstChar = displayString.charAt(0);
@@ -1494,6 +1605,7 @@ public class StringUtil extends StringUtilRt {
* @return stripped string e.g. "mystring"
*/
@NotNull
+ @Contract(pure = true)
public static String strip(@NotNull final String s, @NotNull final CharFilter filter) {
final StringBuilder result = new StringBuilder(s.length());
for (int i = 0; i < s.length(); i++) {
@@ -1506,11 +1618,13 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static List<String> findMatches(@NotNull String s, @NotNull Pattern pattern) {
return findMatches(s, pattern, 1);
}
@NotNull
+ @Contract(pure = true)
public static List<String> findMatches(@NotNull String s, @NotNull Pattern pattern, int groupIndex) {
List<String> result = new SmartList<String>();
Matcher m = pattern.matcher(s);
@@ -1530,6 +1644,7 @@ public class StringUtil extends StringUtilRt {
* @param filter search filter
* @return position of the first character accepted or -1 if not found
*/
+ @Contract(pure = true)
public static int findFirst(@NotNull final CharSequence s, @NotNull CharFilter filter) {
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
@@ -1541,18 +1656,22 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static String replaceSubstring(@NotNull String string, @NotNull TextRange range, @NotNull String replacement) {
return range.replace(string, replacement);
}
+ @Contract(pure = true)
public static boolean startsWithWhitespace(@NotNull String text) {
return !text.isEmpty() && Character.isWhitespace(text.charAt(0));
}
+ @Contract(pure = true)
public static boolean isChar(CharSequence seq, int index, char c) {
return index >= 0 && index < seq.length() && seq.charAt(index) == c;
}
+ @Contract(pure = true)
public static boolean startsWith(@NotNull CharSequence text, @NotNull CharSequence prefix) {
int l1 = text.length();
int l2 = prefix.length();
@@ -1565,6 +1684,7 @@ public class StringUtil extends StringUtilRt {
return true;
}
+ @Contract(pure = true)
public static boolean startsWith(@NotNull CharSequence text, int startIndex, @NotNull CharSequence prefix) {
int l1 = text.length() - startIndex;
int l2 = prefix.length();
@@ -1577,6 +1697,7 @@ public class StringUtil extends StringUtilRt {
return true;
}
+ @Contract(pure = true)
public static boolean endsWith(@NotNull CharSequence text, @NotNull CharSequence suffix) {
int l1 = text.length();
int l2 = suffix.length();
@@ -1590,10 +1711,12 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static String commonPrefix(@NotNull String s1, @NotNull String s2) {
return s1.substring(0, commonPrefixLength(s1, s2));
}
+ @Contract(pure = true)
public static int commonPrefixLength(@NotNull CharSequence s1, @NotNull CharSequence s2) {
int i;
int minLength = Math.min(s1.length(), s2.length());
@@ -1606,10 +1729,12 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static String commonSuffix(@NotNull String s1, @NotNull String s2) {
return s1.substring(s1.length() - commonSuffixLength(s1, s2));
}
+ @Contract(pure = true)
public static int commonSuffixLength(@NotNull CharSequence s1, @NotNull CharSequence s2) {
int s1Length = s1.length();
int s2Length = s2.length();
@@ -1633,10 +1758,12 @@ public class StringUtil extends StringUtilRt {
* @return <code>true</code> if given symbol is contained at the target range of the given char sequence;
* <code>false</code> otherwise
*/
+ @Contract(pure = true)
public static boolean contains(@NotNull CharSequence s, int start, int end, char c) {
return indexOf(s, c, start, end) >= 0;
}
+ @Contract(pure = true)
public static boolean containsWhitespaces(@Nullable CharSequence s) {
if (s == null) return false;
@@ -1646,14 +1773,17 @@ public class StringUtil extends StringUtilRt {
return false;
}
+ @Contract(pure = true)
public static int indexOf(@NotNull CharSequence s, char c) {
return indexOf(s, c, 0, s.length());
}
+ @Contract(pure = true)
public static int indexOf(@NotNull CharSequence s, char c, int start) {
return indexOf(s, c, start, s.length());
}
+ @Contract(pure = true)
public static int indexOf(@NotNull CharSequence s, char c, int start, int end) {
for (int i = start; i < end; i++) {
if (s.charAt(i) == c) return i;
@@ -1661,10 +1791,12 @@ public class StringUtil extends StringUtilRt {
return -1;
}
+ @Contract(pure = true)
public static boolean contains(@NotNull CharSequence sequence, @NotNull CharSequence infix) {
return indexOf(sequence, infix) >= 0;
}
-
+
+ @Contract(pure = true)
public static int indexOf(@NotNull CharSequence sequence, @NotNull CharSequence infix) {
for (int i = 0; i < sequence.length() - infix.length(); i++) {
if (startsWith(sequence, i, infix)) {
@@ -1674,6 +1806,7 @@ public class StringUtil extends StringUtilRt {
return -1;
}
+ @Contract(pure = true)
public static int indexOf(@NotNull CharSequence s, char c, int start, int end, boolean caseSensitive) {
for (int i = start; i < end; i++) {
if (charsMatch(s.charAt(i), c, !caseSensitive)) return i;
@@ -1681,6 +1814,7 @@ public class StringUtil extends StringUtilRt {
return -1;
}
+ @Contract(pure = true)
public static int indexOf(@NotNull char[] s, char c, int start, int end, boolean caseSensitive) {
for (int i = start; i < end; i++) {
if (charsMatch(s[i], c, !caseSensitive)) return i;
@@ -1688,24 +1822,29 @@ public class StringUtil extends StringUtilRt {
return -1;
}
+ @Contract(pure = true)
public static int indexOfSubstringEnd(@NotNull String text, @NotNull String subString) {
int i = text.indexOf(subString);
if (i == -1) return -1;
return i + subString.length();
}
+ @Contract(pure = true)
public static int indexOfAny(@NotNull final String s, @NotNull final String chars) {
return indexOfAny(s, chars, 0, s.length());
}
+ @Contract(pure = true)
public static int indexOfAny(@NotNull final CharSequence s, @NotNull final String chars) {
return indexOfAny(s, chars, 0, s.length());
}
+ @Contract(pure = true)
public static int indexOfAny(@NotNull final String s, @NotNull final String chars, final int start, final int end) {
return indexOfAny((CharSequence)s, chars, start, end);
}
+ @Contract(pure = true)
public static int indexOfAny(@NotNull final CharSequence s, @NotNull final String chars, final int start, final int end) {
for (int i = start; i < end; i++) {
if (containsChar(chars, s.charAt(i))) return i;
@@ -1714,6 +1853,7 @@ public class StringUtil extends StringUtilRt {
}
@Nullable
+ @Contract(pure = true)
public static String substringBefore(@NotNull String text, @NotNull String subString) {
int i = text.indexOf(subString);
if (i == -1) return null;
@@ -1721,6 +1861,7 @@ public class StringUtil extends StringUtilRt {
}
@Nullable
+ @Contract(pure = true)
public static String substringAfter(@NotNull String text, @NotNull String subString) {
int i = text.indexOf(subString);
if (i == -1) return null;
@@ -1737,26 +1878,31 @@ public class StringUtil extends StringUtilRt {
* @return index of the last occurrence of the given symbol at the target sub-sequence of the given text if any;
* <code>-1</code> otherwise
*/
+ @Contract(pure = true)
public static int lastIndexOf(@NotNull CharSequence s, char c, int start, int end) {
return StringUtilRt.lastIndexOf(s, c, start, end);
}
@NotNull
+ @Contract(pure = true)
public static String first(@NotNull String text, final int maxLength, final boolean appendEllipsis) {
return text.length() > maxLength ? text.substring(0, maxLength) + (appendEllipsis ? "..." : "") : text;
}
@NotNull
+ @Contract(pure = true)
public static CharSequence first(@NotNull CharSequence text, final int length, final boolean appendEllipsis) {
return text.length() > length ? text.subSequence(0, length) + (appendEllipsis ? "..." : "") : text;
}
@NotNull
+ @Contract(pure = true)
public static CharSequence last(@NotNull CharSequence text, final int length, boolean prependEllipsis) {
return text.length() > length ? (prependEllipsis ? "..." : "") + text.subSequence(text.length() - length, text.length()) : text;
}
@NotNull
+ @Contract(pure = true)
public static String escapeChar(@NotNull final String str, final char character) {
final StringBuilder buf = new StringBuilder(str);
escapeChar(buf, character);
@@ -1772,6 +1918,7 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static String escapeQuotes(@NotNull final String str) {
return escapeChar(str, '"');
}
@@ -1781,11 +1928,13 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static String escapeSlashes(@NotNull final String str) {
return escapeChar(str, '/');
}
@NotNull
+ @Contract(pure = true)
public static String escapeBackSlashes(@NotNull final String str) {
return escapeChar(str, '\\');
}
@@ -1795,6 +1944,7 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static String unescapeSlashes(@NotNull final String str) {
final StringBuilder buf = new StringBuilder(str.length());
unescapeSlashes(buf, str);
@@ -1826,6 +1976,7 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static String wrapWithDoubleQuote(@NotNull String str) {
return '\"' + str + "\"";
}
@@ -1833,25 +1984,27 @@ public class StringUtil extends StringUtilRt {
@NonNls private static final String[] REPLACES_REFS = {"&lt;", "&gt;", "&amp;", "&#39;", "&quot;"};
@NonNls private static final String[] REPLACES_DISP = {"<", ">", "&", "'", "\""};
- @Contract("null -> null; !null -> !null")
+ @Contract(value = "null -> null; !null -> !null",pure = true)
public static String unescapeXml(@Nullable final String text) {
if (text == null) return null;
return replace(text, REPLACES_REFS, REPLACES_DISP);
}
- @Contract("null -> null; !null -> !null")
+ @Contract(value = "null -> null; !null -> !null",pure = true)
public static String escapeXml(@Nullable final String text) {
if (text == null) return null;
return replace(text, REPLACES_DISP, REPLACES_REFS);
}
@NotNull
- public static String htmlEmphasize(String text) {
+ @Contract(pure = true)
+ public static String htmlEmphasize(@NotNull String text) {
return "<b><code>" + escapeXml(text) + "</code></b>";
}
@NotNull
+ @Contract(pure = true)
public static String escapeToRegexp(@NotNull String text) {
final StringBuilder result = new StringBuilder(text.length());
return escapeToRegexp(text, result).toString();
@@ -1875,6 +2028,7 @@ public class StringUtil extends StringUtilRt {
return builder;
}
+ @Contract(pure = true)
public static boolean isNotEscapedBackslash(@NotNull char[] chars, int startOffset, int backslashOffset) {
if (chars[backslashOffset] != '\\') {
return false;
@@ -1891,6 +2045,7 @@ public class StringUtil extends StringUtilRt {
return !escaped;
}
+ @Contract(pure = true)
public static boolean isNotEscapedBackslash(@NotNull CharSequence text, int startOffset, int backslashOffset) {
if (text.charAt(backslashOffset) != '\\') {
return false;
@@ -1908,6 +2063,7 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static String replace(@NotNull String text, @NotNull String[] from, @NotNull String[] to) {
final StringBuilder result = new StringBuilder(text.length());
replace:
@@ -1929,6 +2085,7 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static String[] filterEmptyStrings(@NotNull String[] strings) {
int emptyCount = 0;
for (String string : strings) {
@@ -1946,14 +2103,17 @@ public class StringUtil extends StringUtilRt {
return result;
}
+ @Contract(pure = true)
public static int countNewLines(@NotNull CharSequence text) {
return countChars(text, '\n');
}
+ @Contract(pure = true)
public static int countChars(@NotNull CharSequence text, char c) {
return countChars(text, c, 0, false);
}
+ @Contract(pure = true)
public static int countChars(@NotNull CharSequence text, char c, int offset, boolean continuous) {
int count = 0;
for (int i = offset; i < text.length(); ++i) {
@@ -1968,6 +2128,7 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static String capitalsOnly(@NotNull String s) {
StringBuilder b = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
@@ -1984,6 +2145,7 @@ public class StringUtil extends StringUtilRt {
* @return {@code null} if any of given Strings is {@code null}.
*/
@Nullable
+ @Contract(pure = true)
public static String joinOrNull(@NotNull String... args) {
StringBuilder r = new StringBuilder();
for (String arg : args) {
@@ -1994,6 +2156,7 @@ public class StringUtil extends StringUtilRt {
}
@Nullable
+ @Contract(pure = true)
public static String getPropertyName(@NonNls @NotNull String methodName) {
if (methodName.startsWith("get")) {
return Introspector.decapitalize(methodName.substring(3));
@@ -2009,14 +2172,17 @@ public class StringUtil extends StringUtilRt {
}
}
+ @Contract(pure = true)
public static boolean isJavaIdentifierStart(char c) {
return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || Character.isJavaIdentifierStart(c);
}
+ @Contract(pure = true)
public static boolean isJavaIdentifierPart(char c) {
return c >= '0' && c <= '9' || isJavaIdentifierStart(c);
}
+ @Contract(pure = true)
public static boolean isJavaIdentifier(@NotNull String text) {
int len = text.length();
if (len == 0) return false;
@@ -2038,6 +2204,7 @@ public class StringUtil extends StringUtilRt {
* @return an escaped string
*/
@NotNull
+ @Contract(pure = true)
public static String escapeProperty(@NotNull String input, final boolean isKey) {
final StringBuilder escaped = new StringBuilder(input.length());
for (int i = 0; i < input.length(); i++) {
@@ -2087,6 +2254,7 @@ public class StringUtil extends StringUtilRt {
return escaped.toString();
}
+ @Contract(pure = true)
public static String getQualifiedName(@Nullable String packageName, String className) {
if (packageName == null || packageName.isEmpty()) {
return className;
@@ -2094,6 +2262,7 @@ public class StringUtil extends StringUtilRt {
return packageName + '.' + className;
}
+ @Contract(pure = true)
public static int compareVersionNumbers(@Nullable String v1, @Nullable String v2) {
// todo duplicates com.intellij.util.text.VersionComparatorUtil.compare
// todo please refactor next time you make changes here
@@ -2147,6 +2316,7 @@ public class StringUtil extends StringUtilRt {
}
}
+ @Contract(pure = true)
public static int getOccurrenceCount(@NotNull String text, final char c) {
int res = 0;
int i = 0;
@@ -2163,6 +2333,7 @@ public class StringUtil extends StringUtilRt {
return res;
}
+ @Contract(pure = true)
public static int getOccurrenceCount(@NotNull String text, @NotNull String s) {
int res = 0;
int i = 0;
@@ -2180,6 +2351,7 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static String fixVariableNameDerivedFromPropertyName(@NotNull String name) {
if (isEmptyOrSpaces(name)) return name;
char c = name.charAt(0);
@@ -2190,6 +2362,7 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static String sanitizeJavaIdentifier(@NotNull String name) {
final StringBuilder result = new StringBuilder(name.length());
@@ -2236,6 +2409,7 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static String tail(@NotNull String s, final int idx) {
return idx >= s.length() ? "" : s.substring(idx, s.length());
}
@@ -2247,6 +2421,7 @@ public class StringUtil extends StringUtilRt {
* @return array of strings
*/
@NotNull
+ @Contract(pure = true)
public static String[] splitByLines(@NotNull String string) {
return splitByLines(string, true);
}
@@ -2259,11 +2434,13 @@ public class StringUtil extends StringUtilRt {
* @return array of strings
*/
@NotNull
+ @Contract(pure = true)
public static String[] splitByLines(@NotNull String string, boolean excludeEmptyStrings) {
return (excludeEmptyStrings ? EOL_SPLIT_PATTERN : EOL_SPLIT_PATTERN_WITH_EMPTY).split(string);
}
@NotNull
+ @Contract(pure = true)
public static String[] splitByLinesDontTrim(@NotNull String string) {
return EOL_SPLIT_DONT_TRIM_PATTERN.split(string);
}
@@ -2280,14 +2457,16 @@ public class StringUtil extends StringUtilRt {
* \r<br>
* </blockquote>
* will return the following array: foo\r\n, \n, bar\n, \r\n, baz\r, \r
- *
+ *
*/
@NotNull
+ @Contract(pure = true)
public static String[] splitByLinesKeepSeparators(@NotNull String string) {
return EOL_SPLIT_KEEP_SEPARATORS.split(string);
}
@NotNull
+ @Contract(pure = true)
public static List<Pair<String, Integer>> getWordsWithOffset(@NotNull String s) {
List<Pair<String, Integer>> res = ContainerUtil.newArrayList();
s += " ";
@@ -2315,10 +2494,12 @@ public class StringUtil extends StringUtilRt {
* Implementation of "Sorting for Humans: Natural Sort Order":
* http://www.codinghorror.com/blog/2007/12/sorting-for-humans-natural-sort-order.html
*/
+ @Contract(pure = true)
public static int naturalCompare(@Nullable String string1, @Nullable String string2) {
return naturalCompare(string1, string2, false);
}
+ @Contract(pure = true)
private static int naturalCompare(@Nullable String string1, @Nullable String string2, boolean caseSensitive) {
//noinspection StringEquality
if (string1 == string2) {
@@ -2333,7 +2514,8 @@ public class StringUtil extends StringUtilRt {
final int string1Length = string1.length();
final int string2Length = string2.length();
- int i = 0, j = 0;
+ int i = 0;
+ int j = 0;
for (; i < string1Length && j < string2Length; i++, j++) {
char ch1 = string1.charAt(i);
char ch2 = string2.charAt(j);
@@ -2404,10 +2586,12 @@ public class StringUtil extends StringUtilRt {
return string1Length - string2Length;
}
+ @Contract(pure = true)
public static boolean isDecimalDigit(char c) {
return c >= '0' && c <= '9';
}
+ @Contract(pure = true)
public static int compare(@Nullable String s1, @Nullable String s2, boolean ignoreCase) {
//noinspection StringEquality
if (s1 == s2) return 0;
@@ -2416,15 +2600,18 @@ public class StringUtil extends StringUtilRt {
return ignoreCase ? s1.compareToIgnoreCase(s2) : s1.compareTo(s2);
}
+ @Contract(pure = true)
public static int comparePairs(@Nullable String s1, @Nullable String t1, @Nullable String s2, @Nullable String t2, boolean ignoreCase) {
final int compare = compare(s1, s2, ignoreCase);
return compare != 0 ? compare : compare(t1, t2, ignoreCase);
}
+ @Contract(pure = true)
public static int hashCode(@NotNull CharSequence s) {
return stringHashCode(s);
}
+ @Contract(pure = true)
public static boolean equals(@Nullable CharSequence s1, @Nullable CharSequence s2) {
if (s1 == null ^ s2 == null) {
return false;
@@ -2445,6 +2632,7 @@ public class StringUtil extends StringUtilRt {
return true;
}
+ @Contract(pure = true)
public static boolean equalsIgnoreCase(@Nullable CharSequence s1, @Nullable CharSequence s2) {
if (s1 == null ^ s2 == null) {
return false;
@@ -2465,6 +2653,7 @@ public class StringUtil extends StringUtilRt {
return true;
}
+ @Contract(pure = true)
public static int compare(char c1, char c2, boolean ignoreCase) {
// duplicating String.equalsIgnoreCase logic
int d = c1 - c2;
@@ -2488,11 +2677,13 @@ public class StringUtil extends StringUtilRt {
return d;
}
+ @Contract(pure = true)
public static boolean charsMatch(char c1, char c2, boolean ignoreCase) {
return compare(c1, c2, ignoreCase) == 0;
}
@NotNull
+ @Contract(pure = true)
public static String formatLinks(@NotNull String message) {
Pattern linkPattern = Pattern.compile("http://[a-zA-Z0-9\\./\\-\\+]+");
StringBuffer result = new StringBuffer();
@@ -2504,25 +2695,30 @@ public class StringUtil extends StringUtilRt {
return result.toString();
}
+ @Contract(pure = true)
public static boolean isHexDigit(char c) {
return '0' <= c && c <= '9' || 'a' <= c && c <= 'f' || 'A' <= c && c <= 'F';
}
+ @Contract(pure = true)
public static boolean isOctalDigit(char c) {
return '0' <= c && c <= '7';
}
@NotNull
+ @Contract(pure = true)
public static String shortenTextWithEllipsis(@NotNull final String text, final int maxLength, final int suffixLength) {
return shortenTextWithEllipsis(text, maxLength, suffixLength, false);
}
@NotNull
+ @Contract(pure = true)
public static String trimMiddle(@NotNull String text, int maxLength) {
return shortenTextWithEllipsis(text, maxLength, maxLength >> 1, true);
}
@NotNull
+ @Contract(pure = true)
public static String shortenTextWithEllipsis(@NotNull final String text,
final int maxLength,
final int suffixLength,
@@ -2539,6 +2735,7 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static String shortenTextWithEllipsis(@NotNull final String text,
final int maxLength,
final int suffixLength,
@@ -2548,47 +2745,57 @@ public class StringUtil extends StringUtilRt {
}
@NotNull
+ @Contract(pure = true)
public static String shortenPathWithEllipsis(@NotNull final String path, final int maxLength, boolean useEllipsisSymbol) {
return shortenTextWithEllipsis(path, maxLength, (int)(maxLength * 0.7), useEllipsisSymbol);
}
@NotNull
+ @Contract(pure = true)
public static String shortenPathWithEllipsis(@NotNull final String path, final int maxLength) {
return shortenPathWithEllipsis(path, maxLength, false);
}
+ @Contract(pure = true)
public static boolean charsEqual(char a, char b, boolean ignoreCase) {
return ignoreCase ? charsEqualIgnoreCase(a, b) : a == b;
}
+ @Contract(pure = true)
public static boolean charsEqualIgnoreCase(char a, char b) {
return StringUtilRt.charsEqualIgnoreCase(a, b);
}
+ @Contract(pure = true)
public static char toUpperCase(char a) {
return StringUtilRt.toUpperCase(a);
}
@NotNull
+ @Contract(pure = true)
public static String toUpperCase(@NotNull String a) {
return StringUtilRt.toUpperCase(a);
}
+ @Contract(pure = true)
public static char toLowerCase(final char a) {
return StringUtilRt.toLowerCase(a);
}
@NotNull
+ @Contract(pure = true)
public static String convertLineSeparators(@NotNull String text) {
return StringUtilRt.convertLineSeparators(text);
}
@NotNull
+ @Contract(pure = true)
public static String convertLineSeparators(@NotNull String text, boolean keepCarriageReturn) {
return StringUtilRt.convertLineSeparators(text, keepCarriageReturn);
}
@NotNull
+ @Contract(pure = true)
public static String convertLineSeparators(@NotNull String text, @NotNull String newSeparator) {
return StringUtilRt.convertLineSeparators(text, newSeparator);
}
@@ -2606,34 +2813,41 @@ public class StringUtil extends StringUtilRt {
return StringUtilRt.convertLineSeparators(text, newSeparator, offsetsToKeep, keepCarriageReturn);
}
+ @Contract(pure = true)
public static int parseInt(final String string, final int defaultValue) {
return StringUtilRt.parseInt(string, defaultValue);
}
+ @Contract(pure = true)
public static double parseDouble(final String string, final double defaultValue) {
return StringUtilRt.parseDouble(string, defaultValue);
}
+ @Contract(pure = true)
public static boolean parseBoolean(String string, final boolean defaultValue) {
return StringUtilRt.parseBoolean(string, defaultValue);
}
@NotNull
+ @Contract(pure = true)
public static String getShortName(@NotNull Class aClass) {
return StringUtilRt.getShortName(aClass);
}
@NotNull
+ @Contract(pure = true)
public static String getShortName(@NotNull String fqName) {
return StringUtilRt.getShortName(fqName);
}
@NotNull
+ @Contract(pure = true)
public static String getShortName(@NotNull String fqName, char separator) {
return StringUtilRt.getShortName(fqName, separator);
}
@NotNull
+ @Contract(pure = true)
public static CharSequence newBombedCharSequence(@NotNull CharSequence sequence, long delay) {
final long myTime = System.currentTimeMillis() + delay;
return new BombedCharSequence(sequence) {
@@ -2655,23 +2869,17 @@ public class StringUtil extends StringUtilRt {
return false;
}
- private static boolean trimStart(@NotNull StringBuilder buffer, @NotNull CharSequence start) {
- if (startsWith(buffer, start)) {
- buffer.delete(0, start.length());
- return true;
- }
- return false;
- }
-
/**
* Say smallPart = "op" and bigPart="open". Method returns true for "Ope" and false for "ops"
*/
+ @Contract(pure = true)
public static boolean isBetween(@NotNull String string, @NotNull String smallPart, @NotNull String bigPart) {
final String s = string.toLowerCase();
return s.startsWith(smallPart.toLowerCase()) && bigPart.toLowerCase().startsWith(s);
}
- public static String getShortened(String s, int maxWidth) {
+ @Contract(pure = true)
+ public static String getShortened(@NotNull String s, int maxWidth) {
int length = s.length();
if (isEmpty(s) || length <= maxWidth) return s;
ArrayList<String> words = new ArrayList<String>();
diff --git a/platform/util/src/com/intellij/util/ArrayUtil.java b/platform/util/src/com/intellij/util/ArrayUtil.java
index d0419de9e820..0dcfdb307ae0 100644
--- a/platform/util/src/com/intellij/util/ArrayUtil.java
+++ b/platform/util/src/com/intellij/util/ArrayUtil.java
@@ -18,6 +18,7 @@ package com.intellij.util;
import com.intellij.openapi.util.Comparing;
import com.intellij.util.text.CharArrayCharSequence;
import gnu.trove.Equality;
+import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -64,6 +65,7 @@ public class ArrayUtil extends ArrayUtilRt {
private ArrayUtil() { }
@NotNull
+ @Contract(pure=true)
public static byte[] realloc(@NotNull byte[] array, final int newSize) {
if (newSize == 0) {
return EMPTY_BYTE_ARRAY;
@@ -79,6 +81,7 @@ public class ArrayUtil extends ArrayUtilRt {
return result;
}
@NotNull
+ @Contract(pure=true)
public static boolean[] realloc(@NotNull boolean[] array, final int newSize) {
if (newSize == 0) {
return EMPTY_BOOLEAN_ARRAY;
@@ -95,6 +98,7 @@ public class ArrayUtil extends ArrayUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static int[] realloc(@NotNull int[] array, final int newSize) {
if (newSize == 0) {
return EMPTY_INT_ARRAY;
@@ -110,6 +114,7 @@ public class ArrayUtil extends ArrayUtilRt {
return result;
}
@NotNull
+ @Contract(pure=true)
public static <T> T[] realloc(@NotNull T[] array, final int newSize, @NotNull ArrayFactory<T> factory) {
final int oldSize = array.length;
if (oldSize == newSize) {
@@ -126,12 +131,14 @@ public class ArrayUtil extends ArrayUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static int[] append(@NotNull int[] array, int value) {
array = realloc(array, array.length + 1);
array[array.length - 1] = value;
return array;
}
@NotNull
+ @Contract(pure=true)
public static int[] insert(@NotNull int[] array, int index, int value) {
int[] result = new int[array.length + 1];
System.arraycopy(array, 0, result, 0, index);
@@ -141,12 +148,14 @@ public class ArrayUtil extends ArrayUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static byte[] append(@NotNull byte[] array, byte value) {
array = realloc(array, array.length + 1);
array[array.length - 1] = value;
return array;
}
@NotNull
+ @Contract(pure=true)
public static boolean[] append(@NotNull boolean[] array, boolean value) {
array = realloc(array, array.length + 1);
array[array.length - 1] = value;
@@ -154,6 +163,7 @@ public class ArrayUtil extends ArrayUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static char[] realloc(@NotNull char[] array, final int newSize) {
if (newSize == 0) {
return EMPTY_CHAR_ARRAY;
@@ -170,12 +180,14 @@ public class ArrayUtil extends ArrayUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> T[] toObjectArray(@NotNull Collection<T> collection, @NotNull Class<T> aClass) {
@SuppressWarnings("unchecked") T[] array = (T[])Array.newInstance(aClass, collection.size());
return collection.toArray(array);
}
@NotNull
+ @Contract(pure=true)
public static <T> T[] toObjectArray(@NotNull Class<T> aClass, @NotNull Object... source) {
@SuppressWarnings("unchecked") T[] array = (T[])Array.newInstance(aClass, source.length);
System.arraycopy(source, 0, array, 0, array.length);
@@ -183,6 +195,7 @@ public class ArrayUtil extends ArrayUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static Object[] toObjectArray(@NotNull Collection<?> collection) {
if (collection.isEmpty()) return EMPTY_OBJECT_ARRAY;
//noinspection SSBasedInspection
@@ -190,6 +203,7 @@ public class ArrayUtil extends ArrayUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static int[] toIntArray(@NotNull Collection<Integer> list) {
int[] ret = newIntArray(list.size());
int i = 0;
@@ -200,6 +214,7 @@ public class ArrayUtil extends ArrayUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> T[] mergeArrays(@NotNull T[] a1, @NotNull T[] a2) {
if (a1.length == 0) {
return a2;
@@ -219,6 +234,7 @@ public class ArrayUtil extends ArrayUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> T[] mergeCollections(@NotNull Collection<? extends T> c1, @NotNull Collection<? extends T> c2, @NotNull ArrayFactory<T> factory) {
T[] res = factory.create(c1.size() + c2.size());
@@ -236,6 +252,7 @@ public class ArrayUtil extends ArrayUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> T[] mergeArrays(@NotNull T[] a1, @NotNull T[] a2, @NotNull ArrayFactory<T> factory) {
if (a1.length == 0) {
return a2;
@@ -250,11 +267,13 @@ public class ArrayUtil extends ArrayUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static String[] mergeArrays(@NotNull String[] a1, @NotNull String... a2) {
return mergeArrays(a1, a2, STRING_ARRAY_FACTORY);
}
@NotNull
+ @Contract(pure=true)
public static int[] mergeArrays(@NotNull int[] a1, @NotNull int[] a2) {
if (a1.length == 0) {
return a2;
@@ -269,6 +288,7 @@ public class ArrayUtil extends ArrayUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static byte[] mergeArrays(@NotNull byte[] a1, @NotNull byte[] a2) {
if (a1.length == 0) {
return a2;
@@ -292,6 +312,7 @@ public class ArrayUtil extends ArrayUtilRt {
* @return destination array
*/
@NotNull
+ @Contract(pure=true)
public static <T> T[] mergeArrayAndCollection(@NotNull T[] array,
@NotNull Collection<T> collection,
@NotNull final ArrayFactory<T> factory) {
@@ -326,16 +347,19 @@ public class ArrayUtil extends ArrayUtilRt {
* @return new array
*/
@NotNull
+ @Contract(pure=true)
public static <T> T[] append(@NotNull final T[] src, @Nullable final T element) {
return append(src, element, (Class<T>)src.getClass().getComponentType());
}
@NotNull
+ @Contract(pure=true)
public static <T> T[] prepend(final T element, @NotNull final T[] array) {
return prepend(element, array, (Class<T>)array.getClass().getComponentType());
}
@NotNull
+ @Contract(pure=true)
public static <T> T[] prepend(T element, @NotNull T[] array, @NotNull Class<T> type) {
int length = array.length;
T[] result = (T[])Array.newInstance(type, length + 1);
@@ -345,6 +369,7 @@ public class ArrayUtil extends ArrayUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static byte[] prepend(byte element, @NotNull byte[] array) {
int length = array.length;
final byte[] result = new byte[length + 1];
@@ -353,8 +378,8 @@ public class ArrayUtil extends ArrayUtilRt {
return result;
}
+ @Contract(pure=true)
public static <T> T[] append(@NotNull final T[] src, final T element, @NotNull ArrayFactory<T> factory) {
-
int length = src.length;
T[] result = factory.create(length + 1);
System.arraycopy(src, 0, result, 0, length);
@@ -363,6 +388,7 @@ public class ArrayUtil extends ArrayUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> T[] append(@NotNull T[] src, @Nullable final T element, @NotNull Class<T> componentType) {
int length = src.length;
T[] result = (T[])Array.newInstance(componentType, length + 1);
@@ -379,6 +405,7 @@ public class ArrayUtil extends ArrayUtilRt {
* @return modified array.
*/
@NotNull
+ @Contract(pure=true)
public static <T> T[] remove(@NotNull final T[] src, int idx) {
int length = src.length;
if (idx < 0 || idx >= length) {
@@ -391,6 +418,7 @@ public class ArrayUtil extends ArrayUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> T[] remove(@NotNull final T[] src, int idx, @NotNull ArrayFactory<T> factory) {
int length = src.length;
if (idx < 0 || idx >= length) {
@@ -403,6 +431,7 @@ public class ArrayUtil extends ArrayUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> T[] remove(@NotNull final T[] src, T element) {
final int idx = find(src, element);
if (idx == -1) return src;
@@ -411,6 +440,7 @@ public class ArrayUtil extends ArrayUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> T[] remove(@NotNull final T[] src, T element, @NotNull ArrayFactory<T> factory) {
final int idx = find(src, element);
if (idx == -1) return src;
@@ -419,6 +449,7 @@ public class ArrayUtil extends ArrayUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static int[] remove(@NotNull final int[] src, int idx) {
int length = src.length;
if (idx < 0 || idx >= length) {
@@ -430,6 +461,7 @@ public class ArrayUtil extends ArrayUtilRt {
return result;
}
@NotNull
+ @Contract(pure=true)
public static short[] remove(@NotNull final short[] src, int idx) {
int length = src.length;
if (idx < 0 || idx >= length) {
@@ -441,6 +473,7 @@ public class ArrayUtil extends ArrayUtilRt {
return result;
}
+ @Contract(pure=true)
public static <T> int lastIndexOf(@NotNull final T[] src, final T obj) {
for (int i = src.length - 1; i >= 0; i--) {
final T o = src[i];
@@ -458,14 +491,17 @@ public class ArrayUtil extends ArrayUtilRt {
return -1;
}
+ @Contract(pure=true)
public static int find(@NotNull int[] src, int obj) {
return indexOf(src, obj);
}
+ @Contract(pure=true)
public static <T> int find(@NotNull final T[] src, final T obj) {
return ArrayUtilRt.find(src, obj);
}
+ @Contract(pure=true)
public static boolean startsWith(@NotNull byte[] array, @NotNull byte[] prefix) {
if (array == prefix) {
return true;
@@ -484,6 +520,7 @@ public class ArrayUtil extends ArrayUtilRt {
return true;
}
+ @Contract(pure=true)
public static <E> boolean startsWith(@NotNull E[] array, @NotNull E[] subArray) {
if (array == subArray) {
return true;
@@ -502,6 +539,7 @@ public class ArrayUtil extends ArrayUtilRt {
return true;
}
+ @Contract(pure=true)
public static boolean startsWith(@NotNull byte[] array, int start, @NotNull byte[] subArray) {
int length = subArray.length;
if (array.length - start < length) {
@@ -517,6 +555,7 @@ public class ArrayUtil extends ArrayUtilRt {
return true;
}
+ @Contract(pure=true)
public static <T> boolean equals(@NotNull T[] a1, @NotNull T[] a2, @NotNull Equality<? super T> comparator) {
if (a1 == a2) {
return true;
@@ -535,6 +574,7 @@ public class ArrayUtil extends ArrayUtilRt {
return true;
}
+ @Contract(pure=true)
public static <T> boolean equals(@NotNull T[] a1, @NotNull T[] a2, @NotNull Comparator<? super T> comparator) {
if (a1 == a2) {
return true;
@@ -553,6 +593,7 @@ public class ArrayUtil extends ArrayUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> T[] reverseArray(@NotNull T[] array) {
T[] newArray = array.clone();
for (int i = 0; i < array.length; i++) {
@@ -562,6 +603,7 @@ public class ArrayUtil extends ArrayUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static int[] reverseArray(@NotNull int[] array) {
int[] newArray = array.clone();
for (int i = 0; i < array.length; i++) {
@@ -576,6 +618,7 @@ public class ArrayUtil extends ArrayUtilRt {
}
}
+ @Contract(pure=true)
public static int lexicographicCompare(@NotNull String[] obj1, @NotNull String[] obj2) {
for (int i = 0; i < Math.max(obj1.length, obj2.length); i++) {
String o1 = i < obj1.length ? obj1[i] : null;
@@ -589,6 +632,7 @@ public class ArrayUtil extends ArrayUtilRt {
}
//must be Comparables
+ @Contract(pure=true)
public static <T> int lexicographicCompare(@NotNull T[] obj1, @NotNull T[] obj2) {
for (int i = 0; i < Math.max(obj1.length, obj2.length); i++) {
T o1 = i < obj1.length ? obj1[i] : null;
@@ -637,10 +681,12 @@ public class ArrayUtil extends ArrayUtilRt {
array[i1] = t;
}
+ @Contract(pure=true)
public static int indexOf(@NotNull Object[] objects, @Nullable Object object) {
return indexOf(objects, object, 0, objects.length);
}
+ @Contract(pure=true)
public static int indexOf(@NotNull Object[] objects, Object object, int start, int end) {
if (object == null) {
for (int i = start; i < end; i++) {
@@ -655,6 +701,7 @@ public class ArrayUtil extends ArrayUtilRt {
return -1;
}
+ @Contract(pure=true)
public static <T> int indexOf(@NotNull List<T> objects, T object, @NotNull Equality<T> comparator) {
for (int i = 0; i < objects.size(); i++) {
if (comparator.equals(objects.get(i), object)) return i;
@@ -662,6 +709,7 @@ public class ArrayUtil extends ArrayUtilRt {
return -1;
}
+ @Contract(pure=true)
public static <T> int indexOf(@NotNull List<T> objects, T object, @NotNull Comparator<T> comparator) {
for (int i = 0; i < objects.size(); i++) {
if (comparator.compare(objects.get(i), object) == 0) return i;
@@ -669,6 +717,7 @@ public class ArrayUtil extends ArrayUtilRt {
return -1;
}
+ @Contract(pure=true)
public static <T> int indexOf(@NotNull T[] objects, T object, @NotNull Equality<T> comparator) {
for (int i = 0; i < objects.length; i++) {
if (comparator.equals(objects[i], object)) return i;
@@ -676,6 +725,7 @@ public class ArrayUtil extends ArrayUtilRt {
return -1;
}
+ @Contract(pure=true)
public static int indexOf(@NotNull int[] ints, int value) {
for (int i = 0; i < ints.length; i++) {
if (ints[i] == value) return i;
@@ -683,6 +733,7 @@ public class ArrayUtil extends ArrayUtilRt {
return -1;
}
+ @Contract(pure=true)
public static int indexOf(@NotNull short[] ints, short value) {
for (int i = 0; i < ints.length; i++) {
if (ints[i] == value) return i;
@@ -691,10 +742,12 @@ public class ArrayUtil extends ArrayUtilRt {
return -1;
}
+ @Contract(pure=true)
public static boolean contains(@Nullable final Object o, @NotNull Object... objects) {
return indexOf(objects, o) >= 0;
}
+ @Contract(pure=true)
public static boolean contains(@Nullable final String s, @NotNull String... strings) {
if (s == null) {
for (String str : strings) {
@@ -711,26 +764,31 @@ public class ArrayUtil extends ArrayUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static int[] newIntArray(int count) {
return count == 0 ? EMPTY_INT_ARRAY : new int[count];
}
@NotNull
+ @Contract(pure=true)
public static long[] newLongArray(int count) {
return count == 0 ? EMPTY_LONG_ARRAY : new long[count];
}
@NotNull
+ @Contract(pure=true)
public static String[] newStringArray(int count) {
return count == 0 ? EMPTY_STRING_ARRAY : new String[count];
}
@NotNull
+ @Contract(pure=true)
public static Object[] newObjectArray(int count) {
return count == 0 ? EMPTY_OBJECT_ARRAY : new Object[count];
}
@NotNull
+ @Contract(pure=true)
public static <E> E[] ensureExactSize(int count, @NotNull E[] sample) {
if (count == sample.length) return sample;
@SuppressWarnings({"unchecked"}) final E[] array = (E[])Array.newInstance(sample.getClass().getComponentType(), count);
@@ -738,16 +796,19 @@ public class ArrayUtil extends ArrayUtilRt {
}
@Nullable
+ @Contract(pure=true)
public static <T> T getFirstElement(@NotNull T[] array) {
return array.length > 0 ? array[0] : null;
}
@Nullable
+ @Contract(pure=true)
public static <T> T getLastElement(@NotNull T[] array) {
return array.length > 0 ? array[array.length - 1] : null;
}
@NotNull
+ @Contract(pure=true)
public static String[] toStringArray(@Nullable Collection<String> collection) {
return ArrayUtilRt.toStringArray(collection);
}
diff --git a/platform/util/src/com/intellij/util/ReflectionUtil.java b/platform/util/src/com/intellij/util/ReflectionUtil.java
index d5f6a58dc951..8e2204415988 100644
--- a/platform/util/src/com/intellij/util/ReflectionUtil.java
+++ b/platform/util/src/com/intellij/util/ReflectionUtil.java
@@ -19,17 +19,15 @@ package com.intellij.util;
import com.intellij.Patches;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Condition;
-import com.intellij.util.containers.ContainerUtil;
+import com.intellij.openapi.util.DifferenceFilter;
+import com.intellij.util.containers.*;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import sun.reflect.ConstructorAccessor;
import java.lang.reflect.*;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
+import java.util.*;
public class ReflectionUtil {
private static final Logger LOG = Logger.getInstance("#com.intellij.util.ReflectionUtil");
@@ -479,6 +477,50 @@ public class ReflectionUtil {
return callerClass;
}
+ public static void copyFields(@NotNull Field[] fields, @NotNull Object from, @NotNull Object to) {
+ copyFields(fields, from, to, null);
+ }
+
+ public static boolean copyFields(@NotNull Field[] fields, @NotNull Object from, @NotNull Object to, @Nullable DifferenceFilter diffFilter) {
+ Set<Field> sourceFields = new com.intellij.util.containers.HashSet<Field>(Arrays.asList(from.getClass().getFields()));
+ boolean valuesChanged = false;
+ for (Field field : fields) {
+ if (sourceFields.contains(field)) {
+ if (isPublic(field) && !isFinal(field)) {
+ try {
+ if (diffFilter == null || diffFilter.isAccept(field)) {
+ copyFieldValue(from, to, field);
+ valuesChanged = true;
+ }
+ }
+ catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ }
+ return valuesChanged;
+ }
+
+ public static void copyFieldValue(@NotNull Object from, @NotNull Object to, @NotNull Field field)
+ throws IllegalAccessException {
+ Class<?> fieldType = field.getType();
+ if (fieldType.isPrimitive() || fieldType.equals(String.class)) {
+ field.set(to, field.get(from));
+ }
+ else {
+ throw new RuntimeException("Field '" + field.getName()+"' not copied: unsupported type: "+field.getType());
+ }
+ }
+
+ private static boolean isPublic(final Field field) {
+ return (field.getModifiers() & Modifier.PUBLIC) != 0;
+ }
+
+ private static boolean isFinal(final Field field) {
+ return (field.getModifiers() & Modifier.FINAL) != 0;
+ }
+
private static class MySecurityManager extends SecurityManager {
private static final MySecurityManager INSTANCE = new MySecurityManager();
diff --git a/platform/util/src/com/intellij/util/Restarter.java b/platform/util/src/com/intellij/util/Restarter.java
index 01e7fc494f5b..1eb1691808be 100644
--- a/platform/util/src/com/intellij/util/Restarter.java
+++ b/platform/util/src/com/intellij/util/Restarter.java
@@ -153,11 +153,16 @@ public class Restarter {
}
public static File createTempExecutable(File executable) throws IOException {
- File copy = new File(System.getProperty("user.home") + "/." + System.getProperty("idea.paths.selector") + "/restart/" + executable.getName());
- if (FileUtilRt.ensureCanCreateFile(copy)) {
- FileUtilRt.copy(executable, copy);
- if (!copy.setExecutable(executable.canExecute())) throw new IOException("Cannot make file executable: " + copy);
+ File executableDir = new File(System.getProperty("user.home") + "/." + System.getProperty("idea.paths.selector") + "/restart");
+ File copy = new File(executableDir.getPath() + "/" + executable.getName());
+ if (!FileUtilRt.ensureCanCreateFile(copy)) {
+ String ext = FileUtilRt.getExtension(executable.getName());
+ copy = FileUtilRt.createTempFile(executableDir, FileUtilRt.getNameWithoutExtension(copy.getName()),
+ StringUtil.isEmptyOrSpaces(ext) ? ".tmp" : ("." + ext),
+ true, false);
}
+ FileUtilRt.copy(executable, copy);
+ if (!copy.setExecutable(executable.canExecute())) throw new IOException("Cannot make file executable: " + copy);
return copy;
}
diff --git a/platform/util/src/com/intellij/util/containers/ContainerUtil.java b/platform/util/src/com/intellij/util/containers/ContainerUtil.java
index 40bd75a2eff8..0047217285a5 100644
--- a/platform/util/src/com/intellij/util/containers/ContainerUtil.java
+++ b/platform/util/src/com/intellij/util/containers/ContainerUtil.java
@@ -33,135 +33,166 @@ import java.util.LinkedHashSet;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
-@SuppressWarnings({"UtilityClassWithoutPrivateConstructor", "MethodOverridesStaticMethodOfSuperclass", "UnusedDeclaration"})
+@SuppressWarnings({"UtilityClassWithoutPrivateConstructor", "MethodOverridesStaticMethodOfSuperclass"})
public class ContainerUtil extends ContainerUtilRt {
private static final int INSERTION_SORT_THRESHOLD = 10;
private static final int DEFAULT_CONCURRENCY_LEVEL = Math.min(16, Runtime.getRuntime().availableProcessors());
@NotNull
+ @Contract(pure=true)
public static <T> T[] ar(@NotNull T... elements) {
return elements;
}
@NotNull
+ @Contract(pure=true)
public static <K, V> HashMap<K, V> newHashMap() {
return ContainerUtilRt.newHashMap();
}
@NotNull
+ @Contract(pure=true)
public static <K, V> HashMap<K, V> newHashMap(@NotNull Map<K, V> map) {
return ContainerUtilRt.newHashMap(map);
}
@NotNull
+ @Contract(pure=true)
public static <K, V> Map<K, V> newHashMap(@NotNull Pair<K, V> first, Pair<K, V>... entries) {
return ContainerUtilRt.newHashMap(first, entries);
}
@NotNull
+ @Contract(pure=true)
public static <K, V> Map<K, V> newHashMap(@NotNull List<K> keys, @NotNull List<V> values) {
return ContainerUtilRt.newHashMap(keys, values);
}
@NotNull
+ @Contract(pure=true)
public static <K extends Comparable, V> TreeMap<K, V> newTreeMap() {
return ContainerUtilRt.newTreeMap();
}
@NotNull
+ @Contract(pure=true)
public static <K extends Comparable, V> TreeMap<K, V> newTreeMap(@NotNull Map<K, V> map) {
return ContainerUtilRt.newTreeMap(map);
}
@NotNull
+ @Contract(pure=true)
public static <K, V> LinkedHashMap<K, V> newLinkedHashMap() {
return ContainerUtilRt.newLinkedHashMap();
}
@NotNull
+ @Contract(pure=true)
+ public static <K, V> LinkedHashMap<K, V> newLinkedHashMap(int capacity) {
+ return ContainerUtilRt.newLinkedHashMap(capacity);
+ }
+
+ @NotNull
+ @Contract(pure=true)
public static <K, V> LinkedHashMap<K, V> newLinkedHashMap(@NotNull Map<K, V> map) {
return ContainerUtilRt.newLinkedHashMap(map);
}
@NotNull
+ @Contract(pure=true)
public static <K, V> LinkedHashMap<K, V> newLinkedHashMap(@NotNull Pair<K, V> first, Pair<K, V>... entries) {
return ContainerUtilRt.newLinkedHashMap(first, entries);
}
@NotNull
+ @Contract(pure=true)
public static <K, V> THashMap<K, V> newTroveMap() {
return new THashMap<K, V>();
}
@NotNull
+ @Contract(pure=true)
public static <K, V> THashMap<K, V> newTroveMap(@NotNull TObjectHashingStrategy<K> strategy) {
return new THashMap<K, V>(strategy);
}
@NotNull
+ @Contract(pure=true)
public static <K extends Enum<K>, V> EnumMap<K, V> newEnumMap(@NotNull Class<K> keyType) {
return new EnumMap<K, V>(keyType);
}
@SuppressWarnings("unchecked")
@NotNull
+ @Contract(pure=true)
public static <T> TObjectHashingStrategy<T> canonicalStrategy() {
return TObjectHashingStrategy.CANONICAL;
}
@SuppressWarnings("unchecked")
@NotNull
+ @Contract(pure=true)
public static <T> TObjectHashingStrategy<T> identityStrategy() {
return TObjectHashingStrategy.IDENTITY;
}
@NotNull
+ @Contract(pure=true)
public static <K, V> IdentityHashMap<K, V> newIdentityHashMap() {
return new IdentityHashMap<K, V>();
}
@NotNull
+ @Contract(pure=true)
public static <T> LinkedList<T> newLinkedList() {
return ContainerUtilRt.newLinkedList();
}
@NotNull
+ @Contract(pure=true)
public static <T> LinkedList<T> newLinkedList(@NotNull T... elements) {
return ContainerUtilRt.newLinkedList(elements);
}
@NotNull
+ @Contract(pure=true)
public static <T> LinkedList<T> newLinkedList(@NotNull Iterable<? extends T> elements) {
return ContainerUtilRt.newLinkedList(elements);
}
@NotNull
+ @Contract(pure=true)
public static <T> ArrayList<T> newArrayList() {
return ContainerUtilRt.newArrayList();
}
@NotNull
+ @Contract(pure=true)
public static <E> ArrayList<E> newArrayList(@NotNull E... array) {
return ContainerUtilRt.newArrayList(array);
}
@NotNull
+ @Contract(pure=true)
public static <E> ArrayList<E> newArrayList(@NotNull Iterable<? extends E> iterable) {
return ContainerUtilRt.newArrayList(iterable);
}
/** @deprecated Use {@link #newArrayListWithCapacity(int)} (to remove in IDEA 15) */
@SuppressWarnings("deprecation")
+ @Contract(pure=true)
public static <T> ArrayList<T> newArrayListWithExpectedSize(int size) {
return ContainerUtilRt.newArrayListWithCapacity(size);
}
@NotNull
+ @Contract(pure=true)
public static <T> ArrayList<T> newArrayListWithCapacity(int size) {
return ContainerUtilRt.newArrayListWithCapacity(size);
}
@NotNull
+ @Contract(pure=true)
public static <T> List<T> newArrayList(@NotNull final T[] elements, final int start, final int end) {
if (start < 0 || start > end || end > elements.length) {
throw new IllegalArgumentException("start:" + start + " end:" + end + " length:" + elements.length);
@@ -184,31 +215,37 @@ public class ContainerUtil extends ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> List<T> newSmartList(T element) {
return new SmartList<T>(element);
}
@NotNull
+ @Contract(pure=true)
public static <T> List<T> newSmartList(@NotNull T... elements) {
return new SmartList<T>(elements);
}
@NotNull
+ @Contract(pure=true)
public static <T> HashSet<T> newHashSet() {
return ContainerUtilRt.newHashSet();
}
@NotNull
+ @Contract(pure=true)
public static <T> HashSet<T> newHashSet(int initialCapacity) {
return ContainerUtilRt.newHashSet(initialCapacity);
}
@NotNull
+ @Contract(pure=true)
public static <T> HashSet<T> newHashSet(@NotNull T... elements) {
return ContainerUtilRt.newHashSet(elements);
}
@NotNull
+ @Contract(pure=true)
public static <T> HashSet<T> newHashSet(@NotNull Iterable<? extends T> iterable) {
return ContainerUtilRt.newHashSet(iterable);
}
@@ -219,117 +256,141 @@ public class ContainerUtil extends ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> Set<T> newHashOrEmptySet(@Nullable Iterable<? extends T> iterable) {
boolean empty = iterable == null || iterable instanceof Collection && ((Collection)iterable).isEmpty();
return empty ? Collections.<T>emptySet() : ContainerUtilRt.newHashSet(iterable);
}
@NotNull
+ @Contract(pure=true)
public static <T> LinkedHashSet<T> newLinkedHashSet() {
return ContainerUtilRt.newLinkedHashSet();
}
@NotNull
+ @Contract(pure=true)
public static <T> LinkedHashSet<T> newLinkedHashSet(@NotNull Iterable<? extends T> elements) {
return ContainerUtilRt.newLinkedHashSet(elements);
}
@NotNull
+ @Contract(pure=true)
public static <T> LinkedHashSet<T> newLinkedHashSet(@NotNull T... elements) {
return ContainerUtilRt.newLinkedHashSet(elements);
}
@NotNull
+ @Contract(pure=true)
public static <T> THashSet<T> newTroveSet() {
return new THashSet<T>();
}
@NotNull
+ @Contract(pure=true)
public static <T> THashSet<T> newTroveSet(@NotNull TObjectHashingStrategy<T> strategy) {
return new THashSet<T>(strategy);
}
@NotNull
+ @Contract(pure=true)
public static <T> THashSet<T> newTroveSet(@NotNull T... elements) {
return newTroveSet(Arrays.asList(elements));
}
@NotNull
+ @Contract(pure=true)
public static <T> THashSet<T> newTroveSet(@NotNull TObjectHashingStrategy<T> strategy, @NotNull T... elements) {
return new THashSet<T>(Arrays.asList(elements), strategy);
}
@NotNull
+ @Contract(pure=true)
public static <T> THashSet<T> newTroveSet(@NotNull TObjectHashingStrategy<T> strategy, @NotNull Collection<T> elements) {
return new THashSet<T>(elements, strategy);
}
@NotNull
+ @Contract(pure=true)
public static <T> THashSet<T> newTroveSet(@NotNull Collection<T> elements) {
return new THashSet<T>(elements);
}
@NotNull
+ @Contract(pure=true)
public static <K> THashSet<K> newIdentityTroveSet() {
return new THashSet<K>(ContainerUtil.<K>identityStrategy());
}
@NotNull
+ @Contract(pure=true)
public static <K> THashSet<K> newIdentityTroveSet(int initialCapacity) {
return new THashSet<K>(initialCapacity, ContainerUtil.<K>identityStrategy());
}
@NotNull
+ @Contract(pure=true)
public static <K> THashSet<K> newIdentityTroveSet(@NotNull Collection<K> collection) {
return new THashSet<K>(collection, ContainerUtil.<K>identityStrategy());
}
@NotNull
+ @Contract(pure=true)
public static <K,V> THashMap<K,V> newIdentityTroveMap() {
return new THashMap<K,V>(ContainerUtil.<K>identityStrategy());
}
@NotNull
+ @Contract(pure=true)
public static <T> TreeSet<T> newTreeSet() {
return ContainerUtilRt.newTreeSet();
}
@NotNull
+ @Contract(pure=true)
public static <T> TreeSet<T> newTreeSet(@NotNull Iterable<? extends T> elements) {
return ContainerUtilRt.newTreeSet(elements);
}
@NotNull
+ @Contract(pure=true)
public static <T> TreeSet<T> newTreeSet(@NotNull T... elements) {
return ContainerUtilRt.newTreeSet(elements);
}
@NotNull
+ @Contract(pure=true)
public static <T> TreeSet<T> newTreeSet(@Nullable Comparator<? super T> comparator) {
return ContainerUtilRt.newTreeSet(comparator);
}
@NotNull
+ @Contract(pure=true)
public static <K, V> ConcurrentMap<K, V> newConcurrentMap() {
return CHM_FACTORY.createMap();
}
+ @Contract(pure=true)
public static <K, V> ConcurrentMap<K,V> newConcurrentMap(@NotNull TObjectHashingStrategy<K> hashStrategy) {
return CHM_FACTORY.createMap(hashStrategy);
}
+ @Contract(pure=true)
public static <K, V> ConcurrentMap<K,V> newConcurrentMap(int initialCapacity) {
return CHM_FACTORY.createMap(initialCapacity);
}
+ @Contract(pure=true)
public static <K, V> ConcurrentMap<K,V> newConcurrentMap(int initialCapacity, float loadFactor, int concurrencyLevel, @NotNull TObjectHashingStrategy<K> hashStrategy) {
return CHM_FACTORY.createMap(initialCapacity, loadFactor, concurrencyLevel, hashStrategy);
}
+ @Contract(pure=true)
public static <K, V> ConcurrentMap<K,V> newConcurrentMap(int initialCapacity, float loadFactor, int concurrencyLevel) {
return CHM_FACTORY.createMap(initialCapacity, loadFactor, concurrencyLevel);
}
@NotNull
+ @Contract(pure=true)
public static <E> List<E> reverse(@NotNull final List<E> elements) {
if (elements.isEmpty()) {
return ContainerUtilRt.emptyList();
@@ -349,37 +410,43 @@ public class ContainerUtil extends ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <K, V> Map<K, V> union(@NotNull Map<? extends K, ? extends V> map, @NotNull Map<? extends K, ? extends V> map2) {
- THashMap<K, V> result = new THashMap<K, V>(map.size() + map2.size());
+ Map<K, V> result = new THashMap<K, V>(map.size() + map2.size());
result.putAll(map);
result.putAll(map2);
return result;
}
@NotNull
+ @Contract(pure=true)
public static <T> Set<T> union(@NotNull Set<T> set, @NotNull Set<T> set2) {
- THashSet<T> result = new THashSet<T>(set.size() + set2.size());
+ Set<T> result = new THashSet<T>(set.size() + set2.size());
result.addAll(set);
result.addAll(set2);
return result;
}
@NotNull
+ @Contract(pure=true)
public static <E> Set<E> immutableSet(@NotNull E ... elements) {
return Collections.unmodifiableSet(new THashSet<E>(Arrays.asList(elements)));
}
@NotNull
+ @Contract(pure=true)
public static <E> ImmutableList<E> immutableList(@NotNull E ... array) {
return new ImmutableListBackedByArray<E>(array);
}
@NotNull
+ @Contract(pure=true)
public static <E> ImmutableList<E> immutableList(@NotNull List<E> list) {
return new ImmutableListBackedByList<E>(list);
}
@NotNull
+ @Contract(pure=true)
public static <K, V> ImmutableMapBuilder<K, V> immutableMapBuilder() {
return new ImmutableMapBuilder<K, V>();
}
@@ -392,6 +459,7 @@ public class ContainerUtil extends ContainerUtilRt {
return this;
}
+ @Contract(pure=true)
public Map<K, V> build() {
return Collections.unmodifiableMap(myMap);
}
@@ -434,6 +502,7 @@ public class ContainerUtil extends ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <K, V> Map<K, V> intersection(@NotNull Map<K, V> map1, @NotNull Map<K, V> map2) {
final Map<K, V> res = newHashMap();
final Set<K> keys = newHashSet();
@@ -450,6 +519,7 @@ public class ContainerUtil extends ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <K, V> Map<K,Couple<V>> diff(@NotNull Map<K, V> map1, @NotNull Map<K, V> map2) {
final Map<K, Couple<V>> res = newHashMap();
final Set<K> keys = newHashSet();
@@ -505,6 +575,7 @@ public class ContainerUtil extends ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> List<T> mergeSortedLists(@NotNull List<T> list1,
@NotNull List<T> list2,
@NotNull Comparator<? super T> comparator,
@@ -521,6 +592,7 @@ public class ContainerUtil extends ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> List<T> mergeSortedArrays(@NotNull T[] list1, @NotNull T[] list2, @NotNull Comparator<? super T> comparator, boolean mergeEqualItems, @Nullable Processor<? super T> filter) {
int index1 = 0;
int index2 = 0;
@@ -572,6 +644,7 @@ public class ContainerUtil extends ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> List<T> subList(@NotNull List<T> list, int from) {
return list.subList(from, list.size());
}
@@ -658,16 +731,19 @@ public class ContainerUtil extends ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> Iterator<T> emptyIterator() {
return EmptyIterator.getInstance();
}
@NotNull
+ @Contract(pure=true)
public static <T> Iterable<T> emptyIterable() {
return EmptyIterable.getInstance();
}
@Nullable
+ @Contract(pure=true)
public static <T> T find(@NotNull T[] array, @NotNull Condition<T> condition) {
for (T element : array) {
if (condition.value(element)) return element;
@@ -714,11 +790,13 @@ public class ContainerUtil extends ContainerUtilRt {
}
@Nullable
+ @Contract(pure=true)
public static <T, V extends T> V find(@NotNull Iterable<V> iterable, @NotNull Condition<T> condition) {
return find(iterable.iterator(), condition);
}
@Nullable
+ @Contract(pure=true)
public static <T> T find(@NotNull Iterable<? extends T> iterable, final T equalTo) {
return find(iterable, new Condition<T>() {
@Override
@@ -738,11 +816,13 @@ public class ContainerUtil extends ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T, KEY, VALUE> Map<KEY, VALUE> map2Map(@NotNull T[] collection, @NotNull Function<T, Pair<KEY, VALUE>> mapper) {
return map2Map(Arrays.asList(collection), mapper);
}
@NotNull
+ @Contract(pure=true)
public static <T, KEY, VALUE> Map<KEY, VALUE> map2Map(@NotNull Collection<? extends T> collection,
@NotNull Function<T, Pair<KEY, VALUE>> mapper) {
final Map<KEY, VALUE> set = new THashMap<KEY, VALUE>(collection.size());
@@ -754,6 +834,7 @@ public class ContainerUtil extends ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <KEY, VALUE> Map<KEY, VALUE> map2Map(@NotNull Collection<Pair<KEY, VALUE>> collection) {
final Map<KEY, VALUE> result = new THashMap<KEY, VALUE>(collection.size());
for (Pair<KEY, VALUE> pair : collection) {
@@ -763,21 +844,25 @@ public class ContainerUtil extends ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> Object[] map2Array(@NotNull T[] array, @NotNull Function<T, Object> mapper) {
return map2Array(array, Object.class, mapper);
}
@NotNull
+ @Contract(pure=true)
public static <T> Object[] map2Array(@NotNull Collection<T> array, @NotNull Function<T, Object> mapper) {
return map2Array(array, Object.class, mapper);
}
@NotNull
+ @Contract(pure=true)
public static <T, V> V[] map2Array(@NotNull T[] array, @NotNull Class<? extends V> aClass, @NotNull Function<T, V> mapper) {
return map2Array(Arrays.asList(array), aClass, mapper);
}
@NotNull
+ @Contract(pure=true)
public static <T, V> V[] map2Array(@NotNull Collection<? extends T> collection, @NotNull Class<? extends V> aClass, @NotNull Function<T, V> mapper) {
final List<V> list = map2List(collection, mapper);
@SuppressWarnings("unchecked") V[] array = (V[])Array.newInstance(aClass, list.size());
@@ -785,16 +870,19 @@ public class ContainerUtil extends ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T, V> V[] map2Array(@NotNull Collection<? extends T> collection, @NotNull V[] to, @NotNull Function<T, V> mapper) {
return map2List(collection, mapper).toArray(to);
}
@NotNull
+ @Contract(pure=true)
public static <T> List<T> filter(@NotNull T[] collection, @NotNull Condition<? super T> condition) {
return findAll(collection, condition);
}
@NotNull
+ @Contract(pure=true)
public static int[] filter(@NotNull int[] collection, @NotNull TIntProcedure condition) {
TIntArrayList result = new TIntArrayList();
for (int t : collection) {
@@ -806,11 +894,13 @@ public class ContainerUtil extends ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> List<T> filter(@NotNull Condition<? super T> condition, @NotNull T... collection) {
return findAll(collection, condition);
}
@NotNull
+ @Contract(pure=true)
public static <T> List<T> findAll(@NotNull T[] collection, @NotNull Condition<? super T> condition) {
final List<T> result = new SmartList<T>();
for (T t : collection) {
@@ -822,11 +912,13 @@ public class ContainerUtil extends ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> List<T> filter(@NotNull Collection<? extends T> collection, @NotNull Condition<? super T> condition) {
return findAll(collection, condition);
}
@NotNull
+ @Contract(pure=true)
public static <T> List<T> findAll(@NotNull Collection<? extends T> collection, @NotNull Condition<? super T> condition) {
if (collection.isEmpty()) return emptyList();
final List<T> result = new SmartList<T>();
@@ -839,16 +931,19 @@ public class ContainerUtil extends ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> List<T> skipNulls(@NotNull Collection<? extends T> collection) {
return findAll(collection, Condition.NOT_NULL);
}
@NotNull
+ @Contract(pure=true)
public static <T, V> List<V> findAll(@NotNull T[] collection, @NotNull Class<V> instanceOf) {
return findAll(Arrays.asList(collection), instanceOf);
}
@NotNull
+ @Contract(pure=true)
public static <T, V> V[] findAllAsArray(@NotNull T[] collection, @NotNull Class<V> instanceOf) {
List<V> list = findAll(Arrays.asList(collection), instanceOf);
@SuppressWarnings("unchecked") V[] array = (V[])Array.newInstance(instanceOf, list.size());
@@ -856,6 +951,7 @@ public class ContainerUtil extends ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T, V> V[] findAllAsArray(@NotNull Collection<? extends T> collection, @NotNull Class<V> instanceOf) {
List<V> list = findAll(collection, instanceOf);
@SuppressWarnings("unchecked") V[] array = (V[])Array.newInstance(instanceOf, list.size());
@@ -863,6 +959,7 @@ public class ContainerUtil extends ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> T[] findAllAsArray(@NotNull T[] collection, @NotNull Condition<? super T> instanceOf) {
List<T> list = findAll(collection, instanceOf);
@SuppressWarnings("unchecked") T[] array = (T[])Array.newInstance(collection.getClass().getComponentType(), list.size());
@@ -870,6 +967,7 @@ public class ContainerUtil extends ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T, V> List<V> findAll(@NotNull Collection<? extends T> collection, @NotNull Class<V> instanceOf) {
final List<V> result = new SmartList<V>();
for (final T t : collection) {
@@ -895,6 +993,7 @@ public class ContainerUtil extends ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static Map<String, String> stringMap(@NotNull final String... keyValues) {
final Map<String, String> result = newHashMap();
for (int i = 0; i < keyValues.length - 1; i+=2) {
@@ -905,11 +1004,13 @@ public class ContainerUtil extends ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> Iterator<T> iterate(@NotNull T[] arrays) {
return Arrays.asList(arrays).iterator();
}
@NotNull
+ @Contract(pure=true)
public static <T> Iterator<T> iterate(@NotNull final Enumeration<T> enumeration) {
return new Iterator<T>() {
@Override
@@ -930,11 +1031,13 @@ public class ContainerUtil extends ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> Iterable<T> iterate(@NotNull T[] arrays, @NotNull Condition<? super T> condition) {
return iterate(Arrays.asList(arrays), condition);
}
@NotNull
+ @Contract(pure=true)
public static <T> Iterable<T> iterate(@NotNull final Collection<? extends T> collection, @NotNull final Condition<? super T> condition) {
if (collection.isEmpty()) return emptyIterable();
return new Iterable<T>() {
@@ -977,6 +1080,7 @@ public class ContainerUtil extends ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> Iterable<T> iterateBackward(@NotNull final List<? extends T> list) {
return new Iterable<T>() {
@Override
@@ -1068,6 +1172,7 @@ public class ContainerUtil extends ContainerUtilRt {
return modified;
}
+ @Contract(pure=true)
public static <T, U extends T> U findInstance(@NotNull Iterable<T> iterable, @NotNull Class<U> aClass) {
return findInstance(iterable.iterator(), aClass);
}
@@ -1079,11 +1184,13 @@ public class ContainerUtil extends ContainerUtilRt {
}
@Nullable
+ @Contract(pure=true)
public static <T, U extends T> U findInstance(@NotNull T[] array, @NotNull Class<U> aClass) {
return findInstance(Arrays.asList(array), aClass);
}
@NotNull
+ @Contract(pure=true)
public static <T, V> List<T> concat(@NotNull V[] array, @NotNull Function<V, Collection<? extends T>> fun) {
return concat(Arrays.asList(array), fun);
}
@@ -1092,6 +1199,7 @@ public class ContainerUtil extends ContainerUtilRt {
* @return read-only list consisting of the elements from the collections stored in list added together
*/
@NotNull
+ @Contract(pure=true)
public static <T> List<T> concat(@NotNull Iterable<? extends Collection<T>> list) {
List<T> result = new ArrayList<T>();
for (final Collection<T> ts : list) {
@@ -1105,6 +1213,7 @@ public class ContainerUtil extends ContainerUtilRt {
* @return read-only list consisting of the elements from specified list with some additional values
*/
@NotNull
+ @Contract(pure=true)
public static <T> List<T> concat(boolean appendTail, @NotNull List<? extends T> list, T... values) {
return appendTail ? concat(list, list(values)) : concat(list(values), list);
}
@@ -1113,6 +1222,7 @@ public class ContainerUtil extends ContainerUtilRt {
* @return read-only list consisting of the two lists added together
*/
@NotNull
+ @Contract(pure=true)
public static <T> List<T> concat(@NotNull final List<? extends T> list1, @NotNull final List<? extends T> list2) {
if (list1.isEmpty() && list2.isEmpty()) {
return Collections.emptyList();
@@ -1139,6 +1249,7 @@ public class ContainerUtil extends ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> Iterable<T> concat(@NotNull final Iterable<? extends T>... iterables) {
return new Iterable<T>() {
@Override
@@ -1155,16 +1266,19 @@ public class ContainerUtil extends ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> Iterator<T> concatIterators(@NotNull Iterator<T>... iterators) {
return new SequenceIterator<T>(iterators);
}
@NotNull
+ @Contract(pure=true)
public static <T> Iterator<T> concatIterators(@NotNull Collection<Iterator<T>> iterators) {
return new SequenceIterator<T>(iterators);
}
@NotNull
+ @Contract(pure=true)
public static <T> Iterable<T> concat(@NotNull final T[]... iterables) {
return new Iterable<T>() {
@Override
@@ -1184,6 +1298,7 @@ public class ContainerUtil extends ContainerUtilRt {
* @return read-only list consisting of the lists added together
*/
@NotNull
+ @Contract(pure=true)
public static <T> List<T> concat(@NotNull final List<? extends T>... lists) {
int size = 0;
for (List<? extends T> each : lists) {
@@ -1215,6 +1330,7 @@ public class ContainerUtil extends ContainerUtilRt {
* @return read-only list consisting of the lists added together
*/
@NotNull
+ @Contract(pure=true)
public static <T> List<T> concat(@NotNull final List<List<? extends T>> lists) {
@SuppressWarnings("unchecked") List<? extends T>[] array = lists.toArray(new List[lists.size()]);
return concat(array);
@@ -1224,6 +1340,7 @@ public class ContainerUtil extends ContainerUtilRt {
* @return read-only list consisting of the lists (made by listGenerator) added together
*/
@NotNull
+ @Contract(pure=true)
public static <T, V> List<T> concat(@NotNull Iterable<? extends V> list, @NotNull Function<V, Collection<? extends T>> listGenerator) {
List<T> result = new ArrayList<T>();
for (final V v : list) {
@@ -1232,6 +1349,7 @@ public class ContainerUtil extends ContainerUtilRt {
return result.isEmpty() ? ContainerUtil.<T>emptyList() : result;
}
+ @Contract(pure=true)
public static <T> boolean intersects(@NotNull Collection<? extends T> collection1, @NotNull Collection<? extends T> collection2) {
for (T t : collection1) {
//noinspection SuspiciousMethodCalls
@@ -1246,6 +1364,7 @@ public class ContainerUtil extends ContainerUtilRt {
* @return read-only collection consisting of elements from both collections
*/
@NotNull
+ @Contract(pure=true)
public static <T> Collection<T> intersection(@NotNull Collection<? extends T> collection1, @NotNull Collection<? extends T> collection2) {
List<T> result = new ArrayList<T>();
for (T t : collection1) {
@@ -1257,15 +1376,18 @@ public class ContainerUtil extends ContainerUtilRt {
}
@Nullable
+ @Contract(pure=true)
public static <T> T getFirstItem(@Nullable Collection<T> items) {
return getFirstItem(items, null);
}
@Nullable
+ @Contract(pure=true)
public static <T> T getFirstItem(@Nullable List<T> items) {
return items == null || items.isEmpty() ? null : items.get(0);
}
+ @Contract(pure=true)
public static <T> T getFirstItem(@Nullable final Collection<T> items, @Nullable final T def) {
return items == null || items.isEmpty() ? def : items.iterator().next();
}
@@ -1280,11 +1402,13 @@ public class ContainerUtil extends ContainerUtilRt {
* @return new list with no more than <code>maxItems</code> first elements
*/
@NotNull
+ @Contract(pure=true)
public static <T> List<T> getFirstItems(@NotNull final List<T> items, int maxItems) {
return items.subList(0, Math.min(maxItems, items.size()));
}
@Nullable
+ @Contract(pure=true)
public static <T> T iterateAndGetLastItem(@NotNull Iterable<T> items) {
Iterator<T> itr = items.iterator();
T res = null;
@@ -1296,11 +1420,13 @@ public class ContainerUtil extends ContainerUtilRt {
}
@Nullable
+ @Contract(pure=true)
public static <T, L extends List<T>> T getLastItem(@NotNull L list, @Nullable T def) {
return list.isEmpty() ? def : list.get(list.size() - 1);
}
@Nullable
+ @Contract(pure=true)
public static <T, L extends List<T>> T getLastItem(@NotNull L list) {
return getLastItem(list, null);
}
@@ -1309,6 +1435,7 @@ public class ContainerUtil extends ContainerUtilRt {
* @return read-only collection consisting of elements from the 'from' collection which are absent from the 'what' collection
*/
@NotNull
+ @Contract(pure=true)
public static <T> Collection<T> subtract(@NotNull Collection<T> from, @NotNull Collection<T> what) {
final Set<T> set = newHashSet(from);
set.removeAll(what);
@@ -1316,16 +1443,19 @@ public class ContainerUtil extends ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> T[] toArray(@Nullable Collection<T> c, @NotNull ArrayFactory<T> factory) {
return c != null ? c.toArray(factory.create(c.size())) : factory.create(0);
}
@NotNull
+ @Contract(pure=true)
public static <T> T[] toArray(@NotNull Collection<? extends T> c1, @NotNull Collection<? extends T> c2, @NotNull ArrayFactory<T> factory) {
return ArrayUtil.mergeCollections(c1, c2, factory);
}
@NotNull
+ @Contract(pure=true)
public static <T> T[] mergeCollectionsToArray(@NotNull Collection<? extends T> c1, @NotNull Collection<? extends T> c2, @NotNull ArrayFactory<T> factory) {
return ArrayUtil.mergeCollections(c1, c2, factory);
}
@@ -1424,6 +1554,7 @@ public class ContainerUtil extends ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> List<T> sorted(@NotNull Collection<T> list, @NotNull Comparator<T> comparator) {
List<T> sorted = newArrayList(list);
sort(sorted, comparator);
@@ -1431,6 +1562,7 @@ public class ContainerUtil extends ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T extends Comparable<T>> List<T> sorted(@NotNull Collection<T> list) {
return sorted(list, new Comparator<T>() {
@Override
@@ -1475,6 +1607,7 @@ public class ContainerUtil extends ContainerUtilRt {
* @return read-only list consisting of the elements from the iterable converted by mapping
*/
@NotNull
+ @Contract(pure=true)
public static <T,V> List<V> map(@NotNull Iterable<? extends T> iterable, @NotNull Function<T, V> mapping) {
List<V> result = new ArrayList<V>();
for (T t : iterable) {
@@ -1487,6 +1620,7 @@ public class ContainerUtil extends ContainerUtilRt {
* @return read-only list consisting of the elements from the iterable converted by mapping
*/
@NotNull
+ @Contract(pure=true)
public static <T,V> List<V> map(@NotNull Collection<? extends T> iterable, @NotNull Function<T, V> mapping) {
if (iterable.isEmpty()) return emptyList();
List<V> result = new ArrayList<V>(iterable.size());
@@ -1500,6 +1634,7 @@ public class ContainerUtil extends ContainerUtilRt {
* @return read-only list consisting of the elements from the array converted by mapping with nulls filtered out
*/
@NotNull
+ @Contract(pure=true)
public static <T, V> List<V> mapNotNull(@NotNull T[] array, @NotNull Function<T, V> mapping) {
return mapNotNull(Arrays.asList(array), mapping);
}
@@ -1508,6 +1643,7 @@ public class ContainerUtil extends ContainerUtilRt {
* @return read-only list consisting of the elements from the array converted by mapping with nulls filtered out
*/
@NotNull
+ @Contract(pure=true)
public static <T, V> V[] mapNotNull(@NotNull T[] array, @NotNull Function<T, V> mapping, @NotNull V[] emptyArray) {
List<V> result = new ArrayList<V>(array.length);
for (T t : array) {
@@ -1527,6 +1663,7 @@ public class ContainerUtil extends ContainerUtilRt {
* @return read-only list consisting of the elements from the iterable converted by mapping with nulls filtered out
*/
@NotNull
+ @Contract(pure=true)
public static <T, V> List<V> mapNotNull(@NotNull Iterable<? extends T> iterable, @NotNull Function<T, V> mapping) {
List<V> result = new ArrayList<V>();
for (T t : iterable) {
@@ -1542,6 +1679,7 @@ public class ContainerUtil extends ContainerUtilRt {
* @return read-only list consisting of the elements from the array converted by mapping with nulls filtered out
*/
@NotNull
+ @Contract(pure=true)
public static <T, V> List<V> mapNotNull(@NotNull Collection<? extends T> iterable, @NotNull Function<T, V> mapping) {
if (iterable.isEmpty()) {
return emptyList();
@@ -1561,6 +1699,7 @@ public class ContainerUtil extends ContainerUtilRt {
* @return read-only list consisting of the elements with nulls filtered out
*/
@NotNull
+ @Contract(pure=true)
public static <T> List<T> packNullables(@NotNull T... elements) {
List<T> list = new ArrayList<T>();
for (T element : elements) {
@@ -1573,6 +1712,7 @@ public class ContainerUtil extends ContainerUtilRt {
* @return read-only list consisting of the elements from the array converted by mapping
*/
@NotNull
+ @Contract(pure=true)
public static <T, V> List<V> map(@NotNull T[] array, @NotNull Function<T, V> mapping) {
List<V> result = new ArrayList<V>(array.length);
for (T t : array) {
@@ -1582,6 +1722,7 @@ public class ContainerUtil extends ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T, V> V[] map(@NotNull T[] arr, @NotNull Function<T, V> mapping, @NotNull V[] emptyArray) {
if (arr.length==0) {
assert emptyArray.length == 0 : "You must pass an empty array";
@@ -1596,6 +1737,7 @@ public class ContainerUtil extends ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> Set<T> set(@NotNull T ... items) {
return newHashSet(items);
}
@@ -1618,11 +1760,13 @@ public class ContainerUtil extends ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> List<T> createMaybeSingletonList(@Nullable T element) {
return element == null ? ContainerUtil.<T>emptyList() : Collections.singletonList(element);
}
@NotNull
+ @Contract(pure=true)
public static <T> Set<T> createMaybeSingletonSet(@Nullable T element) {
return element == null ? Collections.<T>emptySet() : Collections.singleton(element);
}
@@ -1645,15 +1789,18 @@ public class ContainerUtil extends ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T, V> V getOrElse(@NotNull Map<T, V> result, final T key, @NotNull V defValue) {
V value = result.get(key);
return value == null ? defValue : value;
}
+ @Contract(pure=true)
public static <T> boolean and(@NotNull T[] iterable, @NotNull Condition<T> condition) {
return and(Arrays.asList(iterable), condition);
}
+ @Contract(pure=true)
public static <T> boolean and(@NotNull Iterable<T> iterable, @NotNull Condition<T> condition) {
for (final T t : iterable) {
if (!condition.value(t)) return false;
@@ -1661,18 +1808,22 @@ public class ContainerUtil extends ContainerUtilRt {
return true;
}
+ @Contract(pure=true)
public static <T> boolean exists(@NotNull T[] iterable, @NotNull Condition<T> condition) {
return or(Arrays.asList(iterable), condition);
}
+ @Contract(pure=true)
public static <T> boolean exists(@NotNull Iterable<T> iterable, @NotNull Condition<T> condition) {
return or(iterable, condition);
}
+ @Contract(pure=true)
public static <T> boolean or(@NotNull T[] iterable, @NotNull Condition<T> condition) {
return or(Arrays.asList(iterable), condition);
}
+ @Contract(pure=true)
public static <T> boolean or(@NotNull Iterable<T> iterable, @NotNull Condition<T> condition) {
for (final T t : iterable) {
if (condition.value(t)) return true;
@@ -1681,10 +1832,11 @@ public class ContainerUtil extends ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> List<T> unfold(@Nullable T t, @NotNull NullableFunction<T, T> next) {
if (t == null) return emptyList();
- final ArrayList<T> list = new ArrayList<T>();
+ List<T> list = new ArrayList<T>();
while (t != null) {
list.add(t);
t = next.fun(t);
@@ -1693,11 +1845,13 @@ public class ContainerUtil extends ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> List<T> dropTail(@NotNull List<T> items) {
return items.subList(0, items.size() - 1);
}
@NotNull
+ @Contract(pure=true)
public static <T> List<T> list(@NotNull T... items) {
return Arrays.asList(items);
}
@@ -1845,6 +1999,7 @@ public class ContainerUtil extends ContainerUtilRt {
* @return read-only set consisting of the only element o
*/
@NotNull
+ @Contract(pure=true)
public static <T> Set<T> singleton(final T o, @NotNull final TObjectHashingStrategy<T> strategy) {
return new SingletonSet<T>(o, strategy);
}
@@ -1853,6 +2008,7 @@ public class ContainerUtil extends ContainerUtilRt {
* @return read-only list consisting of the elements from all of the collections
*/
@NotNull
+ @Contract(pure=true)
public static <E> List<E> flatten(@NotNull Collection<E>[] collections) {
return flatten(Arrays.asList(collections));
}
@@ -1861,6 +2017,7 @@ public class ContainerUtil extends ContainerUtilRt {
* @return read-only list consisting of the elements from all of the collections
*/
@NotNull
+ @Contract(pure=true)
public static <E> List<E> flatten(@NotNull Iterable<? extends Collection<E>> collections) {
List<E> result = new ArrayList<E>();
for (Collection<E> list : collections) {
@@ -1874,6 +2031,7 @@ public class ContainerUtil extends ContainerUtilRt {
* @return read-only list consisting of the elements from all of the collections
*/
@NotNull
+ @Contract(pure=true)
public static <E> List<E> flattenIterables(@NotNull Iterable<? extends Iterable<E>> collections) {
List<E> result = new ArrayList<E>();
for (Iterable<E> list : collections) {
@@ -1885,6 +2043,7 @@ public class ContainerUtil extends ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <K,V> V[] convert(@NotNull K[] from, @NotNull V[] to, @NotNull Function<K,V> fun) {
if (to.length < from.length) {
@SuppressWarnings("unchecked") V[] array = (V[])Array.newInstance(to.getClass().getComponentType(), from.length);
@@ -1896,6 +2055,7 @@ public class ContainerUtil extends ContainerUtilRt {
return to;
}
+ @Contract(pure=true)
public static <T> boolean containsIdentity(@NotNull Iterable<T> list, T element) {
for (T t : list) {
if (t == element) {
@@ -1905,6 +2065,7 @@ public class ContainerUtil extends ContainerUtilRt {
return false;
}
+ @Contract(pure=true)
public static <T> int indexOfIdentity(@NotNull List<T> list, T element) {
for (int i = 0, listSize = list.size(); i < listSize; i++) {
if (list.get(i) == element) {
@@ -1914,6 +2075,7 @@ public class ContainerUtil extends ContainerUtilRt {
return -1;
}
+ @Contract(pure=true)
public static <T> boolean equalsIdentity(@NotNull List<T> list1, @NotNull List<T> list2) {
int listSize = list1.size();
if (list2.size() != listSize) {
@@ -1928,6 +2090,7 @@ public class ContainerUtil extends ContainerUtilRt {
return true;
}
+ @Contract(pure=true)
public static <T> int indexOf(@NotNull List<T> list, @NotNull Condition<T> condition) {
for (int i = 0, listSize = list.size(); i < listSize; i++) {
T t = list.get(i);
@@ -1938,6 +2101,7 @@ public class ContainerUtil extends ContainerUtilRt {
return -1;
}
+ @Contract(pure=true)
public static <T> int indexOf(@NotNull List<T> list, @NotNull final T object) {
return indexOf(list, new Condition<T>() {
@Override
@@ -1948,6 +2112,7 @@ public class ContainerUtil extends ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <A,B> Map<B,A> reverseMap(@NotNull Map<A,B> map) {
final Map<B,A> result = newHashMap();
for (Map.Entry<A, B> entry : map.entrySet()) {
@@ -1956,6 +2121,7 @@ public class ContainerUtil extends ContainerUtilRt {
return result;
}
+ @Contract(pure=true)
public static <T> boolean processRecursively(final T root, @NotNull PairProcessor<T, List<T>> processor) {
final LinkedList<T> list = new LinkedList<T>();
list.add(root);
@@ -1979,26 +2145,31 @@ public class ContainerUtil extends ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> Stack<T> newStack() {
return ContainerUtilRt.newStack();
}
@NotNull
+ @Contract(pure=true)
public static <T> Stack<T> newStack(@NotNull Collection<T> initial) {
return ContainerUtilRt.newStack(initial);
}
@NotNull
+ @Contract(pure=true)
public static <T> Stack<T> newStack(@NotNull T... initial) {
return ContainerUtilRt.newStack(initial);
}
@NotNull
+ @Contract(pure=true)
public static <T> List<T> emptyList() {
return ContainerUtilRt.emptyList();
}
@NotNull
+ @Contract(pure=true)
public static <T> CopyOnWriteArrayList<T> createEmptyCOWList() {
return ContainerUtilRt.createEmptyCOWList();
}
@@ -2011,16 +2182,19 @@ public class ContainerUtil extends ContainerUtilRt {
* - slower modification in highly contented case (which is the kind of situation you shouldn't use COWAL anyway)
*/
@NotNull
+ @Contract(pure=true)
public static <T> List<T> createLockFreeCopyOnWriteList() {
return createConcurrentList();
}
@NotNull
+ @Contract(pure=true)
public static <T> List<T> createLockFreeCopyOnWriteList(@NotNull Collection<? extends T> c) {
return new LockFreeCopyOnWriteArrayList<T>(c);
}
@NotNull
+ @Contract(pure=true)
public static <T> ConcurrentList<T> createConcurrentList() {
return new LockFreeCopyOnWriteArrayList<T>();
}
@@ -2034,31 +2208,37 @@ public class ContainerUtil extends ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T, V> List<V> map2List(@NotNull T[] array, @NotNull Function<T, V> mapper) {
return ContainerUtilRt.map2List(array, mapper);
}
@NotNull
+ @Contract(pure=true)
public static <T, V> List<V> map2List(@NotNull Collection<? extends T> collection, @NotNull Function<T, V> mapper) {
return ContainerUtilRt.map2List(collection, mapper);
}
@NotNull
+ @Contract(pure=true)
public static <T, V> Set<V> map2Set(@NotNull T[] collection, @NotNull Function<T, V> mapper) {
return ContainerUtilRt.map2Set(collection, mapper);
}
@NotNull
+ @Contract(pure=true)
public static <T, V> Set<V> map2Set(@NotNull Collection<? extends T> collection, @NotNull Function<T, V> mapper) {
return ContainerUtilRt.map2Set(collection, mapper);
}
@NotNull
+ @Contract(pure=true)
public static <T> T[] toArray(@NotNull List<T> collection, @NotNull T[] array) {
return ContainerUtilRt.toArray(collection, array);
}
@NotNull
+ @Contract(pure=true)
public static <T> T[] toArray(@NotNull Collection<T> c, @NotNull T[] sample) {
return ContainerUtilRt.toArray(c, sample);
}
@@ -2075,6 +2255,7 @@ public class ContainerUtil extends ContainerUtilRt {
}
@NotNull
+ @Contract(pure=true)
public static <T> Collection<T> toCollection(@NotNull Iterable<T> iterable) {
return iterable instanceof Collection ? (Collection<T>)iterable : newArrayList(iterable);
}
@@ -2092,18 +2273,26 @@ public class ContainerUtil extends ContainerUtilRt {
return result;
}
- @Contract("null -> true")
+ @Contract(value = "null -> true", pure = true)
public static <T> boolean isEmpty(Collection<T> collection) {
return collection == null || collection.isEmpty();
}
@NotNull
- public static <T, C extends Collection<T>> C notNullize(@Nullable C collection) {
+ @Contract(pure=true)
+ public static <T> List<T> notNullize(@Nullable List<T> list) {
+ return list == null ? ContainerUtilRt.<T>emptyList() : list;
+ }
+
+ @NotNull
+ @Contract(pure=true)
+ public static <T> Set<T> notNullize(@Nullable Set<T> set) {
//noinspection unchecked
- return collection == null ? (C)ContainerUtilRt.emptyList() : collection;
+ return set == null ? Collections.<T>emptySet() : set;
}
@Nullable
+ @Contract(pure=true)
public static <T, C extends Collection<T>> C nullize(@Nullable C collection) {
return isEmpty(collection) ? null : collection;
}
@@ -2117,26 +2306,31 @@ public class ContainerUtil extends ContainerUtilRt {
}
private static final ConcurrentMapFactory V8_MAP_FACTORY = new ConcurrentMapFactory() {
+ @Override
@NotNull
public <T, V> ConcurrentMap<T, V> createMap() {
return new ConcurrentHashMap<T,V>();
}
+ @Override
@NotNull
public <T, V> ConcurrentMap<T, V> createMap(int initialCapacity) {
return new ConcurrentHashMap<T,V>(initialCapacity);
}
+ @Override
@NotNull
public <T, V> ConcurrentMap<T, V> createMap(@NotNull TObjectHashingStrategy<T> hashStrategy) {
return new ConcurrentHashMap<T,V>(hashStrategy);
}
+ @Override
@NotNull
public <T, V> ConcurrentMap<T, V> createMap(int initialCapacity, float loadFactor, int concurrencyLevel) {
return new ConcurrentHashMap<T,V>(initialCapacity, loadFactor, concurrencyLevel);
}
+ @Override
@NotNull
public <T, V> ConcurrentMap<T, V> createMap(int initialCapacity, float loadFactor, int concurrencyLevel, @NotNull TObjectHashingStrategy<T> hashingStrategy) {
return new ConcurrentHashMap<T,V>(initialCapacity, loadFactor, concurrencyLevel, hashingStrategy);
@@ -2144,16 +2338,19 @@ public class ContainerUtil extends ContainerUtilRt {
};
private static final ConcurrentMapFactory PLATFORM_MAP_FACTORY = new ConcurrentMapFactory() {
+ @Override
@NotNull
public <T, V> ConcurrentMap<T, V> createMap() {
return createMap(16, 0.75f, DEFAULT_CONCURRENCY_LEVEL);
}
+ @Override
@NotNull
public <T, V> ConcurrentMap<T, V> createMap(int initialCapacity) {
return new java.util.concurrent.ConcurrentHashMap<T,V>(initialCapacity);
}
+ @Override
@NotNull
public <T, V> ConcurrentMap<T, V> createMap(@NotNull TObjectHashingStrategy<T> hashingStrategy) {
if (hashingStrategy != canonicalStrategy()) {
@@ -2163,11 +2360,13 @@ public class ContainerUtil extends ContainerUtilRt {
return createMap();
}
+ @Override
@NotNull
public <T, V> ConcurrentMap<T, V> createMap(int initialCapacity, float loadFactor, int concurrencyLevel) {
return new java.util.concurrent.ConcurrentHashMap<T,V>(initialCapacity, loadFactor, concurrencyLevel);
}
+ @Override
@NotNull
public <T, V> ConcurrentMap<T, V> createMap(int initialCapacity, float loadFactor, int concurrencyLevel, @NotNull TObjectHashingStrategy<T> hashingStrategy) {
if (hashingStrategy != canonicalStrategy()) {
@@ -2185,7 +2384,8 @@ public class ContainerUtil extends ContainerUtilRt {
return StringUtil.compareVersionNumbers(SystemInfo.JAVA_VERSION, "1.7") >= 0;
}
- public static <T extends Comparable<T>> int compareLexicographically(List<T> o1, List<T> o2) {
+ @Contract(pure=true)
+ public static <T extends Comparable<T>> int compareLexicographically(@NotNull List<T> o1, @NotNull List<T> o2) {
for (int i = 0; i < Math.min(o1.size(), o2.size()); i++) {
int result = o1.get(i).compareTo(o2.get(i));
if (result != 0) {
@@ -2194,5 +2394,16 @@ public class ContainerUtil extends ContainerUtilRt {
}
return o1.size() < o2.size() ? -1 : o1.size() == o2.size() ? 0 : 1;
}
+
+ @Contract(pure=true)
+ public static <T> int compareLexicographically(@NotNull List<T> o1, @NotNull List<T> o2, @NotNull Comparator<T> comparator) {
+ for (int i = 0; i < Math.min(o1.size(), o2.size()); i++) {
+ int result = comparator.compare(o1.get(i), o2.get(i));
+ if (result != 0) {
+ return result;
+ }
+ }
+ return o1.size() < o2.size() ? -1 : o1.size() == o2.size() ? 0 : 1;
+ }
}
diff --git a/platform/util/src/com/intellij/util/containers/FactoryMap.java b/platform/util/src/com/intellij/util/containers/FactoryMap.java
index 30684d0e6dfa..3eea4d3dd984 100644
--- a/platform/util/src/com/intellij/util/containers/FactoryMap.java
+++ b/platform/util/src/com/intellij/util/containers/FactoryMap.java
@@ -15,6 +15,7 @@
*/
package com.intellij.util.containers;
+import com.intellij.util.ObjectUtils;
import gnu.trove.THashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -92,7 +93,7 @@ public abstract class FactoryMap<K,V> implements Map<K, V> {
public Collection<V> notNullValues() {
if (myMap == null) return Collections.emptyList();
- final Collection<V> values = new ArrayList<V>(myMap.values());
+ final Collection<V> values = ContainerUtil.newArrayList(myMap.values());
for (Iterator<V> iterator = values.iterator(); iterator.hasNext();) {
if (iterator.next() == NULL) {
iterator.remove();
@@ -101,6 +102,13 @@ public abstract class FactoryMap<K,V> implements Map<K, V> {
return values;
}
+ public boolean removeValue(Object value) {
+ if (myMap == null) return false;
+ Object t = ObjectUtils.notNull(value, NULL);
+ return myMap.values().remove(t);
+ }
+
+
@Override
public void clear() {
if (myMap != null) {
diff --git a/platform/util/src/com/intellij/util/containers/TransferToEDTQueue.java b/platform/util/src/com/intellij/util/containers/TransferToEDTQueue.java
index 5db4de22b401..425947ba50cb 100644
--- a/platform/util/src/com/intellij/util/containers/TransferToEDTQueue.java
+++ b/platform/util/src/com/intellij/util/containers/TransferToEDTQueue.java
@@ -16,6 +16,7 @@
package com.intellij.util.containers;
import com.intellij.openapi.util.Condition;
+import com.intellij.openapi.util.Conditions;
import com.intellij.util.Processor;
import com.intellij.util.concurrency.Semaphore;
import gnu.trove.Equality;
@@ -80,7 +81,7 @@ public class TransferToEDTQueue<T> {
runnable.run();
return true;
}
- }, Condition.FALSE, maxUnitOfWorkThresholdMs);
+ }, Conditions.alwaysFalse(), maxUnitOfWorkThresholdMs);
}
private boolean isEmpty() {
diff --git a/platform/util/src/com/intellij/util/io/AppendableStorageBackedByResizableMappedFile.java b/platform/util/src/com/intellij/util/io/AppendableStorageBackedByResizableMappedFile.java
index c4381da1a406..1c43b652b02b 100644
--- a/platform/util/src/com/intellij/util/io/AppendableStorageBackedByResizableMappedFile.java
+++ b/platform/util/src/com/intellij/util/io/AppendableStorageBackedByResizableMappedFile.java
@@ -72,8 +72,7 @@ public class AppendableStorageBackedByResizableMappedFile extends ResizeableMapp
}
public <Data> boolean processAll(Processor<Data> processor, KeyDescriptor<Data> descriptor) throws IOException {
- force();
-
+ assert !isDirty();
DataInputStream keysStream = new DataInputStream(new BufferedInputStream(new LimitedInputStream(new FileInputStream(getPagedFileStorage().getFile()),
myFileLength) {
@Override
diff --git a/platform/util/src/com/intellij/util/io/PersistentEnumeratorBase.java b/platform/util/src/com/intellij/util/io/PersistentEnumeratorBase.java
index 9f879f67d99d..eb7cdef28d69 100644
--- a/platform/util/src/com/intellij/util/io/PersistentEnumeratorBase.java
+++ b/platform/util/src/com/intellij/util/io/PersistentEnumeratorBase.java
@@ -443,11 +443,13 @@ public abstract class PersistentEnumeratorBase<Data> implements Forceable, Close
lockStorage(); // todo locking in key storage
try {
- return myKeyStorage.processAll(processor, myDataDescriptor);
+ myKeyStorage.force();
}
finally {
unlockStorage();
}
+
+ return myKeyStorage.processAll(processor, myDataDescriptor);
}
private File keystreamFile() {
diff --git a/platform/util/src/com/intellij/util/messages/impl/MessageListenerList.java b/platform/util/src/com/intellij/util/messages/impl/MessageListenerList.java
index d054416846a1..6d7bf76ccde7 100644
--- a/platform/util/src/com/intellij/util/messages/impl/MessageListenerList.java
+++ b/platform/util/src/com/intellij/util/messages/impl/MessageListenerList.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,14 +15,14 @@
*/
package com.intellij.util.messages.impl;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.util.containers.ConcurrentHashMap;
import com.intellij.util.messages.MessageBus;
import com.intellij.util.messages.MessageBusConnection;
import com.intellij.util.messages.Topic;
-import com.intellij.openapi.Disposable;
-import com.intellij.openapi.util.Disposer;
import org.jetbrains.annotations.NotNull;
-import java.util.HashMap;
import java.util.Map;
/**
@@ -31,7 +31,7 @@ import java.util.Map;
public class MessageListenerList<T> {
private final MessageBus myMessageBus;
private final Topic<T> myTopic;
- private final Map<T, MessageBusConnection> myListenerToConnectionMap = new HashMap<T, MessageBusConnection>();
+ private final Map<T, MessageBusConnection> myListenerToConnectionMap = new ConcurrentHashMap<T, MessageBusConnection>();
public MessageListenerList(@NotNull MessageBus messageBus, @NotNull Topic<T> topic) {
myTopic = topic;
diff --git a/platform/util/src/com/intellij/util/ui/JBSwingUtilities.java b/platform/util/src/com/intellij/util/ui/JBSwingUtilities.java
new file mode 100644
index 000000000000..d48aa5fc4ad2
--- /dev/null
+++ b/platform/util/src/com/intellij/util/ui/JBSwingUtilities.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.util.ui;
+
+import java.awt.event.InputEvent;
+import java.awt.event.MouseEvent;
+
+/**
+ * @author gregsh
+ */
+public class JBSwingUtilities {
+ /**
+ * Replaces SwingUtilities#isLeftMouseButton() for consistency with other button-related methods
+ *
+ * @see javax.swing.SwingUtilities#isLeftMouseButton(java.awt.event.MouseEvent)
+ */
+ public static boolean isLeftMouseButton(MouseEvent anEvent) {
+ return (anEvent.getModifiersEx() & InputEvent.BUTTON1_DOWN_MASK) > 0;
+ }
+
+ /**
+ * Replaces SwingUtilities#isMiddleMouseButton() due to the fact that BUTTON2_MASK == Event.ALT_MASK
+ *
+ * @see javax.swing.SwingUtilities#isMiddleMouseButton(java.awt.event.MouseEvent)
+ * @see java.awt.event.InputEvent#BUTTON2_MASK
+ */
+ public static boolean isMiddleMouseButton(MouseEvent anEvent) {
+ return (anEvent.getModifiersEx() & InputEvent.BUTTON2_DOWN_MASK) > 0;
+ }
+
+ /**
+ * Replaces SwingUtilities#isRightMouseButton() due to the fact that BUTTON3_MASK == Event.META_MASK
+ *
+ * @see javax.swing.SwingUtilities#isRightMouseButton(java.awt.event.MouseEvent)
+ * @see java.awt.event.InputEvent#BUTTON3_MASK
+ */
+ public static boolean isRightMouseButton(MouseEvent anEvent) {
+ return (anEvent.getModifiersEx() & InputEvent.BUTTON3_DOWN_MASK) > 0;
+ }
+}
diff --git a/platform/util/src/com/intellij/util/ui/UIUtil.java b/platform/util/src/com/intellij/util/ui/UIUtil.java
index aec2a356ded0..28c95b80763c 100644
--- a/platform/util/src/com/intellij/util/ui/UIUtil.java
+++ b/platform/util/src/com/intellij/util/ui/UIUtil.java
@@ -2085,7 +2085,7 @@ public class UIUtil {
* Invoke and wait in the event dispatch thread
* or in the current thread if the current thread
* is event queue thread.
- *
+ * DO NOT INVOKE THIS METHOD FROM UNDER READ ACTION.
* @param runnable a runnable to invoke
* @see #invokeAndWaitIfNeeded(com.intellij.util.ThrowableRunnable)
*/
@@ -2103,6 +2103,14 @@ public class UIUtil {
}
}
+ /**
+ * Invoke and wait in the event dispatch thread
+ * or in the current thread if the current thread
+ * is event queue thread.
+ * DO NOT INVOKE THIS METHOD FROM UNDER READ ACTION.
+ * @param computable a runnable to invoke
+ * @see #invokeAndWaitIfNeeded(com.intellij.util.ThrowableRunnable)
+ */
public static <T> T invokeAndWaitIfNeeded(@NotNull final Computable<T> computable) {
final Ref<T> result = Ref.create();
invokeAndWaitIfNeeded(new Runnable() {
@@ -2114,6 +2122,14 @@ public class UIUtil {
return result.get();
}
+ /**
+ * Invoke and wait in the event dispatch thread
+ * or in the current thread if the current thread
+ * is event queue thread.
+ * DO NOT INVOKE THIS METHOD FROM UNDER READ ACTION.
+ * @param runnable a runnable to invoke
+ * @see #invokeAndWaitIfNeeded(com.intellij.util.ThrowableRunnable)
+ */
public static void invokeAndWaitIfNeeded(@NotNull final ThrowableRunnable runnable) throws Throwable {
if (SwingUtilities.isEventDispatchThread()) {
runnable.run();
@@ -2890,6 +2906,7 @@ public class UIUtil {
new Thread(new Runnable() {
// The wrapper thread is unnecessary, unless it blocks on the
// Clip finishing; see comments.
+ @Override
public void run() {
try {
Clip clip = AudioSystem.getClip();
diff --git a/platform/util/src/com/intellij/util/ui/tree/WideSelectionTreeUI.java b/platform/util/src/com/intellij/util/ui/tree/WideSelectionTreeUI.java
index ba0eb265655e..9775ddb01be1 100644
--- a/platform/util/src/com/intellij/util/ui/tree/WideSelectionTreeUI.java
+++ b/platform/util/src/com/intellij/util/ui/tree/WideSelectionTreeUI.java
@@ -16,6 +16,7 @@
package com.intellij.util.ui.tree;
import com.intellij.openapi.util.Condition;
+import com.intellij.openapi.util.Conditions;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NonNls;
@@ -53,7 +54,7 @@ public class WideSelectionTreeUI extends BasicTreeUI {
@SuppressWarnings("unchecked")
public WideSelectionTreeUI() {
- this(true, Condition.TRUE);
+ this(true, Conditions.<Integer>alwaysTrue());
}
/**
diff --git a/platform/util/testSrc/com/intellij/execution/configurations/CommandLineTokenizerTest.java b/platform/util/testSrc/com/intellij/execution/configurations/CommandLineTokenizerTest.java
new file mode 100644
index 000000000000..276ca549eb30
--- /dev/null
+++ b/platform/util/testSrc/com/intellij/execution/configurations/CommandLineTokenizerTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.execution.configurations;
+
+import junit.framework.TestCase;
+
+public class CommandLineTokenizerTest extends TestCase {
+ public void testBasic() throws Exception {
+ assertTokens("a b", "a", "b");
+ assertTokens("\"a b\"", "a b");
+ assertTokens("a\" b\"", "a b");
+ assertTokens("\"a b", "a b");
+ assertTokens("a b\"", "a", "b");
+ assertTokens("a b\" c", "a", "b c");
+ assertTokens("\"a b\" c \"d e\"", "a b", "c", "d e");
+ }
+
+ public void testEscape() throws Exception {
+ assertTokens("a\\ b", true, "a b");
+ assertTokens("a\\ b", false, "a\\", "b");
+
+ assertTokens("\"a\\ b\"", true, "a\\ b");
+ assertTokens("\"a\\ b\"", false, "a\\ b");
+
+ assertTokens("a\\ ", true, "a ");
+ assertTokens("a\\ ", false, "a\\");
+
+ assertTokens("\\\"", "\"");
+ assertTokens("\"\\\" a \\\"\"", "\" a \"");
+ assertTokens("\\\"a b\\\"", "\"a", "b\"");
+ assertTokens("\\\"a\\ b\\\"", true, "\"a b\"");
+ assertTokens("\\\"a\\ b\\\"", false, "\"a\\", "b\"");
+ }
+
+ private static void assertTokens(String cmd, String... tokens) {
+ assertTokens(cmd, false, tokens);
+ }
+
+ private static void assertTokens(String cmd, boolean handleEscapedWhitespaces, String... tokens) {
+ CommandLineTokenizer tokenizer = new CommandLineTokenizer(cmd, handleEscapedWhitespaces);
+
+ assertEquals(tokens.length, tokenizer.countTokens());
+ for (String token : tokens) {
+ assertEquals(token, tokenizer.nextToken());
+ }
+ }
+}
diff --git a/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java b/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java
index d2f593d13ff1..93ebb038cae1 100644
--- a/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java
+++ b/platform/util/testSrc/com/intellij/util/text/StringUtilTest.java
@@ -111,7 +111,7 @@ public class StringUtilTest extends TestCase {
public void testFormatLinks() {
assertEquals("<a href=\"http://a-b+c\">http://a-b+c</a>", StringUtil.formatLinks("http://a-b+c"));
}
-
+
public void testCopyHeapCharBuffer() {
String s = "abcde";
CharBuffer buffer = CharBuffer.allocate(s.length());
@@ -124,7 +124,7 @@ public class StringUtilTest extends TestCase {
assertNull(CharArrayUtil.fromSequenceWithoutCopying(buffer.subSequence(1, 5)));
assertNull(CharArrayUtil.fromSequenceWithoutCopying(buffer.subSequence(1, 2)));
}
-
+
public void testTitleCase() {
assertEquals("Couldn't Connect to Debugger", StringUtil.wordsToBeginFromUpperCase("Couldn't connect to debugger"));
}
@@ -198,7 +198,7 @@ public class StringUtilTest extends TestCase {
assertEquals(Arrays.asList("aa"), Arrays.asList(StringUtil.splitByLinesKeepSeparators("aa")));
assertEquals(Arrays.asList("\n", "\n", "aa\n", "\n", "bb\n", "cc\n", "\n"),
Arrays.asList(StringUtil.splitByLinesKeepSeparators("\n\naa\n\nbb\ncc\n\n")));
-
+
assertEquals(Arrays.asList("\r", "\r\n", "\r"), Arrays.asList(StringUtil.splitByLinesKeepSeparators("\r\r\n\r")));
assertEquals(Arrays.asList("\r\n", "\r", "\r\n"), Arrays.asList(StringUtil.splitByLinesKeepSeparators("\r\n\r\r\n")));
@@ -224,4 +224,13 @@ public class StringUtilTest extends TestCase {
}
}
}
+
+ public void testReplaceReturnReplacementIfTextEqualsToReplacedText() {
+ String newS = "/tmp";
+ assertSame(StringUtil.replace("$PROJECT_FILE$", "$PROJECT_FILE$".toLowerCase().toUpperCase() /* ensure new String instance */, newS), newS);
+ }
+
+ public void testReplace() {
+ assertEquals(StringUtil.replace("$PROJECT_FILE$/filename", "$PROJECT_FILE$", "/tmp"), "/tmp/filename");
+ }
}
diff --git a/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/FrameDialogWrapper.java b/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/FrameDialogWrapper.java
new file mode 100644
index 000000000000..f89e28ea8b6b
--- /dev/null
+++ b/platform/vcs-impl/src/com/intellij/openapi/diff/impl/dir/FrameDialogWrapper.java
@@ -0,0 +1,135 @@
+package com.intellij.openapi.diff.impl.dir;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.openapi.ui.FrameWrapper;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+
+public abstract class FrameDialogWrapper {
+ public enum Mode {FRAME, MODAL, NON_MODAL}
+
+ @NotNull
+ protected abstract JComponent getPanel();
+
+ @Nullable
+ protected String getDimensionServiceKey() {
+ return null;
+ }
+
+ @Nullable
+ protected JComponent getPreferredFocusedComponent() {
+ return null;
+ }
+
+ @Nullable
+ protected String getTitle() {
+ return null;
+ }
+
+ @Nullable
+ protected Project getProject() {
+ return null;
+ }
+
+ @NotNull
+ protected Mode getMode() {
+ return Mode.MODAL;
+ }
+
+ public void show() {
+ switch (getMode()) {
+ case FRAME:
+ new MyFrameWrapper(getProject(), getMode(), getPanel(), getPreferredFocusedComponent(), getTitle(), getDimensionServiceKey())
+ .show();
+ return;
+ case MODAL:
+ case NON_MODAL:
+ new MyDialogWrapper(getProject(), getMode(), getPanel(), getPreferredFocusedComponent(), getTitle(), getDimensionServiceKey())
+ .show();
+ return;
+ default:
+ throw new IllegalArgumentException(getMode().toString());
+ }
+ }
+
+ private static class MyDialogWrapper extends DialogWrapper {
+ private final JComponent myComponent;
+ private final JComponent myPreferredFocusedComponent;
+ private final String myDimensionServiceKey;
+
+ public MyDialogWrapper(@Nullable Project project,
+ @NotNull Mode mode,
+ @NotNull JComponent component,
+ @Nullable JComponent preferredFocusedComponent,
+ @Nullable String title,
+ @Nullable String dimensionServiceKey) {
+ super(project, true);
+ myComponent = component;
+ myPreferredFocusedComponent = preferredFocusedComponent;
+ myDimensionServiceKey = dimensionServiceKey;
+
+ if (title != null) {
+ setTitle(title);
+ }
+ switch (mode) {
+ case MODAL:
+ setModal(true);
+ break;
+ case NON_MODAL:
+ setModal(false);
+ break;
+ default:
+ throw new IllegalArgumentException(mode.toString());
+ }
+
+ init();
+ }
+
+ @Override
+ protected JComponent createCenterPanel() {
+ return myComponent;
+ }
+
+ @Nullable
+ @Override
+ public JComponent getPreferredFocusedComponent() {
+ return myPreferredFocusedComponent;
+ }
+
+ @Nullable
+ @Override
+ protected String getDimensionServiceKey() {
+ return myDimensionServiceKey;
+ }
+
+ // it is information dialog - no need to OK or Cancel. Close the dialog by clicking the cross button or pressing Esc.
+ @NotNull
+ @Override
+ protected Action[] createActions() {
+ return new Action[0];
+ }
+ }
+
+ private static class MyFrameWrapper extends FrameWrapper {
+ public MyFrameWrapper(@Nullable Project project,
+ @NotNull Mode mode,
+ @NotNull JComponent component,
+ @Nullable JComponent preferredFocusedComponent,
+ @Nullable String title,
+ @Nullable String dimensionServiceKey) {
+ super(project, dimensionServiceKey);
+
+ assert mode == Mode.FRAME;
+
+ if (title != null) {
+ setTitle(title);
+ }
+ setComponent(component);
+ setPreferredFocusedComponent(preferredFocusedComponent);
+ closeOnEsc();
+ }
+ }
+}
diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateToggleAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateToggleAction.java
index 291289854fa7..a347531b2363 100644
--- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateToggleAction.java
+++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateToggleAction.java
@@ -205,6 +205,7 @@ public class AnnotateToggleAction extends ToggleAction implements DumbAware, Ann
handler.completed(file.getPath());
if (!exceptionRef.isNull()) {
+ LOG.warn(exceptionRef.get());
AbstractVcsHelper.getInstance(project).showErrors(Arrays.asList(exceptionRef.get()), VcsBundle.message("message.title.annotate"));
}
diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesFragmentedDiffPanel.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesFragmentedDiffPanel.java
index 53092e6a1369..6afbc181b98c 100644
--- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesFragmentedDiffPanel.java
+++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ChangesFragmentedDiffPanel.java
@@ -187,7 +187,7 @@ public class ChangesFragmentedDiffPanel implements Disposable {
current = range;
}
if (current == null) return null;
- final Fragment at = fragments.getFragmentAt(offset, FragmentSide.SIDE1, Condition.TRUE);
+ final Fragment at = fragments.getFragmentAt(offset, FragmentSide.SIDE1, Conditions.<Fragment>alwaysTrue());
if (at == null) return null;
final TextRange opposite = at.getRange(FragmentSide.SIDE2);
diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeManagerImpl.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeManagerImpl.java
index 6e44a7864b3d..0e38675a8239 100644
--- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeManagerImpl.java
+++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/VcsDirtyScopeManagerImpl.java
@@ -79,7 +79,11 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr
StartupManager.getInstance(myProject).registerPostStartupActivity(new DumbAwareRunnable() {
public void run() {
myLife.born();
- markEverythingDirty();
+ ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
+ public void run() {
+ markEverythingDirty();
+ }
+ });
}
});
}
diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/CommittedChangesCache.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/CommittedChangesCache.java
index 6619b98ea5e9..2708f5130040 100644
--- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/CommittedChangesCache.java
+++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/CommittedChangesCache.java
@@ -21,7 +21,10 @@ import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
-import com.intellij.openapi.components.*;
+import com.intellij.openapi.components.PersistentStateComponent;
+import com.intellij.openapi.components.State;
+import com.intellij.openapi.components.Storage;
+import com.intellij.openapi.components.StoragePathMacros;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.progress.ProgressManagerQueue;
@@ -64,12 +67,8 @@ import java.util.concurrent.TimeUnit;
* @author yole
*/
@State(
- name="CommittedChangesCache",
- roamingType = RoamingType.DISABLED,
- storages= {
- @Storage(
- file = StoragePathMacros.WORKSPACE_FILE
- )}
+ name = "CommittedChangesCache",
+ storages = {@Storage(file = StoragePathMacros.WORKSPACE_FILE)}
)
public class CommittedChangesCache implements PersistentStateComponent<CommittedChangesCache.State> {
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.changes.committed.CommittedChangesCache");
diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitChangeListDialog.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitChangeListDialog.java
index 497db3da7d9f..47fae2b88339 100644
--- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitChangeListDialog.java
+++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitChangeListDialog.java
@@ -175,6 +175,11 @@ public class CommitChangeListDialog extends DialogWrapper implements CheckinProj
ProjectLevelVcsManager.getInstance(project).getAllActiveVcss());
}
+ @NotNull
+ public List<RefreshableOnComponent> getAdditionalComponents() {
+ return Collections.unmodifiableList(myAdditionalComponents);
+ }
+
public static void commitPaths(final Project project, Collection<FilePath> paths, final LocalChangeList initialSelection,
@Nullable final CommitExecutor executor, final String comment) {
final ChangeListManager manager = ChangeListManager.getInstance(project);
diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/configurable/VcsManagerConfigurableProvider.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/configurable/VcsManagerConfigurableProvider.java
new file mode 100644
index 000000000000..0ff9ef6c96d6
--- /dev/null
+++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/configurable/VcsManagerConfigurableProvider.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.openapi.vcs.configurable;
+
+import com.intellij.openapi.options.Configurable;
+import com.intellij.openapi.options.ConfigurableProvider;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vcs.ProjectLevelVcsManager;
+import org.jetbrains.annotations.NotNull;
+
+public final class VcsManagerConfigurableProvider extends ConfigurableProvider {
+ private final Project myProject;
+
+ public VcsManagerConfigurableProvider(Project project) {
+ myProject = project;
+ }
+
+ @NotNull
+ @Override
+ public Configurable createConfigurable() {
+ return new VcsManagerConfigurable(myProject);
+ }
+
+ @Override
+ public boolean canCreateConfigurable() {
+ return ProjectLevelVcsManager.getInstance(myProject).getAllVcss().length > 0;
+ }
+}
diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java
index daef43857c4e..abc43dd3a34d 100644
--- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java
+++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/LineStatusTracker.java
@@ -295,6 +295,23 @@ public class LineStatusTracker {
}
}
+ private void markFileUnchanged() {
+ ApplicationManager.getApplication().invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ FileDocumentManager.getInstance().saveDocument(myDocument);
+ boolean stillEmpty;
+ synchronized (myLock) {
+ stillEmpty = myRanges.isEmpty();
+ }
+ if (stillEmpty) {
+ // file was modified, and now it's not -> dirty local change
+ myVcsDirtyScopeManager.fileDirty(myVirtualFile);
+ }
+ }
+ });
+ }
+
private class MyDocumentListener extends DocumentAdapter {
// We have 3 document versions:
// * VCS version
@@ -457,20 +474,7 @@ public class LineStatusTracker {
}
if (myRanges.isEmpty() && myVirtualFile != null) {
- ApplicationManager.getApplication().invokeLater(new Runnable() {
- @Override
- public void run() {
- FileDocumentManager.getInstance().saveDocument(myDocument);
- boolean stillEmpty;
- synchronized (myLock) {
- stillEmpty = myRanges.isEmpty();
- }
- if (stillEmpty) {
- // file was modified, and now it's not -> dirty local change
- myVcsDirtyScopeManager.fileDirty(myVirtualFile);
- }
- }
- });
+ markFileUnchanged();
}
}
}
@@ -764,15 +768,10 @@ public class LineStatusTracker {
}
}
- public void rollbackChanges(@NotNull BitSet lines) {
- myApplication.assertWriteAccessAllowed();
-
- synchronized (myLock) {
- if (myBulkUpdate) return;
-
- try {
- mySuppressUpdate = true;
-
+ public void rollbackChanges(@NotNull final BitSet lines) {
+ runBulkRollback(new Runnable() {
+ @Override
+ public void run() {
Range first = null;
Range last = null;
@@ -816,11 +815,41 @@ public class LineStatusTracker {
doUpdateRanges(beforeChangedLine1, beforeChangedLine2, shift, beforeTotalLines);
}
}
- catch (Throwable e) {
+ });
+ }
+
+ public void rollbackAllChanges() {
+ runBulkRollback(new Runnable() {
+ @Override
+ public void run() {
+ myDocument.setText(myVcsDocument.getText());
+
+ removeAnathema();
+ removeHighlightersFromMarkupModel();
+
+ markFileUnchanged();
+ }
+ });
+ }
+
+ private void runBulkRollback(@NotNull Runnable task) {
+ myApplication.assertWriteAccessAllowed();
+
+ synchronized (myLock) {
+ if (myBulkUpdate) return;
+
+ try {
+ mySuppressUpdate = true;
+
+ task.run();
+ }
+ catch (Error e) {
+ reinstallRanges();
+ throw e;
+ }
+ catch (RuntimeException e) {
reinstallRanges();
- if (e instanceof Error) throw ((Error)e);
- if (e instanceof RuntimeException) throw ((RuntimeException)e);
- throw new RuntimeException(e);
+ throw e;
}
finally {
mySuppressUpdate = false;
diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RollbackLineStatusAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RollbackLineStatusAction.java
index 1286b6815fcf..529da7371bf7 100644
--- a/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RollbackLineStatusAction.java
+++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/ex/RollbackLineStatusAction.java
@@ -12,8 +12,6 @@
*/
package com.intellij.openapi.vcs.ex;
-import com.intellij.icons.AllIcons;
-import com.intellij.idea.ActionsBundle;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.application.ApplicationManager;
@@ -73,6 +71,15 @@ public class RollbackLineStatusAction extends DumbAwareAction {
BitSet lines = new BitSet(totalLines + 1);
List<Caret> carets = editor.getCaretModel().getAllCarets();
+
+ if (carets.size() == 1) {
+ Caret caret = carets.get(0);
+ if (caret.getSelectionStart() == 0 && caret.getSelectionEnd() == document.getTextLength()) {
+ doRollback(tracker);
+ return;
+ }
+ }
+
for (Caret caret : carets) {
if (caret.hasSelection()) {
int line1 = editor.offsetToLogicalPosition(caret.getSelectionStart()).line;
@@ -107,6 +114,15 @@ public class RollbackLineStatusAction extends DumbAwareAction {
});
}
+ private static void doRollback(@NotNull final LineStatusTracker tracker) {
+ execute(tracker, new Runnable() {
+ @Override
+ public void run() {
+ tracker.rollbackAllChanges();
+ }
+ });
+ }
+
private static void execute(@NotNull final LineStatusTracker tracker, @NotNull final Runnable task) {
CommandProcessor.getInstance().executeCommand(tracker.getProject(), new Runnable() {
public void run() {
diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/VcsLogProvider.java b/platform/vcs-log/api/src/com/intellij/vcs/log/VcsLogProvider.java
index 89805947869c..d9c72314edbc 100644
--- a/platform/vcs-log/api/src/com/intellij/vcs/log/VcsLogProvider.java
+++ b/platform/vcs-log/api/src/com/intellij/vcs/log/VcsLogProvider.java
@@ -10,6 +10,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.List;
+import java.util.Set;
/**
* Provides the information needed to build the VCS log, such as the list of most recent commits with their parents.
@@ -17,20 +18,26 @@ import java.util.List;
public interface VcsLogProvider {
/**
- * Reads the most recent correctly ordered commits from the log. <br/>
- * Commits should be at least topologically ordered, better considering commit time as well. <br/>
- * Commits will be shown in the log in this order.
- * @param requirements some limitations on commit data that should be returned.
+ * Reads the most recent commits from the log together with all repository references.<br/>
+ * Commits should be at least topologically ordered, better considering commit time as well: they will be shown in the log in this order.
+ * <p/>
+ * This method is called both on the startup and on refresh.
+ *
+ * @param requirements some limitations on commit data that should be returned, e.g. the number of commits.
+ * @return given amount of ordered commits and <b>all</b> references in the repository.
*/
@NotNull
- List<? extends VcsCommitMetadata> readFirstBlock(@NotNull VirtualFile root, @NotNull Requirements requirements) throws VcsException;
+ DetailedLogData readFirstBlock(@NotNull VirtualFile root, @NotNull Requirements requirements) throws VcsException;
/**
- * <p>Reads the whole history, but only hashes & parents.</p>
- * <p>Also reports authors/committers of this repository to the given user registry.</p>
+ * Reads the whole history.
+ * <p/>
+ * Reports commits to the consumer to avoid creation & even temporary storage of a too large commits collection.
+ *
+ * @return all references and all authors in the repository.
*/
- void readAllHashes(@NotNull VirtualFile root, @NotNull Consumer<VcsUser> userRegistry,
- @NotNull Consumer<TimedVcsCommit> commitConsumer) throws VcsException;
+ @NotNull
+ LogData readAllHashes(@NotNull VirtualFile root, @NotNull Consumer<TimedVcsCommit> commitConsumer) throws VcsException;
/**
* Reads those details of the given commits, which are necessary to be shown in the log table.
@@ -45,12 +52,6 @@ public interface VcsLogProvider {
List<? extends VcsFullCommitDetails> readFullDetails(@NotNull VirtualFile root, @NotNull List<String> hashes) throws VcsException;
/**
- * Read all references (branches, tags, etc.) for the given roots.
- */
- @NotNull
- Collection<VcsRef> readAllRefs(@NotNull VirtualFile root) throws VcsException;
-
- /**
* <p>Returns the VCS which is supported by this provider.</p>
* <p>If there will be several VcsLogProviders which support the same VCS, only one will be chosen. It is undefined, which one.</p>
*/
@@ -106,4 +107,20 @@ public interface VcsLogProvider {
}
+ /**
+ * Container for references and users.
+ */
+ interface LogData {
+ @NotNull Set<VcsRef> getRefs();
+ @NotNull Set<VcsUser> getUsers();
+ }
+
+ /**
+ * Container for the ordered list of commits together with their details, and references.
+ */
+ interface DetailedLogData {
+ @NotNull List<VcsCommitMetadata> getCommits();
+ @NotNull Set<VcsRef> getRefs();
+ }
+
}
diff --git a/platform/vcs-log/api/src/com/intellij/vcs/log/VcsLogProviderRequirementsEx.java b/platform/vcs-log/api/src/com/intellij/vcs/log/VcsLogProviderRequirementsEx.java
index d69579ac00b1..68623a6852f9 100644
--- a/platform/vcs-log/api/src/com/intellij/vcs/log/VcsLogProviderRequirementsEx.java
+++ b/platform/vcs-log/api/src/com/intellij/vcs/log/VcsLogProviderRequirementsEx.java
@@ -15,7 +15,6 @@
*/
package com.intellij.vcs.log;
-import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import java.util.Set;
@@ -24,7 +23,7 @@ import static com.intellij.vcs.log.VcsLogProvider.Requirements;
/**
* Extension of the standard {@link Requirements} which contains data used by some VCSs. <br/>
- * An object of this object is actually passed to {@link VcsLogProvider#readFirstBlock(VirtualFile, Requirements)}, but VcsLogProviders
+ * An object of this object is actually passed to {@link #readFirstBlock(com.intellij.util.Consumer}, but VcsLogProviders
* which need this additional information must check for instanceof before casting & be able to fallback.
*/
public interface VcsLogProviderRequirementsEx extends Requirements {
@@ -41,10 +40,4 @@ public interface VcsLogProviderRequirementsEx extends Requirements {
@NotNull
Set<VcsRef> getPreviousRefs();
- /**
- * Returns current refs.
- */
- @NotNull
- Set<VcsRef> getCurrentRefs();
-
}
diff --git a/platform/vcs-log/api/vcs-log-api.iml b/platform/vcs-log/api/vcs-log-api.iml
index 92d746615afa..a9a76e60b302 100644
--- a/platform/vcs-log/api/vcs-log-api.iml
+++ b/platform/vcs-log/api/vcs-log-api.iml
@@ -10,7 +10,6 @@
<orderEntry type="module" module-name="util-rt" />
<orderEntry type="module" module-name="vcs-log-graph-api" exported="" />
<orderEntry type="module" module-name="core-api" />
- <orderEntry type="library" name="JUnit4" level="project" />
<orderEntry type="module" module-name="vcs-api-core" />
<orderEntry type="module" module-name="editor-ui-api" />
</component>
diff --git a/platform/vcs-log/graph-api/src/com/intellij/vcs/log/graph/RowInfo.java b/platform/vcs-log/graph-api/src/com/intellij/vcs/log/graph/RowInfo.java
index 3855467bffad..15a6cb07895d 100644
--- a/platform/vcs-log/graph-api/src/com/intellij/vcs/log/graph/RowInfo.java
+++ b/platform/vcs-log/graph-api/src/com/intellij/vcs/log/graph/RowInfo.java
@@ -32,4 +32,7 @@ public interface RowInfo<CommitId> {
@NotNull
Collection<PrintElement> getPrintElements();
+ @NotNull
+ RowType getRowType();
+
}
diff --git a/platform/vcs-log/graph-api/src/com/intellij/vcs/log/graph/RowType.java b/platform/vcs-log/graph-api/src/com/intellij/vcs/log/graph/RowType.java
new file mode 100644
index 000000000000..b1deca566e0d
--- /dev/null
+++ b/platform/vcs-log/graph-api/src/com/intellij/vcs/log/graph/RowType.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.vcs.log.graph;
+
+public enum RowType {
+
+ NORMAL,
+
+ /**
+ * Indicates that the commit on this row doesn't match current filters.
+ */
+ UNMATCHED
+
+}
diff --git a/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/facade/AbstractVisibleGraph.java b/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/facade/AbstractVisibleGraph.java
index 83cb53fd8c8f..315371192065 100644
--- a/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/facade/AbstractVisibleGraph.java
+++ b/platform/vcs-log/graph/src/com/intellij/vcs/log/graph/impl/facade/AbstractVisibleGraph.java
@@ -105,6 +105,12 @@ public abstract class AbstractVisibleGraph<CommitId> implements VisibleGraph<Com
public Collection<PrintElement> getPrintElements() {
return myPrintElementGenerator.getPrintElements(visibleRow);
}
+
+ @NotNull
+ @Override
+ public RowType getRowType() {
+ return RowType.NORMAL;
+ }
};
}
diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/DataPack.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/DataPack.java
index 48b25be01ab9..975808611ed4 100644
--- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/DataPack.java
+++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/DataPack.java
@@ -26,16 +26,14 @@ public class DataPack implements VcsLogDataPack {
private boolean myFull;
@NotNull
- static DataPack build(@NotNull List<? extends GraphCommit<Integer>> commits, @NotNull RefsModel refsModel,
- @NotNull NotNullFunction<Hash, Integer> indexGetter, @NotNull NotNullFunction<Integer, Hash> hashGetter,
- @NotNull Map<VirtualFile, VcsLogProvider> providers, boolean full) {
- return build(buildPermanentGraph(commits, refsModel, indexGetter, hashGetter, providers), providers, refsModel, full);
- }
-
- @NotNull
- static DataPack build(@NotNull PermanentGraph<Integer> permanentGraph, @NotNull Map<VirtualFile, VcsLogProvider> providers,
- @NotNull RefsModel refsModel, boolean full) {
- return new DataPack(refsModel, permanentGraph, createGraphFacade(permanentGraph), providers, full);
+ static DataPack build(@NotNull List<? extends GraphCommit<Integer>> commits,
+ @NotNull Map<VirtualFile, Set<VcsRef>> refs,
+ @NotNull Map<VirtualFile, VcsLogProvider> providers,
+ @NotNull VcsLogHashMap hashMap,
+ boolean full) {
+ RefsModel refsModel = new RefsModel(refs, hashMap.asIndexGetter());
+ PermanentGraph<Integer> graph = buildPermanentGraph(commits, refsModel, hashMap.asIndexGetter(), hashMap.asHashGetter(), providers);
+ return new DataPack(refsModel, graph, createGraphFacade(graph), providers, full);
}
@NotNull
@@ -57,11 +55,11 @@ public class DataPack implements VcsLogDataPack {
}
@NotNull
- static PermanentGraph<Integer> buildPermanentGraph(@NotNull List<? extends GraphCommit<Integer>> commits,
- @NotNull RefsModel refsModel,
- @NotNull NotNullFunction<Hash, Integer> indexGetter,
- @NotNull NotNullFunction<Integer, Hash> hashGetter,
- @NotNull Map<VirtualFile, VcsLogProvider> providers) {
+ private static PermanentGraph<Integer> buildPermanentGraph(@NotNull List<? extends GraphCommit<Integer>> commits,
+ @NotNull RefsModel refsModel,
+ @NotNull NotNullFunction<Hash, Integer> indexGetter,
+ @NotNull NotNullFunction<Integer, Hash> hashGetter,
+ @NotNull Map<VirtualFile, VcsLogProvider> providers) {
if (commits.isEmpty()) {
return EmptyPermanentGraph.getInstance();
}
diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/EmptyDataPack.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/EmptyDataPack.java
index 6262d767d071..54140afb3940 100644
--- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/EmptyDataPack.java
+++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/EmptyDataPack.java
@@ -22,14 +22,14 @@ import com.intellij.vcs.log.VcsLogProvider;
import com.intellij.vcs.log.VcsRef;
import org.jetbrains.annotations.NotNull;
-import java.util.Collection;
import java.util.Collections;
+import java.util.Set;
public class EmptyDataPack {
@NotNull
public static DataPack getInstance() {
- RefsModel emptyModel = new RefsModel(Collections.<VirtualFile, Collection<VcsRef>>emptyMap(), new ConstantFunction<Hash, Integer>(0));
+ RefsModel emptyModel = new RefsModel(Collections.<VirtualFile, Set<VcsRef>>emptyMap(), new ConstantFunction<Hash, Integer>(0));
return new DataPack(emptyModel, EmptyPermanentGraph.getInstance(), new EmptyGraphFacade(), Collections.<VirtualFile, VcsLogProvider>emptyMap(), false);
}
diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/EmptyVisibleGraph.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/EmptyVisibleGraph.java
index 4bdd38936361..f52b37d1f021 100644
--- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/EmptyVisibleGraph.java
+++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/EmptyVisibleGraph.java
@@ -17,6 +17,7 @@ package com.intellij.vcs.log.data;
import com.intellij.vcs.log.graph.PrintElement;
import com.intellij.vcs.log.graph.RowInfo;
+import com.intellij.vcs.log.graph.RowType;
import com.intellij.vcs.log.graph.VisibleGraph;
import com.intellij.vcs.log.graph.actions.ActionController;
import com.intellij.vcs.log.graph.actions.GraphAnswer;
@@ -120,5 +121,11 @@ class EmptyVisibleGraph implements VisibleGraph<Integer> {
public Collection<PrintElement> getPrintElements() {
return Collections.emptyList();
}
+
+ @NotNull
+ @Override
+ public RowType getRowType() {
+ return RowType.NORMAL;
+ }
}
}
diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/RefsModel.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/RefsModel.java
index 46504b338970..c38e4c315ff0 100644
--- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/RefsModel.java
+++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/RefsModel.java
@@ -16,14 +16,14 @@ import java.util.*;
public class RefsModel implements VcsLogRefs {
- @NotNull private final Map<VirtualFile, Collection<VcsRef>> myRefs;
+ @NotNull private final Map<VirtualFile, Set<VcsRef>> myRefs;
@NotNull private final NotNullFunction<Hash, Integer> myIndexGetter;
@NotNull private final Collection<VcsRef> myBranches;
@NotNull private final MultiMap<Hash, VcsRef> myRefsToHashes;
@NotNull private final TIntObjectHashMap<SmartList<VcsRef>> myRefsToIndices;
- public RefsModel(@NotNull Map<VirtualFile, Collection<VcsRef>> refsByRoot, @NotNull NotNullFunction<Hash, Integer> indexGetter) {
+ public RefsModel(@NotNull Map<VirtualFile, Set<VcsRef>> refsByRoot, @NotNull NotNullFunction<Hash, Integer> indexGetter) {
myRefs = refsByRoot;
myIndexGetter = indexGetter;
@@ -85,7 +85,7 @@ public class RefsModel implements VcsLogRefs {
}
@NotNull
- public Map<VirtualFile, Collection<VcsRef>> getAllRefsByRoot() {
+ public Map<VirtualFile, Set<VcsRef>> getAllRefsByRoot() {
return myRefs;
}
diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogMultiRepoJoiner.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogMultiRepoJoiner.java
index 072e0e26ace1..f36b26a74d94 100644
--- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogMultiRepoJoiner.java
+++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogMultiRepoJoiner.java
@@ -6,31 +6,31 @@ import org.jetbrains.annotations.NotNull;
import java.util.*;
-public class VcsLogMultiRepoJoiner<CommitId> {
+public class VcsLogMultiRepoJoiner<CommitId, Commit extends GraphCommit<CommitId>> {
@NotNull
- public List<? extends GraphCommit<CommitId>> join(@NotNull Collection<List<? extends GraphCommit<CommitId>>> logsFromRepos) {
+ public List<Commit> join(@NotNull Collection<List<Commit>> logsFromRepos) {
if (logsFromRepos.size() == 1) {
return logsFromRepos.iterator().next();
}
int size = 0;
- for (List<? extends GraphCommit<CommitId>> repo : logsFromRepos) {
+ for (List<Commit> repo : logsFromRepos) {
size += repo.size();
}
- List<GraphCommit<CommitId>> result = new ArrayList<GraphCommit<CommitId>>(size);
+ List<Commit> result = new ArrayList<Commit>(size);
- Map<GraphCommit<CommitId>, Iterator<? extends GraphCommit<CommitId>>> nextCommits = ContainerUtil.newHashMap();
- for (List<? extends GraphCommit<CommitId>> log : logsFromRepos) {
- Iterator<? extends GraphCommit<CommitId>> iterator = log.iterator();
+ Map<Commit, Iterator<Commit>> nextCommits = ContainerUtil.newHashMap();
+ for (List<Commit> log : logsFromRepos) {
+ Iterator<Commit> iterator = log.iterator();
if (iterator.hasNext()) {
nextCommits.put(iterator.next(), iterator);
}
}
while (!nextCommits.isEmpty()) {
- GraphCommit<CommitId> lastCommit = findLatestCommit(nextCommits.keySet());
- Iterator<? extends GraphCommit<CommitId>> iterator = nextCommits.get(lastCommit);
+ Commit lastCommit = findLatestCommit(nextCommits.keySet());
+ Iterator<Commit> iterator = nextCommits.get(lastCommit);
result.add(lastCommit);
nextCommits.remove(lastCommit);
@@ -43,10 +43,10 @@ public class VcsLogMultiRepoJoiner<CommitId> {
}
@NotNull
- private GraphCommit<CommitId> findLatestCommit(@NotNull Set<GraphCommit<CommitId>> commits) {
+ private Commit findLatestCommit(@NotNull Set<Commit> commits) {
long maxTimeStamp = Long.MIN_VALUE;
- GraphCommit<CommitId> lastCommit = null;
- for (GraphCommit<CommitId> commit : commits) {
+ Commit lastCommit = null;
+ for (Commit commit : commits) {
if (commit.getTimestamp() >= maxTimeStamp) {
maxTimeStamp = commit.getTimestamp();
lastCommit = commit;
diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogRefresherImpl.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogRefresherImpl.java
index c7ab5e324b3d..09de51c722bf 100644
--- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogRefresherImpl.java
+++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogRefresherImpl.java
@@ -27,6 +27,7 @@ import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Consumer;
import com.intellij.util.Function;
+import com.intellij.util.NotNullFunction;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.UIUtil;
import com.intellij.vcs.log.*;
@@ -62,7 +63,8 @@ public class VcsLogRefresherImpl implements VcsLogRefresher {
@NotNull final VcsUserRegistryImpl userRegistry,
@NotNull Map<Hash, VcsCommitMetadata> topCommitsDetailsCache,
@NotNull final Consumer<DataPack> dataPackUpdateHandler,
- @NotNull Consumer<Exception> exceptionHandler, int recentCommitsCount) {
+ @NotNull Consumer<Exception> exceptionHandler,
+ int recentCommitsCount) {
myProject = project;
myHashMap = hashMap;
myProviders = providers;
@@ -95,16 +97,11 @@ public class VcsLogRefresherImpl implements VcsLogRefresher {
@Override
public DataPack readFirstBlock() {
try {
- Map<VirtualFile, Collection<VcsRef>> refs = loadRefsFromVcs(myProviders);
- Set<VirtualFile> roots = myProviders.keySet();
- Map<VirtualFile, VcsLogProvider.Requirements> requirements = prepareSimpleRequirements(roots, myRecentCommitCount);
- Map<VirtualFile, List<? extends GraphCommit<Integer>>> commits = loadRecentCommitsFromVcs(myProviders, requirements,
- myUserRegistry, myTopCommitsDetailsCache,
- myHashMap);
- List<? extends GraphCommit<Integer>> compoundLog = compound(commits.values());
- DataPack dataPack = DataPack.build(compoundLog, new RefsModel(refs, myHashMap.asIndexGetter()),
- myHashMap.asIndexGetter(), myHashMap.asHashGetter(), myProviders, false);
- mySingleTaskController.request(RefreshRequest.RELOAD_ALL); // build/rebuild the full log in bg
+ LogInfo data = loadRecentData(new CommitCountRequirements(myRecentCommitCount).asMap(myProviders.keySet()));
+ Collection<List<GraphCommit<Integer>>> commits = data.getCommits();
+ Map<VirtualFile, Set<VcsRef>> refs = data.getRefs();
+ DataPack dataPack = DataPack.build(multiRepoJoin(commits), refs, myProviders, myHashMap, false);
+ mySingleTaskController.request(RefreshRequest.RELOAD_ALL); // build/rebuild the full log in background
return dataPack;
}
catch (VcsException e) {
@@ -113,109 +110,77 @@ public class VcsLogRefresherImpl implements VcsLogRefresher {
}
}
- @Override
- public void refresh(@NotNull Collection<VirtualFile> rootsToRefresh) {
- if (!rootsToRefresh.isEmpty()) {
- mySingleTaskController.request(new RefreshRequest(rootsToRefresh));
- }
- }
-
@NotNull
- private static Map<VirtualFile, VcsLogProvider.Requirements> prepareSimpleRequirements(@NotNull Collection<VirtualFile> roots,
- final int commitCount) {
- final VcsLogProvider.Requirements requirements = new VcsLogProvider.Requirements() {
- @Override
- public int getCommitCount() {
- return commitCount;
- }
- };
- return ContainerUtil.map2Map(roots, new Function<VirtualFile, Pair<VirtualFile, VcsLogProvider.Requirements>>() {
- @Override
- public Pair<VirtualFile, VcsLogProvider.Requirements> fun(VirtualFile file) {
- return Pair.create(file, requirements);
- }
- });
- }
-
- @NotNull
- private static Map<VirtualFile, Collection<VcsRef>> loadRefsFromVcs(@NotNull Map<VirtualFile, VcsLogProvider> providers)
- throws VcsException {
- final StopWatch sw = StopWatch.start("loading refs");
- final Map<VirtualFile, Collection<VcsRef>> refs = ContainerUtil.newHashMap();
+ private LogInfo loadRecentData(@NotNull final Map<VirtualFile, VcsLogProvider.Requirements> requirements) throws VcsException {
+ final StopWatch sw = StopWatch.start("loading commits");
+ final LogInfo logInfo = new LogInfo();
new ProviderIterator() {
@Override
- void each(@NotNull VirtualFile root, @NotNull VcsLogProvider provider) throws VcsException {
- refs.put(root, provider.readAllRefs(root));
+ public void each(@NotNull VirtualFile root, @NotNull VcsLogProvider provider) throws VcsException {
+ VcsLogProvider.DetailedLogData data = provider.readFirstBlock(root, requirements.get(root));
+ storeUsersAndDetails(data.getCommits());
+ logInfo.put(root, compactCommits(data.getCommits()));
+ logInfo.put(root, data.getRefs());
sw.rootCompleted(root);
}
- }.iterate(providers);
+ }.iterate(getProvidersForRoots(requirements.keySet()));
+ myUserRegistry.flush();
sw.report();
- return refs;
+ return logInfo;
}
@NotNull
- private static Map<VirtualFile, List<? extends GraphCommit<Integer>>> loadRecentCommitsFromVcs(
- @NotNull Map<VirtualFile, VcsLogProvider> providers,
- @NotNull final Map<VirtualFile, VcsLogProvider.Requirements> requirements,
- @NotNull final VcsUserRegistryImpl userRegistry,
- @NotNull final Map<Hash, VcsCommitMetadata> topCommitsDetailsCache,
- @NotNull final VcsLogHashMap hashMap) throws VcsException
- {
- final StopWatch sw = StopWatch.start("loading commits");
- final Map<VirtualFile, List<? extends GraphCommit<Integer>>> commits = ContainerUtil.newHashMap();
- new ProviderIterator() {
- @Override
- public void each(@NotNull VirtualFile root, @NotNull VcsLogProvider provider) throws VcsException {
- List<? extends VcsCommitMetadata> metadatas = provider.readFirstBlock(root, requirements.get(root));
- storeUsersAndDetails(metadatas, userRegistry, topCommitsDetailsCache);
- commits.put(root, compactCommits(metadatas, hashMap));
- sw.rootCompleted(root);
- }
- }.iterate(providers);
- userRegistry.flush();
- sw.report();
- return commits;
+ private Map<VirtualFile, VcsLogProvider> getProvidersForRoots(@NotNull Set<VirtualFile> roots) {
+ return ContainerUtil.map2Map(roots,
+ new Function<VirtualFile, Pair<VirtualFile, VcsLogProvider>>() {
+ @Override
+ public Pair<VirtualFile, VcsLogProvider> fun(VirtualFile root) {
+ return Pair.create(root, myProviders.get(root));
+ }
+ });
+ }
+
+ @Override
+ public void refresh(@NotNull Collection<VirtualFile> rootsToRefresh) {
+ if (!rootsToRefresh.isEmpty()) {
+ mySingleTaskController.request(new RefreshRequest(rootsToRefresh));
+ }
}
- /**
- * Compounds logs from different repositories into a single multi-repository log.
- */
@NotNull
- private static List<? extends GraphCommit<Integer>> compound(@NotNull Collection<List<? extends GraphCommit<Integer>>> commits) {
+ private static <T extends GraphCommit<Integer>> List<T> multiRepoJoin(@NotNull Collection<List<T>> commits) {
StopWatch sw = StopWatch.start("multi-repo join");
- List<? extends GraphCommit<Integer>> joined = new VcsLogMultiRepoJoiner<Integer>().join(commits);
+ List<T> joined = new VcsLogMultiRepoJoiner<Integer, T>().join(commits);
sw.report();
return joined;
}
@NotNull
- private static List<GraphCommit<Integer>> compactCommits(@NotNull List<? extends TimedVcsCommit> commits,
- @NotNull final VcsLogHashMap hashMap) {
+ private List<GraphCommit<Integer>> compactCommits(@NotNull List<? extends TimedVcsCommit> commits) {
StopWatch sw = StopWatch.start("compacting commits");
List<GraphCommit<Integer>> map = ContainerUtil.map(commits, new Function<TimedVcsCommit, GraphCommit<Integer>>() {
@NotNull
@Override
public GraphCommit<Integer> fun(@NotNull TimedVcsCommit commit) {
- return compactCommit(commit, hashMap);
+ return compactCommit(commit);
}
});
- hashMap.flush();
+ myHashMap.flush();
sw.report();
return map;
}
@NotNull
- private static GraphCommitImpl<Integer> compactCommit(@NotNull TimedVcsCommit commit, @NotNull VcsLogHashMap hashMap) {
- return new GraphCommitImpl<Integer>(hashMap.getCommitIndex(commit.getId()),
- ContainerUtil.map(commit.getParents(), hashMap.asIndexGetter()), commit.getTimestamp());
+ private GraphCommitImpl<Integer> compactCommit(@NotNull TimedVcsCommit commit) {
+ return new GraphCommitImpl<Integer>(myHashMap.getCommitIndex(commit.getId()),
+ ContainerUtil.map(commit.getParents(), myHashMap.asIndexGetter()), commit.getTimestamp());
}
- private static void storeUsersAndDetails(@NotNull List<? extends VcsCommitMetadata> metadatas, @NotNull VcsUserRegistryImpl userRegistry,
- @NotNull Map<Hash, VcsCommitMetadata> topCommitsDetailsCache) {
+ private void storeUsersAndDetails(@NotNull Collection<? extends VcsCommitMetadata> metadatas) {
for (VcsCommitMetadata detail : metadatas) {
- userRegistry.addUser(detail.getAuthor());
- userRegistry.addUser(detail.getCommitter());
- topCommitsDetailsCache.put(detail.getId(), detail);
+ myUserRegistry.addUser(detail.getAuthor());
+ myUserRegistry.addUser(detail.getCommitter());
+ myTopCommitsDetailsCache.put(detail.getId(), detail);
}
}
@@ -223,17 +188,7 @@ public class VcsLogRefresherImpl implements VcsLogRefresher {
@NotNull private DataPack myCurrentDataPack;
- // collects loaded info from different roots, which refresh was requested consecutively within a single task
- private final Map<VirtualFile, LogAndRefs> myLoadedInfos = ContainerUtil.newHashMap();
-
- private class LogAndRefs {
- List<? extends GraphCommit<Integer>> log;
- Collection<VcsRef> refs;
- LogAndRefs(Collection<VcsRef> refs, List<? extends GraphCommit<Integer>> commits) {
- this.refs = refs;
- this.log = commits;
- }
- }
+ @NotNull private final LogInfo myLoadedInfo = new LogInfo();
MyRefreshTask(@NotNull DataPack currentDataPack) {
super(VcsLogRefresherImpl.this.myProject, "Refreshing history...", false);
@@ -271,30 +226,28 @@ public class VcsLogRefresherImpl implements VcsLogRefresher {
private DataPack doRefresh(@NotNull Collection<VirtualFile> roots) {
StopWatch sw = StopWatch.start("refresh");
PermanentGraph<Integer> permanentGraph = myCurrentDataPack.isFull() ? myCurrentDataPack.getPermanentGraph() : null;
- Map<VirtualFile, Collection<VcsRef>> currentRefs = myCurrentDataPack.getRefsModel().getAllRefsByRoot();
+ Map<VirtualFile, Set<VcsRef>> currentRefs = myCurrentDataPack.getRefsModel().getAllRefsByRoot();
try {
if (permanentGraph != null) {
int commitCount = myRecentCommitCount;
for (int attempt = 0; attempt <= 1; attempt++) {
loadLogAndRefs(roots, currentRefs, commitCount);
- List<? extends GraphCommit<Integer>> compoundLog = compoundLoadedLogs(myLoadedInfos.values());
- Map<VirtualFile, Collection<VcsRef>> allNewRefs = getAllNewRefs(myLoadedInfos, currentRefs);
+ List<? extends GraphCommit<Integer>> compoundLog = multiRepoJoin(myLoadedInfo.getCommits());
+ Map<VirtualFile, Set<VcsRef>> allNewRefs = getAllNewRefs(myLoadedInfo, currentRefs);
List<GraphCommit<Integer>> joinedFullLog = join(compoundLog, permanentGraph.getAllCommits(), currentRefs, allNewRefs);
if (joinedFullLog == null) {
commitCount *= 5;
}
else {
- return DataPack.build(joinedFullLog, new RefsModel(allNewRefs, myHashMap.asIndexGetter()),
- myHashMap.asIndexGetter(), myHashMap.asHashGetter(), myProviders, true);
+ return DataPack.build(joinedFullLog, allNewRefs, myProviders, myHashMap, true);
}
}
// couldn't join => need to reload everything; if 5000 commits is still not enough, it's worth reporting:
LOG.error("Couldn't join " + commitCount + " recent commits to the log (" + permanentGraph.getAllCommits().size() + " commits)",
- new Attachment("recent_commits", toLogString(myLoadedInfos)));
+ new Attachment("recent_commits", myLoadedInfo.toLogString(myHashMap.asIndexGetter())));
}
- Pair<PermanentGraph<Integer>, Map<VirtualFile, Collection<VcsRef>>> fullLogAndRefs = loadFullLog();
- return DataPack.build(fullLogAndRefs.first, myProviders, new RefsModel(fullLogAndRefs.second, myHashMap.asIndexGetter()), true);
+ return loadFullLog();
}
catch (Exception e) {
myExceptionHandler.consume(e);
@@ -305,95 +258,45 @@ public class VcsLogRefresherImpl implements VcsLogRefresher {
}
}
- private String toLogString(Map<VirtualFile, LogAndRefs> infos) {
- StringBuilder sb = new StringBuilder();
- for (Map.Entry<VirtualFile, LogAndRefs> entry : infos.entrySet()) {
- sb.append(entry.getKey().getName());
- sb.append(" LOG:\n");
- sb.append(StringUtil.join(entry.getValue().log, new Function<GraphCommit<Integer>, String>() {
- @Override
- public String fun(GraphCommit<Integer> commit) {
- return commit.getId() + "<-" + StringUtil.join(commit.getParents(), ",");
- }
- }, "\n"));
- sb.append("\nREFS:\n");
- sb.append(StringUtil.join(entry.getValue().refs, new Function<VcsRef, String>() {
- @Override
- public String fun(VcsRef ref) {
- return ref.getName() + "(" + myHashMap.getCommitIndex(ref.getCommitHash()) + ")";
- }
- }, ","));
- }
- return sb.toString();
- }
-
@NotNull
- private List<? extends GraphCommit<Integer>> compoundLoadedLogs(@NotNull Collection<LogAndRefs> logsAndRefs) {
- return compound(ContainerUtil.map(logsAndRefs, new Function<LogAndRefs, List<? extends GraphCommit<Integer>>>() {
- @Override
- public List<? extends GraphCommit<Integer>> fun(LogAndRefs refs) {
- return refs.log;
- }
- }));
- }
-
- @NotNull
- private Map<VirtualFile, Collection<VcsRef>> getAllNewRefs(@NotNull Map<VirtualFile, LogAndRefs> newInfo,
- @NotNull Map<VirtualFile, Collection<VcsRef>> previousRefs) {
- Map<VirtualFile, Collection<VcsRef>> result = ContainerUtil.newHashMap();
+ private Map<VirtualFile, Set<VcsRef>> getAllNewRefs(@NotNull LogInfo newInfo,
+ @NotNull Map<VirtualFile, Set<VcsRef>> previousRefs) {
+ Map<VirtualFile, Set<VcsRef>> result = ContainerUtil.newHashMap();
for (VirtualFile root : previousRefs.keySet()) {
- result.put(root, newInfo.containsKey(root) ? newInfo.get(root).refs : previousRefs.get(root));
+ Set<VcsRef> newInfoRefs = newInfo.getRefs(root);
+ result.put(root, newInfoRefs != null ? newInfoRefs : previousRefs.get(root));
}
return result;
}
- private void loadLogAndRefs(@NotNull Collection<VirtualFile> roots, @NotNull Map<VirtualFile, Collection<VcsRef>> prevRefs,
+ private void loadLogAndRefs(@NotNull Collection<VirtualFile> roots,
+ @NotNull Map<VirtualFile, Set<VcsRef>> prevRefs,
int commitCount) throws VcsException {
- Map<VirtualFile, VcsLogProvider> providers = getProviders(roots);
- Map<VirtualFile, Collection<VcsRef>> refs = loadRefsFromVcs(providers);
- Map<VirtualFile, VcsLogProvider.Requirements> requirements = prepareRequirements(roots, commitCount, prevRefs, refs);
- Map<VirtualFile, List<? extends GraphCommit<Integer>>> commits = loadRecentCommitsFromVcs(providers, requirements,
- myUserRegistry, myTopCommitsDetailsCache,
- myHashMap);
+ LogInfo logInfo = loadRecentData(prepareRequirements(roots, commitCount, prevRefs));
for (VirtualFile root : roots) {
- myLoadedInfos.put(root, new LogAndRefs(refs.get(root), commits.get(root)));
+ myLoadedInfo.put(root, logInfo.getCommits(root));
+ myLoadedInfo.put(root, logInfo.getRefs(root));
}
}
@NotNull
private Map<VirtualFile, VcsLogProvider.Requirements> prepareRequirements(@NotNull Collection<VirtualFile> roots,
int commitCount,
- @NotNull Map<VirtualFile, Collection<VcsRef>> prevRefs,
- @NotNull Map<VirtualFile, Collection<VcsRef>> newRefs) {
+ @NotNull Map<VirtualFile, Set<VcsRef>> prevRefs) {
Map<VirtualFile, VcsLogProvider.Requirements> requirements = ContainerUtil.newHashMap();
for (VirtualFile root : roots) {
- requirements.put(root, new RequirementsImpl(commitCount, true, getRefsForRoot(prevRefs, root), getRefsForRoot(newRefs, root)));
+ requirements.put(root, new RequirementsImpl(commitCount, true, ContainerUtil.notNullize(prevRefs.get(root))));
}
return requirements;
}
- @NotNull
- private Set<VcsRef> getRefsForRoot(@NotNull Map<VirtualFile, Collection<VcsRef>> map, @NotNull VirtualFile root) {
- Collection<VcsRef> refs = map.get(root);
- return refs == null ? Collections.<VcsRef>emptySet() : new HashSet<VcsRef>(refs);
- }
-
- @NotNull
- private Map<VirtualFile, VcsLogProvider> getProviders(@NotNull Collection<VirtualFile> roots) {
- Map<VirtualFile, VcsLogProvider> providers = ContainerUtil.newHashMap();
- for (VirtualFile root : roots) {
- providers.put(root, myProviders.get(root));
- }
- return providers;
- }
-
@Nullable
- private List<GraphCommit<Integer>> join(@NotNull List<? extends GraphCommit<Integer>> recentCommits, @NotNull List<GraphCommit<Integer>> fullLog,
- @NotNull Map<VirtualFile, Collection<VcsRef>> previousRefs,
- @NotNull Map<VirtualFile, Collection<VcsRef>> newRefs) {
+ private List<GraphCommit<Integer>> join(@NotNull List<? extends GraphCommit<Integer>> recentCommits,
+ @NotNull List<GraphCommit<Integer>> fullLog,
+ @NotNull Map<VirtualFile, Set<VcsRef>> previousRefs,
+ @NotNull Map<VirtualFile, Set<VcsRef>> newRefs) {
StopWatch sw = StopWatch.start("joining new commits");
Function<VcsRef, Integer> ref2Int = new Function<VcsRef, Integer>() {
- @NotNull
@Override
public Integer fun(@NotNull VcsRef ref) {
return myHashMap.getCommitIndex(ref.getCommitHash());
@@ -418,50 +321,44 @@ public class VcsLogRefresherImpl implements VcsLogRefresher {
}
@NotNull
- private Pair<PermanentGraph<Integer>, Map<VirtualFile, Collection<VcsRef>>> loadFullLog() throws VcsException {
+ private DataPack loadFullLog() throws VcsException {
StopWatch sw = StopWatch.start("full log reload");
- Collection<List<? extends GraphCommit<Integer>>> commits = readFullLogFromVcs();
- List<? extends GraphCommit<Integer>> graphCommits = compound(commits);
- Map<VirtualFile, Collection<VcsRef>> refMap = loadRefsFromVcs(myProviders);
- PermanentGraph<Integer> permanentGraph = DataPack.buildPermanentGraph(graphCommits, new RefsModel(refMap, myHashMap.asIndexGetter()),
- myHashMap.asIndexGetter(),
- myHashMap.asHashGetter(), myProviders);
+ LogInfo logInfo = readFullLogFromVcs();
+ List<? extends GraphCommit<Integer>> graphCommits = multiRepoJoin(logInfo.getCommits());
+ DataPack dataPack = DataPack.build(graphCommits, logInfo.getRefs(), myProviders, myHashMap, true);
sw.report();
- return Pair.create(permanentGraph, refMap);
+ return dataPack;
}
@NotNull
- private Collection<List<? extends GraphCommit<Integer>>> readFullLogFromVcs() throws VcsException {
+ private LogInfo readFullLogFromVcs() throws VcsException {
final StopWatch sw = StopWatch.start("read full log from VCS");
- final Collection<List<? extends GraphCommit<Integer>>> logs = ContainerUtil.newArrayList();
+ final LogInfo logInfo = new LogInfo();
new ProviderIterator() {
@Override
void each(@NotNull VirtualFile root, @NotNull VcsLogProvider provider) throws VcsException {
final List<GraphCommit<Integer>> graphCommits = ContainerUtil.newArrayList();
- provider.readAllHashes(root, new Consumer<VcsUser>() {
- @Override
- public void consume(@NotNull VcsUser user) {
- myUserRegistry.addUser(user);
- }
- }, new Consumer<TimedVcsCommit>() {
+ VcsLogProvider.LogData data = provider.readAllHashes(root, new Consumer<TimedVcsCommit>() {
@Override
- public void consume(TimedVcsCommit commit) {
- graphCommits.add(compactCommit(commit, myHashMap));
+ public void consume(@NotNull TimedVcsCommit commit) {
+ graphCommits.add(compactCommit(commit));
}
});
- logs.add(graphCommits);
+ logInfo.put(root, graphCommits);
+ logInfo.put(root, data.getRefs());
+ myUserRegistry.addUsers(data.getUsers());
sw.rootCompleted(root);
}
}.iterate(myProviders);
myUserRegistry.flush();
sw.report();
- return logs;
+ return logInfo;
}
}
private static class RefreshRequest {
- private static RefreshRequest RELOAD_ALL = new RefreshRequest(Collections.<VirtualFile>emptyList());
- @NotNull private final Collection<VirtualFile> rootsToRefresh;
+ private static final RefreshRequest RELOAD_ALL = new RefreshRequest(Collections.<VirtualFile>emptyList());
+ private final Collection<VirtualFile> rootsToRefresh;
RefreshRequest(@NotNull Collection<VirtualFile> rootsToRefresh) {
this.rootsToRefresh = rootsToRefresh;
@@ -477,4 +374,85 @@ public class VcsLogRefresherImpl implements VcsLogRefresher {
}
}
}
+
+ private static class CommitCountRequirements implements VcsLogProvider.Requirements {
+ private final int myCommitCount;
+
+ public CommitCountRequirements(int commitCount) {
+ myCommitCount = commitCount;
+ }
+
+ @Override
+ public int getCommitCount() {
+ return myCommitCount;
+ }
+
+ @NotNull
+ Map<VirtualFile, VcsLogProvider.Requirements> asMap(@NotNull Collection<VirtualFile> roots) {
+ return ContainerUtil.map2Map(roots, new Function<VirtualFile, Pair<VirtualFile, VcsLogProvider.Requirements>>() {
+ @Override
+ public Pair<VirtualFile, VcsLogProvider.Requirements> fun(VirtualFile root) {
+ return Pair.<VirtualFile, VcsLogProvider.Requirements>create(root, CommitCountRequirements.this);
+ }
+ });
+ }
+ }
+
+ private static class LogInfo {
+ private final Map<VirtualFile, Set<VcsRef>> myRefs = ContainerUtil.newHashMap();
+ private final Map<VirtualFile, List<GraphCommit<Integer>>> myCommits = ContainerUtil.newHashMap();
+
+ void put(@NotNull VirtualFile root, @NotNull List<GraphCommit<Integer>> commits) {
+ myCommits.put(root, commits);
+ }
+
+ void put(@NotNull VirtualFile root, @NotNull Set<VcsRef> refs) {
+ myRefs.put(root, refs);
+ }
+
+ @NotNull
+ Collection<List<GraphCommit<Integer>>> getCommits() {
+ return myCommits.values();
+ }
+
+ List<GraphCommit<Integer>> getCommits(@NotNull VirtualFile root) {
+ return myCommits.get(root);
+ }
+
+ @NotNull
+ Map<VirtualFile, Set<VcsRef>> getRefs() {
+ return myRefs;
+ }
+
+ public Set<VcsRef> getRefs(@NotNull VirtualFile root) {
+ return myRefs.get(root);
+ }
+
+ @SuppressWarnings("StringConcatenationInsideStringBufferAppend")
+ @NotNull
+ public String toLogString(@NotNull final NotNullFunction<Hash, Integer> indexGetter) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(" LOG:\n");
+ for (Map.Entry<VirtualFile, List<GraphCommit<Integer>>> entry : myCommits.entrySet()) {
+ sb.append(entry.getKey().getName() + "\n");
+ sb.append(StringUtil.join(entry.getValue(), new Function<GraphCommit<Integer>, String>() {
+ @Override
+ public String fun(@NotNull GraphCommit<Integer> commit) {
+ return commit.getId() + "<-" + StringUtil.join(commit.getParents(), ",");
+ }
+ }, "\n"));
+ }
+ sb.append("\nREFS:\n");
+ for (Map.Entry<VirtualFile, Set<VcsRef>> entry : myRefs.entrySet()) {
+ sb.append(entry.getKey().getName() + "\n");
+ sb.append(StringUtil.join(entry.getValue(), new Function<VcsRef, String>() {
+ @Override
+ public String fun(@NotNull VcsRef ref) {
+ return ref.getName() + "(" + indexGetter.fun(ref.getCommitHash()) + ")";
+ }
+ }, ","));
+ }
+ return sb.toString();
+ }
+ }
}
diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogSorter.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogSorter.java
index d872ac236c16..3f9d742eef34 100644
--- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogSorter.java
+++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogSorter.java
@@ -20,12 +20,13 @@ import com.intellij.vcs.log.TimedVcsCommit;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
public class VcsLogSorter {
@NotNull
- public static <Commit extends TimedVcsCommit> List<Commit> sortByDateTopoOrder(@NotNull List<Commit> commits) {
+ public static <Commit extends TimedVcsCommit> List<Commit> sortByDateTopoOrder(@NotNull Collection<Commit> commits) {
return new VcsLogJoiner.NewCommitIntegrator<Hash, Commit>(new ArrayList<Commit>(), commits).getResultList();
}
diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsUserRegistryImpl.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsUserRegistryImpl.java
index a5447d20f115..8621f379ce65 100644
--- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsUserRegistryImpl.java
+++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsUserRegistryImpl.java
@@ -86,6 +86,12 @@ public class VcsUserRegistryImpl implements Disposable, VcsUserRegistry {
}
}
+ public void addUsers(@NotNull Collection<VcsUser> users) {
+ for (VcsUser user : users) {
+ addUser(user);
+ }
+ }
+
@Override
@NotNull
public Set<VcsUser> getUsers() {
diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/LogDataImpl.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/LogDataImpl.java
new file mode 100644
index 000000000000..82eb4e1a6336
--- /dev/null
+++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/LogDataImpl.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.vcs.log.impl;
+
+import com.intellij.vcs.log.VcsCommitMetadata;
+import com.intellij.vcs.log.VcsLogProvider;
+import com.intellij.vcs.log.VcsRef;
+import com.intellij.vcs.log.VcsUser;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+public class LogDataImpl implements VcsLogProvider.DetailedLogData, VcsLogProvider.LogData {
+
+ private static final LogDataImpl EMPTY = new LogDataImpl(Collections.<VcsRef>emptySet(),
+ Collections.<VcsUser>emptySet(),
+ Collections.<VcsCommitMetadata>emptyList());
+
+ @NotNull private final List<VcsCommitMetadata> myCommits;
+ @NotNull private final Set<VcsRef> myRefs;
+ @NotNull private final Set<VcsUser> myUsers;
+
+ @NotNull
+ public static LogDataImpl empty() {
+ return EMPTY;
+ }
+
+ public LogDataImpl(@NotNull Set<VcsRef> refs, @NotNull Set<VcsUser> users) {
+ this(refs, users, Collections.<VcsCommitMetadata>emptyList());
+ }
+
+ public LogDataImpl(@NotNull Set<VcsRef> refs, @NotNull List<VcsCommitMetadata> metadatas) {
+ this(refs, Collections.<VcsUser>emptySet(), metadatas);
+ }
+
+ private LogDataImpl(@NotNull Set<VcsRef> refs, @NotNull Set<VcsUser> users, @NotNull List<VcsCommitMetadata> commits) {
+ myRefs = refs;
+ myUsers = users;
+ myCommits = commits;
+ }
+
+ @NotNull
+ @Override
+ public List<VcsCommitMetadata> getCommits() {
+ return myCommits;
+ }
+
+ @Override
+ @NotNull
+ public Set<VcsRef> getRefs() {
+ return myRefs;
+ }
+
+ @NotNull
+ @Override
+ public Set<VcsUser> getUsers() {
+ return myUsers;
+ }
+}
diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/RequirementsImpl.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/RequirementsImpl.java
index f742e277283f..9a1e54ed3886 100644
--- a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/RequirementsImpl.java
+++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/RequirementsImpl.java
@@ -26,13 +26,11 @@ public class RequirementsImpl implements VcsLogProviderRequirementsEx {
private final int myCommitCount;
private final boolean myRefresh;
@NotNull private final Set<VcsRef> myPreviousRefs;
- @NotNull private final Set<VcsRef> myCurrentRefs;
- public RequirementsImpl(int count, boolean refresh, @NotNull Set<VcsRef> previousRefs, @NotNull Set<VcsRef> currentRefs) {
+ public RequirementsImpl(int count, boolean refresh, @NotNull Set<VcsRef> previousRefs) {
myCommitCount = count;
myRefresh = refresh;
myPreviousRefs = previousRefs;
- myCurrentRefs = currentRefs;
}
@Override
@@ -50,10 +48,4 @@ public class RequirementsImpl implements VcsLogProviderRequirementsEx {
public Set<VcsRef> getPreviousRefs() {
return myPreviousRefs;
}
-
- @NotNull
- @Override
- public Set<VcsRef> getCurrentRefs() {
- return myCurrentRefs;
- }
}
diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsStructureChooser.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsStructureChooser.java
index 34c638088476..0078669cd811 100644
--- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsStructureChooser.java
+++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/VcsStructureChooser.java
@@ -126,6 +126,7 @@ public class VcsStructureChooser extends DialogWrapper {
return myModulesSet;
}
+ @NotNull
public Collection<VirtualFile> getSelectedFiles() {
return ((CollectionListModel) mySelectedList.getModel()).getItems();
}
diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/StructureFilterPopupComponent.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/StructureFilterPopupComponent.java
index c134b1aa330d..3140d647795f 100644
--- a/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/StructureFilterPopupComponent.java
+++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/ui/filter/StructureFilterPopupComponent.java
@@ -101,7 +101,7 @@ class StructureFilterPopupComponent extends FilterPopupComponent<VcsLogStructure
new ArrayList<VirtualFile>(myRoots));
if (chooser.showAndGet()) {
myFiles.clear();
- myFiles.addAll(ContainerUtil.notNullize(chooser.getSelectedFiles()));
+ myFiles.addAll(chooser.getSelectedFiles());
setValue(myFiles);
applyFilters();
}
diff --git a/platform/vcs-log/impl/test/com/intellij/vcs/log/data/VcsLogRefresherTest.java b/platform/vcs-log/impl/test/com/intellij/vcs/log/data/VcsLogRefresherTest.java
index 6baf2318f7a9..01705232a253 100644
--- a/platform/vcs-log/impl/test/com/intellij/vcs/log/data/VcsLogRefresherTest.java
+++ b/platform/vcs-log/impl/test/com/intellij/vcs/log/data/VcsLogRefresherTest.java
@@ -46,11 +46,11 @@ public class VcsLogRefresherTest extends VcsLogPlatformTest {
throw new AssertionError(e);
}
};
- @NotNull private TestVcsLogProvider myLogProvider;
- @NotNull private VcsLogDataHolder myDataHolder;
- @NotNull private Map<Hash, VcsCommitMetadata> myTopDetailsCache;
- @NotNull private Map<VirtualFile, VcsLogProvider> myLogProviders;
- @NotNull private List<String> myCommits;
+ private TestVcsLogProvider myLogProvider;
+ private VcsLogDataHolder myDataHolder;
+ private Map<Hash, VcsCommitMetadata> myTopDetailsCache;
+ private Map<VirtualFile, VcsLogProvider> myLogProviders;
+ private List<String> myCommits;
@Override
public void setUp() throws Exception {
diff --git a/platform/vcs-log/impl/test/com/intellij/vcs/log/impl/TestVcsLogProvider.java b/platform/vcs-log/impl/test/com/intellij/vcs/log/impl/TestVcsLogProvider.java
index 850478b048dc..05659538da20 100644
--- a/platform/vcs-log/impl/test/com/intellij/vcs/log/impl/TestVcsLogProvider.java
+++ b/platform/vcs-log/impl/test/com/intellij/vcs/log/impl/TestVcsLogProvider.java
@@ -26,10 +26,8 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.awt.*;
-import java.util.Collection;
-import java.util.Comparator;
+import java.util.*;
import java.util.List;
-import java.util.Set;
import java.util.concurrent.Semaphore;
import static org.junit.Assert.assertEquals;
@@ -59,13 +57,14 @@ public class TestVcsLogProvider implements VcsLogProvider {
@NotNull private final ReducibleSemaphore myRefreshSemaphore;
private int myReadFirstBlockCounter;
- private final Function<TimedVcsCommit, VcsCommitMetadata> myCommitToMetadataConvertor = new Function<TimedVcsCommit, VcsCommitMetadata>(){
- @Override
- public VcsCommitMetadata fun(TimedVcsCommit commit) {
- return new VcsCommitMetadataImpl(commit.getId(), commit.getParents(), commit.getTimestamp(), myRoot, SAMPLE_SUBJECT, STUB_USER,
- SAMPLE_SUBJECT, STUB_USER, commit.getTimestamp());
- }
- };
+ private final Function<TimedVcsCommit, VcsCommitMetadata> myCommitToMetadataConvertor =
+ new Function<TimedVcsCommit, VcsCommitMetadata>() {
+ @Override
+ public VcsCommitMetadata fun(TimedVcsCommit commit) {
+ return new VcsCommitMetadataImpl(commit.getId(), commit.getParents(), commit.getTimestamp(), myRoot,
+ SAMPLE_SUBJECT, STUB_USER, SAMPLE_SUBJECT, STUB_USER, commit.getTimestamp());
+ }
+ };
public TestVcsLogProvider(@NotNull VirtualFile root) {
myRoot = root;
@@ -78,7 +77,8 @@ public class TestVcsLogProvider implements VcsLogProvider {
@NotNull
@Override
- public List<? extends VcsCommitMetadata> readFirstBlock(@NotNull final VirtualFile root, @NotNull Requirements requirements)
+ public DetailedLogData readFirstBlock(@NotNull final VirtualFile root,
+ @NotNull Requirements requirements)
throws VcsException {
if (requirements instanceof VcsLogProviderRequirementsEx && ((VcsLogProviderRequirementsEx)requirements).isRefresh()) {
try {
@@ -90,12 +90,14 @@ public class TestVcsLogProvider implements VcsLogProvider {
}
myReadFirstBlockCounter++;
assertRoot(root);
- return ContainerUtil.map(myCommits.subList(0, requirements.getCommitCount()), myCommitToMetadataConvertor);
+ List<VcsCommitMetadata> metadatas = ContainerUtil.map(myCommits.subList(0, requirements.getCommitCount()),
+ myCommitToMetadataConvertor);
+ return new LogDataImpl(Collections.<VcsRef>emptySet(), metadatas);
}
+ @NotNull
@Override
- public void readAllHashes(@NotNull VirtualFile root, @NotNull Consumer<VcsUser> userRegistry,
- @NotNull Consumer<TimedVcsCommit> commitConsumer) throws VcsException {
+ public LogData readAllHashes(@NotNull VirtualFile root, @NotNull Consumer<TimedVcsCommit> commitConsumer) throws VcsException {
try {
myFullLogSemaphore.acquire();
}
@@ -106,6 +108,7 @@ public class TestVcsLogProvider implements VcsLogProvider {
for (TimedVcsCommit commit : myCommits) {
commitConsumer.consume(commit);
}
+ return new LogDataImpl(myRefs, Collections.<VcsUser>emptySet());
}
private void assertRoot(@NotNull VirtualFile root) {
@@ -127,12 +130,6 @@ public class TestVcsLogProvider implements VcsLogProvider {
@NotNull
@Override
- public Collection<VcsRef> readAllRefs(@NotNull VirtualFile root) throws VcsException {
- return myRefs;
- }
-
- @NotNull
- @Override
public VcsKey getSupportedVcs() {
throw new UnsupportedOperationException();
}
diff --git a/platform/vcs-log/impl/vcs-log-impl.iml b/platform/vcs-log/impl/vcs-log-impl.iml
index 304affc03123..4fce9792f123 100644
--- a/platform/vcs-log/impl/vcs-log-impl.iml
+++ b/platform/vcs-log/impl/vcs-log-impl.iml
@@ -16,7 +16,7 @@
<orderEntry type="module" module-name="platform-impl" />
<orderEntry type="module" module-name="vcs-impl" />
<orderEntry type="library" name="Guava" level="project" />
- <orderEntry type="library" name="JUnit4" level="project" />
+ <orderEntry type="library" scope="TEST" name="JUnit4" level="project" />
<orderEntry type="module" module-name="lang-impl" />
<orderEntry type="module" module-name="spellchecker" />
<orderEntry type="module" module-name="vcs-log-graph-api" />
diff --git a/platform/xdebugger-api/src/com/intellij/xdebugger/XDebugProcess.java b/platform/xdebugger-api/src/com/intellij/xdebugger/XDebugProcess.java
index 9cfe6e4e7605..ee949a2ae9ce 100644
--- a/platform/xdebugger-api/src/com/intellij/xdebugger/XDebugProcess.java
+++ b/platform/xdebugger-api/src/com/intellij/xdebugger/XDebugProcess.java
@@ -193,19 +193,32 @@ public abstract class XDebugProcess {
}
/**
- * @deprecated override {@link #createTabLayouter()} and {@link com.intellij.xdebugger.ui.XDebugTabLayouter#registerAdditionalContent} instead
+ * @deprecated Override {@link #createTabLayouter()} and {@link com.intellij.xdebugger.ui.XDebugTabLayouter#registerAdditionalContent} instead
+ * to remove in IDEA 15
*/
+ @SuppressWarnings("UnusedParameters")
@Deprecated
public void registerAdditionalContent(@NotNull RunnerLayoutUi ui) {
}
+ @SuppressWarnings("UnusedParameters")
+ @Deprecated
/**
- * Override this method to provide additional actions in 'Debug' tool window
+ * @deprecated Override {@link #registerAdditionalActions(com.intellij.openapi.actionSystem.ActionGroup, com.intellij.openapi.actionSystem.ActionGroup, com.intellij.openapi.actionSystem.ActionGroup)} instead
+ * to remove in IDEA 15
*/
public void registerAdditionalActions(@NotNull DefaultActionGroup leftToolbar, @NotNull DefaultActionGroup topToolbar) {
}
/**
+ * Override this method to provide additional actions in 'Debug' tool window
+ */
+ public void registerAdditionalActions(@NotNull DefaultActionGroup leftToolbar, @NotNull DefaultActionGroup topToolbar, @NotNull DefaultActionGroup settings) {
+ //noinspection deprecation
+ registerAdditionalActions(leftToolbar, topToolbar);
+ }
+
+ /**
* @return message to show in Variables View when debugger isn't paused
*/
public String getCurrentStateMessage() {
@@ -225,6 +238,7 @@ public abstract class XDebugProcess {
return new XDebugTabLayouter() {
@Override
public void registerAdditionalContent(@NotNull RunnerLayoutUi ui) {
+ //noinspection deprecation
XDebugProcess.this.registerAdditionalContent(ui);
}
};
diff --git a/platform/xdebugger-api/src/com/intellij/xdebugger/evaluation/XDebuggerEvaluator.java b/platform/xdebugger-api/src/com/intellij/xdebugger/evaluation/XDebuggerEvaluator.java
index 6109e9a41598..37e2da11e0e1 100644
--- a/platform/xdebugger-api/src/com/intellij/xdebugger/evaluation/XDebuggerEvaluator.java
+++ b/platform/xdebugger-api/src/com/intellij/xdebugger/evaluation/XDebuggerEvaluator.java
@@ -72,6 +72,13 @@ public abstract class XDebuggerEvaluator {
*/
public abstract void evaluate(@NotNull String expression, @NotNull XEvaluationCallback callback, @Nullable XSourcePosition expressionPosition);
+ /**
+ * Start evaluating expression.
+ *
+ * @param expression expression to evaluate
+ * @param callback used to notify that the expression has been evaluated or an error occurs
+ * @param expressionPosition position where this expression should be evaluated
+ */
public void evaluate(@NotNull XExpression expression, @NotNull XEvaluationCallback callback, @Nullable XSourcePosition expressionPosition) {
evaluate(expression.getExpression(), callback, expressionPosition);
}
@@ -83,15 +90,13 @@ public abstract class XDebuggerEvaluator {
* @param expression expression to evaluate
* @param callback used to notify that the expression has been evaluated or an error occurs
* @param mode code fragment or expression
+ * @deprecated use {@link #evaluate(com.intellij.xdebugger.XExpression, com.intellij.xdebugger.evaluation.XDebuggerEvaluator.XEvaluationCallback, com.intellij.xdebugger.XSourcePosition)} ()}
*/
+ @Deprecated
public void evaluate(@NotNull String expression, @NotNull XEvaluationCallback callback, @Nullable XSourcePosition expressionPosition, @NotNull EvaluationMode mode) {
evaluate(expression, callback, expressionPosition);
}
- public void evaluate(@NotNull XExpression expression, @NotNull XEvaluationCallback callback, @Nullable XSourcePosition expressionPosition, @NotNull EvaluationMode mode) {
- evaluate(expression, callback, expressionPosition);
- }
-
/**
* If this method returns {@code true} 'Code Fragment Mode' button will be shown in 'Evaluate' dialog allowing user to execute a set of
* statements
diff --git a/platform/xdebugger-api/src/com/intellij/xdebugger/frame/XReferrersProvider.java b/platform/xdebugger-api/src/com/intellij/xdebugger/frame/XReferrersProvider.java
index 9f9f3a8bf407..cb31a3be23b0 100644
--- a/platform/xdebugger-api/src/com/intellij/xdebugger/frame/XReferrersProvider.java
+++ b/platform/xdebugger-api/src/com/intellij/xdebugger/frame/XReferrersProvider.java
@@ -16,8 +16,10 @@
package com.intellij.xdebugger.frame;
/**
+ * Provides an XValue that returns instead of children a set of objects that refer to it.
+ *
* @author traff
*/
-public interface XReferrersProvider<T extends XValue> {
- T getReferringObjectsValue();
+public abstract class XReferrersProvider {
+ public abstract XValue getReferringObjectsValue();
}
diff --git a/platform/xdebugger-api/src/com/intellij/xdebugger/frame/XValue.java b/platform/xdebugger-api/src/com/intellij/xdebugger/frame/XValue.java
index 9cfa2fb15af4..4d3446bbfb54 100644
--- a/platform/xdebugger-api/src/com/intellij/xdebugger/frame/XValue.java
+++ b/platform/xdebugger-api/src/com/intellij/xdebugger/frame/XValue.java
@@ -88,6 +88,12 @@ public abstract class XValue extends XValueContainer {
navigatable.setSourcePosition(null);
}
+ /**
+ * This enables showing referrers for the value
+ *
+ * @return provider that creates an XValue returning objects that refer to the current value
+ * or null if showing referrers for the value is disabled
+ */
@Nullable
public XReferrersProvider getReferrersProvider() {
return null;
diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/DebuggerSupport.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/DebuggerSupport.java
index b09c7388748f..d76d60410648 100644
--- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/DebuggerSupport.java
+++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/DebuggerSupport.java
@@ -16,6 +16,7 @@
package com.intellij.xdebugger.impl;
import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.project.Project;
@@ -25,11 +26,15 @@ import com.intellij.xdebugger.impl.actions.DebuggerToggleActionHandler;
import com.intellij.xdebugger.impl.actions.EditBreakpointActionHandler;
import com.intellij.xdebugger.impl.actions.MarkObjectActionHandler;
import com.intellij.xdebugger.impl.breakpoints.ui.BreakpointPanelProvider;
+import com.intellij.xdebugger.impl.evaluate.quick.common.AbstractValueHint;
import com.intellij.xdebugger.impl.evaluate.quick.common.QuickEvaluateHandler;
+import com.intellij.xdebugger.impl.evaluate.quick.common.ValueHintType;
import com.intellij.xdebugger.impl.settings.DebuggerSettingsPanelProvider;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import java.awt.*;
+
/**
* @author nik
*/
@@ -118,7 +123,32 @@ public abstract class DebuggerSupport {
public abstract DebuggerActionHandler getEvaluateHandler();
@NotNull
- public abstract QuickEvaluateHandler getQuickEvaluateHandler();
+ public QuickEvaluateHandler getQuickEvaluateHandler() {
+ return DISABLED_QUICK_EVALUATE;
+ }
+
+ private static final QuickEvaluateHandler DISABLED_QUICK_EVALUATE = new QuickEvaluateHandler() {
+ @Override
+ public boolean isEnabled(@NotNull Project project) {
+ return false;
+ }
+
+ @Nullable
+ @Override
+ public AbstractValueHint createValueHint(@NotNull Project project, @NotNull Editor editor, @NotNull Point point, ValueHintType type) {
+ return null;
+ }
+
+ @Override
+ public boolean canShowHint(@NotNull Project project) {
+ return false;
+ }
+
+ @Override
+ public int getValueLookupDelay(Project project) {
+ return 0;
+ }
+ };
@NotNull
public abstract DebuggerActionHandler getAddToWatchesActionHandler();
diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java
index 1b0f0ca69a59..ddc28745934a 100644
--- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java
+++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebugSessionImpl.java
@@ -98,7 +98,7 @@ public class XDebugSessionImpl implements XDebugSession {
private XExecutionStack myCurrentExecutionStack;
private XStackFrame myCurrentStackFrame;
private boolean myIsTopFrame;
- private XSourcePosition myTopFramePosition;
+ private volatile XSourcePosition myTopFramePosition;
private final AtomicBoolean myPaused = new AtomicBoolean();
private MyDependentBreakpointListener myDependentBreakpointListener;
private XValueMarkers<?, ?> myValueMarkers;
diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerManagerImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerManagerImpl.java
index 2e6f91d43924..6ef4ca6a1252 100644
--- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerManagerImpl.java
+++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/XDebuggerManagerImpl.java
@@ -24,7 +24,11 @@ import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.runners.ProgramRunner;
import com.intellij.execution.runners.RunContentBuilder;
-import com.intellij.execution.ui.*;
+import com.intellij.execution.ui.ExecutionConsole;
+import com.intellij.execution.ui.RunContentDescriptor;
+import com.intellij.execution.ui.RunContentManager;
+import com.intellij.execution.ui.RunContentWithExecutorListener;
+import com.intellij.ide.DataManager;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.*;
@@ -49,7 +53,6 @@ import com.intellij.xdebugger.impl.settings.XDebuggerSettingsManager;
import com.intellij.xdebugger.impl.ui.ExecutionPointHighlighter;
import com.intellij.xdebugger.impl.ui.XDebugSessionData;
import com.intellij.xdebugger.impl.ui.XDebugSessionTab;
-import gnu.trove.THashMap;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -70,8 +73,6 @@ public class XDebuggerManagerImpl extends XDebuggerManager
private final Project myProject;
private final XBreakpointManagerImpl myBreakpointManager;
private final XDebuggerWatchesManager myWatchesManager;
- private final Map<RunContentDescriptor, XDebugSessionData> mySessionData;
- private final Map<RunContentDescriptor, XDebugSessionTab> mySessionTabs;
private final Map<ProcessHandler, XDebugSessionImpl> mySessions;
private final ExecutionPointHighlighter myExecutionPointHighlighter;
private XDebugSessionImpl myActiveSession;
@@ -80,8 +81,6 @@ public class XDebuggerManagerImpl extends XDebuggerManager
myProject = project;
myBreakpointManager = new XBreakpointManagerImpl(project, this, startupManager);
myWatchesManager = new XDebuggerWatchesManager();
- mySessionData = new THashMap<RunContentDescriptor, XDebugSessionData>();
- mySessionTabs = new THashMap<RunContentDescriptor, XDebugSessionTab>();
mySessions = new LinkedHashMap<ProcessHandler, XDebugSessionImpl>();
myExecutionPointHighlighter = new ExecutionPointHighlighter(project);
@@ -135,11 +134,6 @@ public class XDebuggerManagerImpl extends XDebuggerManager
public void contentRemoved(@Nullable RunContentDescriptor descriptor, @NotNull Executor executor) {
if (descriptor != null && executor.equals(DefaultDebugExecutor.getDebugExecutorInstance())) {
mySessions.remove(descriptor.getProcessHandler());
- mySessionData.remove(descriptor);
- XDebugSessionTab tab = mySessionTabs.remove(descriptor);
- if (tab != null) {
- Disposer.dispose(tab);
- }
}
}
});
@@ -218,7 +212,13 @@ public class XDebuggerManagerImpl extends XDebuggerManager
XDebugProcess process = processStarter.start(session);
myProject.getMessageBus().syncPublisher(TOPIC).processStarted(process);
- XDebugSessionData oldSessionData = contentToReuse != null ? mySessionData.get(contentToReuse) : null;
+ XDebugSessionData oldSessionData = null;
+ if (contentToReuse != null) {
+ JComponent component = contentToReuse.getComponent();
+ if (component != null) {
+ oldSessionData = XDebugSessionData.DATA_KEY.getData(DataManager.getInstance().getDataContext(component));
+ }
+ }
if (oldSessionData == null) {
oldSessionData = new XDebugSessionData(session.getWatchExpressions());
}
@@ -240,21 +240,17 @@ public class XDebuggerManagerImpl extends XDebuggerManager
XDebugSessionTab sessionTab = session.getSessionTab();
mySessions.remove(session.getDebugProcess().getProcessHandler());
if (sessionTab != null) {
- final RunContentDescriptor descriptor = sessionTab.getRunContentDescriptor();
- mySessionData.put(descriptor, session.getSessionData());
- mySessionTabs.put(descriptor, sessionTab);
-
- // in test-mode RunContentWithExecutorListener.contentRemoved events are not sent (see RunContentManagerImpl.showRunContent)
- // so we make sure the mySessions and mySessionData are cleared correctly when session is disposed
-
- Disposer.register(sessionTab, new Disposable() {
- @Override
- public void dispose() {
- mySessionData.remove(descriptor);
- mySessionTabs.remove(descriptor);
- mySessions.remove(session.getDebugProcess().getProcessHandler());
- }
- });
+ RunContentDescriptor descriptor = sessionTab.getRunContentDescriptor();
+ if (descriptor != null) {
+ // in test-mode RunContentWithExecutorListener.contentRemoved events are not sent (see RunContentManagerImpl.showRunContent)
+ // so we make sure the mySessions and mySessionData are cleared correctly when session is disposed
+ Disposer.register(descriptor, new Disposable() {
+ @Override
+ public void dispose() {
+ mySessions.remove(session.getDebugProcess().getProcessHandler());
+ }
+ });
+ }
if (!myProject.isDisposed() && !ApplicationManager.getApplication().isUnitTestMode() && XDebuggerSettingsManager.getInstanceImpl().getGeneralSettings().isHideDebuggerOnProcessTermination()) {
ExecutionManager.getInstance(myProject).getContentManager().hideRunContent(DefaultDebugExecutor.getDebugExecutorInstance(), descriptor);
diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XMarkObjectActionHandler.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XMarkObjectActionHandler.java
index c3a9b9842661..c83b07fa09ff 100644
--- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XMarkObjectActionHandler.java
+++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/actions/handlers/XMarkObjectActionHandler.java
@@ -30,6 +30,8 @@ import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import static com.intellij.openapi.actionSystem.PlatformDataKeys.CONTEXT_COMPONENT;
+
/**
* @author nik
*/
@@ -49,7 +51,7 @@ public class XMarkObjectActionHandler extends MarkObjectActionHandler {
markers.unmarkValue(value);
}
else {
- ValueMarkerPresentationDialog dialog = new ValueMarkerPresentationDialog(node.getName());
+ ValueMarkerPresentationDialog dialog = new ValueMarkerPresentationDialog(event.getData(CONTEXT_COMPONENT), node.getName());
dialog.show();
ValueMarkup markup = dialog.getConfiguredMarkup();
if (dialog.isOK() && markup != null) {
diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEditorLinePainter.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEditorLinePainter.java
index e73564095b21..b9a58844585a 100644
--- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEditorLinePainter.java
+++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEditorLinePainter.java
@@ -18,6 +18,7 @@ package com.intellij.xdebugger.impl.evaluate;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.EditorLinePainter;
import com.intellij.openapi.editor.LineExtensionInfo;
+import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
@@ -25,10 +26,8 @@ import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.ui.Gray;
-import com.intellij.ui.JBColor;
-import com.intellij.ui.SimpleColoredText;
-import com.intellij.ui.SimpleTextAttributes;
+import com.intellij.ui.*;
+import com.intellij.util.NotNullProducer;
import com.intellij.xdebugger.XDebugSession;
import com.intellij.xdebugger.XSourcePosition;
import com.intellij.xdebugger.frame.presentation.XValuePresentation;
@@ -142,12 +141,33 @@ public class XDebuggerEditorLinePainter extends EditorLinePainter {
return -1;
}
+ private static boolean isDarkEditor() {
+ Color bg = EditorColorsManager.getInstance().getGlobalScheme().getDefaultBackground();
+ return ColorUtil.isDark(bg);
+ }
+
public static JBColor getForeground() {
- return new JBColor(new Color(61, 128, 101), new Color(61, 128, 101));
+ return new JBColor(new NotNullProducer<Color>() {
+ @SuppressWarnings("UseJBColor")
+ @NotNull
+ @Override
+ public Color produce() {
+ return isDarkEditor() ? Registry.getColor("ide.debugger.inline.dark.fg.color", new Color(0x3d8065))
+ : Registry.getColor("ide.debugger.inline.fg.color", new Color(0x3d8065));
+ }
+ });
}
public static JBColor getChangedForeground() {
- return new JBColor(new Color(202, 128, 33), new Color(161, 131, 10));
+ return new JBColor(new NotNullProducer<Color>() {
+ @SuppressWarnings("UseJBColor")
+ @NotNull
+ @Override
+ public Color produce() {
+ return isDarkEditor() ? Registry.getColor("ide.debugger.inline.dark.fg.modified.color", new Color(0xa1830a))
+ : Registry.getColor("ide.debugger.inline.fg.modified.color", new Color(0xca8021));
+ }
+ });
}
static class Variable {
diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEvaluationDialog.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEvaluationDialog.java
index 74b3b5202dbd..5a6d19de3234 100644
--- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEvaluationDialog.java
+++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/XDebuggerEvaluationDialog.java
@@ -295,7 +295,7 @@ public class XDebuggerEvaluationDialog extends DialogWrapper {
evaluationCallback.errorOccurred(XDebuggerBundle.message("xdebugger.evaluate.stack.frame.has.not.evaluator"));
}
else {
- evaluator.evaluate(expression, evaluationCallback, null, inputEditor.getMode());
+ evaluator.evaluate(expression, evaluationCallback, null);
}
}
diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/XValueHint.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/XValueHint.java
index ca78932701d2..37b641e1042e 100644
--- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/XValueHint.java
+++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/XValueHint.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,15 +20,23 @@ import com.intellij.execution.console.LanguageConsoleImpl;
import com.intellij.execution.console.LanguageConsoleView;
import com.intellij.execution.impl.ConsoleViewImpl;
import com.intellij.execution.ui.ConsoleView;
+import com.intellij.openapi.Disposable;
+import com.intellij.openapi.actionSystem.ActionManager;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.ShortcutSet;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.keymap.KeymapUtil;
+import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vcs.changes.issueLinks.LinkMouseListenerBase;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.SimpleColoredComponent;
import com.intellij.ui.SimpleColoredText;
+import com.intellij.ui.SimpleTextAttributes;
import com.intellij.util.Consumer;
import com.intellij.xdebugger.XDebugSession;
import com.intellij.xdebugger.XDebuggerUtil;
@@ -68,6 +76,8 @@ public class XValueHint extends AbstractValueHint {
private final String myExpression;
private final String myValueName;
private final @Nullable XSourcePosition myExpressionPosition;
+ private final ExpressionInfo myExpressionInfo;
+ private Disposable myDisposable;
public XValueHint(@NotNull Project project, @NotNull Editor editor, @NotNull Point point, @NotNull ValueHintType type,
@NotNull ExpressionInfo expressionInfo, @NotNull XDebuggerEvaluator evaluator,
@@ -78,6 +88,7 @@ public class XValueHint extends AbstractValueHint {
myDebugSession = session;
myExpression = XDebuggerEvaluateActionHandler.getExpressionText(expressionInfo, editor.getDocument());
myValueName = XDebuggerEvaluateActionHandler.getDisplayText(expressionInfo, editor.getDocument());
+ myExpressionInfo = expressionInfo;
VirtualFile file;
ConsoleView consoleView = ConsoleViewImpl.CONSOLE_VIEW_IN_EDITOR_VIEW.get(editor);
@@ -98,6 +109,33 @@ public class XValueHint extends AbstractValueHint {
}
@Override
+ protected boolean showHint(final JComponent component) {
+ boolean result = super.showHint(component);
+ if (result && getType() == ValueHintType.MOUSE_OVER_HINT) {
+ myDisposable = Disposer.newDisposable();
+ ShortcutSet shortcut = ActionManager.getInstance().getAction("ShowErrorDescription").getShortcutSet();
+ new DumbAwareAction() {
+ @Override
+ public void actionPerformed(@NotNull AnActionEvent e) {
+ hideHint();
+ final Point point = new Point(myPoint.x, myPoint.y + getEditor().getLineHeight());
+ new XValueHint(getProject(), getEditor(), point, ValueHintType.MOUSE_CLICK_HINT, myExpressionInfo, myEvaluator, myDebugSession).invokeHint();
+ }
+ }.registerCustomShortcutSet(shortcut, getEditor().getContentComponent(), myDisposable);
+ }
+ return result;
+ }
+
+ @Override
+ public void hideHint() {
+ super.hideHint();
+ if (myDisposable != null) {
+ Disposer.dispose(myDisposable);
+
+ }
+ }
+
+ @Override
protected void evaluateAndShowHint() {
myEvaluator.evaluate(myExpression, new XEvaluationCallbackBase() {
@Override
@@ -136,6 +174,11 @@ public class XValueHint extends AbstractValueHint {
showTree(result);
}
else {
+ if (getType() == ValueHintType.MOUSE_OVER_HINT) {
+ text.insert(0, "(" + KeymapUtil.getFirstKeyboardShortcutText("ShowErrorDescription") + ") ",
+ SimpleTextAttributes.GRAYED_ATTRIBUTES);
+ }
+
JComponent component = createExpandableHintComponent(text, new Runnable() {
@Override
public void run() {
diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/common/AbstractValueHint.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/common/AbstractValueHint.java
index 7b860b49d255..c24ce74df1c6 100644
--- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/common/AbstractValueHint.java
+++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/common/AbstractValueHint.java
@@ -65,7 +65,7 @@ public abstract class AbstractValueHint {
private final Project myProject;
private final Editor myEditor;
private final ValueHintType myType;
- private final Point myPoint;
+ protected final Point myPoint;
private LightweightHint myCurrentHint;
private boolean myHintHidden;
private TextRange myCurrentRange;
@@ -132,6 +132,10 @@ public abstract class AbstractValueHint {
}
}
+ public void invokeHint() {
+ invokeHint(null);
+ }
+
public void invokeHint(Runnable hideRunnable) {
myHideRunnable = hideRunnable;
diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/common/DebuggerTreeWithHistoryContainer.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/common/DebuggerTreeWithHistoryContainer.java
index c7c5af9f6fb4..2851c701ef70 100644
--- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/common/DebuggerTreeWithHistoryContainer.java
+++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/common/DebuggerTreeWithHistoryContainer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -170,7 +170,7 @@ abstract class DebuggerTreeWithHistoryContainer<D> {
}
@Override
- public void onFailure(Throwable t) {
+ public void onFailure(@NotNull Throwable t) {
LOG.debug(t);
}
});
diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/common/DebuggerTreeWithHistoryPopup.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/common/DebuggerTreeWithHistoryPopup.java
index e4ea46b69ea9..97edec9133ba 100644
--- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/common/DebuggerTreeWithHistoryPopup.java
+++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/evaluate/quick/common/DebuggerTreeWithHistoryPopup.java
@@ -20,6 +20,7 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.ui.popup.JBPopupFactory;
+import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Disposer;
import com.intellij.ui.ScreenUtil;
import com.intellij.ui.awt.RelativePoint;
@@ -64,7 +65,7 @@ class DebuggerTreeWithHistoryPopup<D> extends DebuggerTreeWithHistoryContainer<D
}
@Override
- protected void updateContainer(Tree tree, String title) {
+ protected void updateContainer(final Tree tree, String title) {
if (myPopup != null) {
myPopup.cancel();
}
@@ -75,6 +76,21 @@ class DebuggerTreeWithHistoryPopup<D> extends DebuggerTreeWithHistoryContainer<D
.setResizable(true)
.setMovable(true)
.setDimensionServiceKey(myProject, DIMENSION_SERVICE_KEY, false)
+ .setMayBeParent(true)
+ .setCancelCallback(new Computable<Boolean>() {
+ @Override
+ public Boolean compute() {
+ Window parent = SwingUtilities.getWindowAncestor(tree);
+ if (parent != null) {
+ for (Window child : parent.getOwnedWindows()) {
+ if (child.isShowing()) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+ })
.createPopup();
if (tree instanceof Disposable) {
diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/WatchInplaceEditor.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/WatchInplaceEditor.java
index 683c27e30e18..00ceef568c21 100644
--- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/WatchInplaceEditor.java
+++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/WatchInplaceEditor.java
@@ -39,7 +39,7 @@ public class WatchInplaceEditor extends XDebuggerTreeInplaceEditor {
@Nullable private final WatchNode myOldNode;
public WatchInplaceEditor(@NotNull WatchesRootNode rootNode,
- @NotNull XDebugSession session, XWatchesView watchesView, final WatchNode node,
+ @Nullable XDebugSession session, XWatchesView watchesView, final WatchNode node,
@NonNls final String historyId,
final @Nullable WatchNode oldNode) {
super((XDebuggerTreeNode)node, historyId);
@@ -47,7 +47,9 @@ public class WatchInplaceEditor extends XDebuggerTreeInplaceEditor {
myWatchesView = watchesView;
myOldNode = oldNode;
myExpressionEditor.setExpression(oldNode != null ? oldNode.getExpression() : null);
- new WatchEditorSessionListener(session).install();
+ if (session != null) {
+ new WatchEditorSessionListener(session).install();
+ }
}
@Override
diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XDebugView.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XDebugView.java
index 0007ec2f9997..847dd9004a49 100644
--- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XDebugView.java
+++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XDebugView.java
@@ -19,6 +19,7 @@ import com.intellij.execution.ui.layout.ViewContext;
import com.intellij.ide.DataManager;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.actionSystem.DataKey;
import com.intellij.ui.content.ContentManager;
import com.intellij.util.SingleAlarm;
import com.intellij.xdebugger.XDebugSession;
@@ -66,15 +67,20 @@ public abstract class XDebugView implements Disposable {
@Nullable
public static XDebugSession getSession(@NotNull Component component) {
+ return getData(XDebugSession.DATA_KEY, component);
+ }
+
+ @Nullable
+ public static <T> T getData(DataKey<T> key, @NotNull Component component) {
DataContext dataContext = DataManager.getInstance().getDataContext(component);
ViewContext viewContext = ViewContext.CONTEXT_KEY.getData(dataContext);
ContentManager contentManager = viewContext == null ? null : viewContext.getContentManager();
if (contentManager != null) {
- XDebugSession session = XDebugSession.DATA_KEY.getData(DataManager.getInstance().getDataContext(contentManager.getComponent()));
- if (session != null) {
- return session;
+ T data = key.getData(DataManager.getInstance().getDataContext(contentManager.getComponent()));
+ if (data != null) {
+ return data;
}
}
- return XDebugSession.DATA_KEY.getData(dataContext);
+ return key.getData(dataContext);
}
}
diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XDebugViewSessionListener.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XDebugViewSessionListener.java
index d790113b1816..f124078f5a57 100644
--- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XDebugViewSessionListener.java
+++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XDebugViewSessionListener.java
@@ -16,7 +16,6 @@
package com.intellij.xdebugger.impl.frame;
import com.intellij.ui.AppUIUtil;
-import com.intellij.xdebugger.XDebugSession;
import com.intellij.xdebugger.XDebugSessionAdapter;
import org.jetbrains.annotations.NotNull;
@@ -25,15 +24,13 @@ import org.jetbrains.annotations.NotNull;
*/
public class XDebugViewSessionListener extends XDebugSessionAdapter {
private final XDebugView myDebugView;
- private final XDebugSession session;
- public XDebugViewSessionListener(@NotNull XDebugView debugView, @NotNull XDebugSession session) {
+ public XDebugViewSessionListener(@NotNull XDebugView debugView) {
myDebugView = debugView;
- this.session = session;
}
private void onSessionEvent(final @NotNull XDebugView.SessionEvent event) {
- AppUIUtil.invokeLaterIfProjectAlive(session.getProject(), new Runnable() {
+ AppUIUtil.invokeOnEdt(new Runnable() {
@Override
public void run() {
myDebugView.processSessionEvent(event);
diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XDebuggerFramesList.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XDebuggerFramesList.java
index 9b39ad63deb8..63a1cfeea6af 100644
--- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XDebuggerFramesList.java
+++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XDebuggerFramesList.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
*/
package com.intellij.xdebugger.impl.frame;
+import com.intellij.openapi.actionSystem.CommonDataKeys;
+import com.intellij.openapi.actionSystem.DataProvider;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
@@ -27,7 +29,9 @@ import com.intellij.util.ui.UIUtil;
import com.intellij.xdebugger.XDebuggerBundle;
import com.intellij.xdebugger.XSourcePosition;
import com.intellij.xdebugger.frame.XStackFrame;
+import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
@@ -78,7 +82,7 @@ public class XDebuggerFramesList extends DebuggerFramesList {
}
@Override
- public int getSourceActions(JComponent c) {
+ public int getSourceActions(@NotNull JComponent c) {
return COPY;
}
};
@@ -90,6 +94,17 @@ public class XDebuggerFramesList extends DebuggerFramesList {
doInit();
setTransferHandler(DEFAULT_TRANSFER_HANDLER);
+ setDataProvider(new DataProvider() {
+ @Nullable
+ @Override
+ public Object getData(@NonNls String dataId) {
+ if (CommonDataKeys.VIRTUAL_FILE.is(dataId) && mySelectedFrame != null) {
+ XSourcePosition position = mySelectedFrame.getSourcePosition();
+ return position != null ? position.getFile() : null;
+ }
+ return null;
+ }
+ });
}
@Override
diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XFramesView.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XFramesView.java
index 9999ac015b77..cd1fee38b074 100644
--- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XFramesView.java
+++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XFramesView.java
@@ -61,6 +61,7 @@ public class XFramesView extends XDebugView {
private final ComboBox myThreadComboBox;
private final Set<XExecutionStack> myExecutionStacks = ContainerUtil.newHashSet();
private XExecutionStack mySelectedStack;
+ private int mySelectedFrameIndex;
private boolean myListenersEnabled;
private final Map<XExecutionStack, StackFramesListBuilder> myBuilders = new HashMap<XExecutionStack, StackFramesListBuilder>();
private final ActionToolbarImpl myToolbar;
@@ -76,7 +77,7 @@ public class XFramesView extends XDebugView {
@Override
public void valueChanged(ListSelectionEvent e) {
if (myListenersEnabled && !e.getValueIsAdjusting()) {
- processFrameSelection(e);
+ processFrameSelection(getSession(e));
}
}
});
@@ -86,7 +87,7 @@ public class XFramesView extends XDebugView {
if (myListenersEnabled) {
int i = myFramesList.locationToIndex(e.getPoint());
if (i != -1 && myFramesList.isSelectedIndex(i)) {
- processFrameSelection(e);
+ processFrameSelection(getSession(e));
}
}
}
@@ -115,9 +116,10 @@ public class XFramesView extends XDebugView {
if (e.getStateChange() == ItemEvent.SELECTED) {
Object item = e.getItem();
- if (item instanceof XExecutionStack) {
+ if (item != mySelectedStack && item instanceof XExecutionStack) {
XDebugSession session = getSession(e);
if (session != null) {
+ mySelectedFrameIndex = 0;
updateFrames((XExecutionStack)item, session);
}
}
@@ -209,16 +211,21 @@ public class XFramesView extends XDebugView {
XStackFrame currentStackFrame = session == null ? null : session.getCurrentStackFrame();
if (currentStackFrame != null) {
myFramesList.setSelectedValue(currentStackFrame, true);
+ mySelectedFrameIndex = myFramesList.getSelectedIndex();
}
return;
}
+ if (event != SessionEvent.SETTINGS_CHANGED) {
+ mySelectedFrameIndex = 0;
+ mySelectedStack = null;
+ }
+
myListenersEnabled = false;
for (StackFramesListBuilder builder : myBuilders.values()) {
builder.dispose();
}
myBuilders.clear();
- mySelectedStack = null;
XSuspendContext suspendContext = session == null ? null : session.getSuspendContext();
if (suspendContext == null) {
requestClear();
@@ -234,7 +241,7 @@ public class XFramesView extends XDebugView {
XExecutionStack[] executionStacks = suspendContext.getExecutionStacks();
addExecutionStacks(Arrays.asList(executionStacks));
- XExecutionStack activeExecutionStack = suspendContext.getActiveExecutionStack();
+ XExecutionStack activeExecutionStack = mySelectedStack != null ? mySelectedStack : suspendContext.getActiveExecutionStack();
myThreadComboBox.setSelectedItem(activeExecutionStack);
myThreadsPanel.removeAll();
myThreadsPanel.add(myToolbar.getComponent(), BorderLayout.EAST);
@@ -265,9 +272,6 @@ public class XFramesView extends XDebugView {
}
private void updateFrames(final XExecutionStack executionStack, @NotNull XDebugSession session) {
- if (mySelectedStack == executionStack) {
- return;
- }
if (mySelectedStack != null) {
getOrCreateBuilder(mySelectedStack, session).stop();
}
@@ -275,6 +279,7 @@ public class XFramesView extends XDebugView {
mySelectedStack = executionStack;
if (executionStack != null) {
StackFramesListBuilder builder = getOrCreateBuilder(executionStack, session);
+ myListenersEnabled = false;
builder.initModel(myFramesList.getModel());
builder.start();
}
@@ -292,12 +297,12 @@ public class XFramesView extends XDebugView {
return myMainPanel;
}
- private void processFrameSelection(@NotNull EventObject e) {
+ private void processFrameSelection(XDebugSession session) {
+ mySelectedFrameIndex = myFramesList.getSelectedIndex();
Object selected = myFramesList.getSelectedValue();
if (selected instanceof XStackFrame) {
- XDebugSession session = getSession(e);
if (session != null) {
- session.setCurrentStackFrame(mySelectedStack, (XStackFrame)selected, myFramesList.getSelectedIndex() == 0);
+ session.setCurrentStackFrame(mySelectedStack, (XStackFrame)selected, mySelectedFrameIndex == 0);
}
}
}
@@ -324,9 +329,7 @@ public class XFramesView extends XDebugView {
public void run() {
myStackFrames.addAll(stackFrames);
addFrameListElements(stackFrames, last);
- if (myNextFrameIndex == 0) {
- selectTopFrame();
- }
+ selectCurrentFrame();
myNextFrameIndex += stackFrames.size();
myAllFramesLoaded = last;
if (last) {
@@ -390,11 +393,13 @@ public class XFramesView extends XDebugView {
myRunning = false;
}
- private void selectTopFrame() {
- if (!myStackFrames.isEmpty() && mySelectedStack != null) {
- XStackFrame topFrame = myStackFrames.get(0);
- myFramesList.setSelectedValue(topFrame, true);
- mySession.setCurrentStackFrame(mySelectedStack, topFrame, true);
+ private void selectCurrentFrame() {
+ if (mySelectedStack != null &&
+ myFramesList.getSelectedIndex() != mySelectedFrameIndex &&
+ myFramesList.getElementCount() > mySelectedFrameIndex &&
+ myFramesList.getModel().get(mySelectedFrameIndex) != null) {
+ myFramesList.setSelectedIndex(mySelectedFrameIndex);
+ processFrameSelection(mySession);
myListenersEnabled = true;
}
}
@@ -411,7 +416,7 @@ public class XFramesView extends XDebugView {
else if (!myAllFramesLoaded) {
model.addElement(null);
}
- selectTopFrame();
+ selectCurrentFrame();
}
}
}
diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XVariablesViewBase.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XVariablesViewBase.java
index d4bd27c30d9b..4bfcfa58855f 100644
--- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XVariablesViewBase.java
+++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XVariablesViewBase.java
@@ -15,34 +15,34 @@
*/
package com.intellij.xdebugger.impl.frame;
-import com.intellij.codeInsight.hint.HintManager;
-import com.intellij.codeInsight.hint.HintUtil;
import com.intellij.ide.dnd.DnDManager;
-import com.intellij.openapi.Disposable;
+import com.intellij.openapi.application.AccessToken;
+import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.editor.LogicalPosition;
import com.intellij.openapi.editor.event.SelectionEvent;
import com.intellij.openapi.editor.event.SelectionListener;
+import com.intellij.openapi.editor.impl.SelectionModelImpl;
import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx;
import com.intellij.openapi.fileEditor.impl.text.PsiAwareTextEditorImpl;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.ui.SimpleColoredComponent;
-import com.intellij.ui.SimpleColoredText;
+import com.intellij.xdebugger.XDebugSession;
import com.intellij.xdebugger.XDebuggerBundle;
import com.intellij.xdebugger.XSourcePosition;
+import com.intellij.xdebugger.evaluation.ExpressionInfo;
import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider;
import com.intellij.xdebugger.evaluation.XDebuggerEvaluator;
-import com.intellij.xdebugger.frame.XFullValueEvaluator;
import com.intellij.xdebugger.frame.XStackFrame;
import com.intellij.xdebugger.frame.XValue;
-import com.intellij.xdebugger.frame.XValuePlace;
-import com.intellij.xdebugger.frame.presentation.XValuePresentation;
import com.intellij.xdebugger.impl.actions.XDebuggerActions;
+import com.intellij.xdebugger.impl.evaluate.quick.XValueHint;
+import com.intellij.xdebugger.impl.evaluate.quick.common.ValueHintType;
import com.intellij.xdebugger.impl.ui.tree.XDebuggerTree;
import com.intellij.xdebugger.impl.ui.tree.XDebuggerTreePanel;
import com.intellij.xdebugger.impl.ui.tree.XDebuggerTreeRestorer;
@@ -50,11 +50,11 @@ import com.intellij.xdebugger.impl.ui.tree.XDebuggerTreeState;
import com.intellij.xdebugger.impl.ui.tree.nodes.XEvaluationCallbackBase;
import com.intellij.xdebugger.impl.ui.tree.nodes.XStackFrameNode;
import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodeImpl;
-import com.intellij.xdebugger.impl.ui.tree.nodes.XValueNodePresentationConfigurator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
+import java.awt.*;
import java.util.HashMap;
import java.util.Set;
@@ -88,68 +88,53 @@ public abstract class XVariablesViewBase extends XDebugView {
myTreeRestorer = myTreeState.restoreState(tree);
}
if (position != null && Registry.is("ide.debugger.inline")) {
- final VirtualFile file = position.getFile();
- final FileEditor fileEditor = FileEditorManagerEx.getInstanceEx(project).getSelectedEditor(file);
- if (fileEditor instanceof PsiAwareTextEditorImpl) {
- final Editor editor = ((PsiAwareTextEditorImpl)fileEditor).getEditor();
- final SelectionListener listener = new SelectionListener() {
- @Override
- public void selectionChanged(SelectionEvent e) {
- final String text = editor.getDocument().getText(e.getNewRange());
- final XDebuggerEvaluator evaluator = stackFrame.getEvaluator();
- if (evaluator != null && !StringUtil.isEmpty(text)
- && !(text.contains("exec(") || text.contains("++") || text.contains("--") || text.contains("="))) {
- evaluator.evaluate(text, new XEvaluationCallbackBase() {
- @Override
- public void evaluated(@NotNull XValue result) {
- result.computePresentation(new XValueNodePresentationConfigurator.ConfigurableXValueNodeImpl() {
- @Override
- public void applyPresentation(@Nullable Icon icon,
- @NotNull XValuePresentation valuePresenter,
- boolean hasChildren) {
- SimpleColoredText text = new SimpleColoredText();
- XValueNodeImpl.buildText(valuePresenter, text, false);
- SimpleColoredComponent component = HintUtil.createInformationComponent();
- text.appendToComponent(component);
- String str = text.toString();
- if ("undefined".equals(str) || str.startsWith("Cannot find local variable")
- || str.startsWith("Invalid expression")) {
- return; //todo[kb] this is temporary solution
- }
- HintManager.getInstance().hideAllHints();
- HintManager.getInstance().showInformationHint(editor, component);
- }
+ registerInlineEvaluator(stackFrame, tree, position, project);
+ }
+ }
- @Override
- public void setFullValueEvaluator(@NotNull XFullValueEvaluator fullValueEvaluator) {
- }
+ private void registerInlineEvaluator(final XStackFrame stackFrame,
+ XDebuggerTree tree,
+ final XSourcePosition position,
+ final Project project) {
+ final VirtualFile file = position.getFile();
+ final FileEditor fileEditor = FileEditorManagerEx.getInstanceEx(project).getSelectedEditor(file);
+ if (fileEditor instanceof PsiAwareTextEditorImpl) {
+ final Editor editor = ((PsiAwareTextEditorImpl)fileEditor).getEditor();
+ final SelectionListener listener = new SelectionListener() {
+ @Override
+ public void selectionChanged(final SelectionEvent e) {
+ final String text = editor.getDocument().getText(e.getNewRange());
+ final XDebuggerEvaluator evaluator = stackFrame.getEvaluator();
+ if (evaluator != null && !StringUtil.isEmpty(text)
+ && !(text.contains("exec(") || text.contains("++") || text.contains("--") || text.contains("="))) {
+ evaluator.evaluate(text, new XEvaluationCallbackBase() {
+ @Override
+ public void evaluated(@NotNull XValue result) {
+ final AccessToken token = ApplicationManager.getApplication().acquireReadActionLock();
+ try {
+ final XDebugSession session = getSession(getTree());
+ if (session == null) return;
+ final TextRange range = e.getNewRange();
+ final ExpressionInfo info = new ExpressionInfo(range);
+ final int offset = range.getStartOffset();
+ final LogicalPosition pos = editor.offsetToLogicalPosition(offset);
+ final Point point = editor.logicalPositionToXY(pos);
- @Override
- public boolean isObsolete() {
- return true;
- }
- }, XValuePlace.TOOLTIP);
+ new XValueHint(project, editor, point, ValueHintType.MOUSE_OVER_HINT, info, evaluator, session).invokeHint();
}
-
- @Override
- public void errorOccurred(@NotNull String errorMessage) {
- System.out.println(errorMessage);
+ finally {
+ token.finish();
}
- }, position);
- }
- }
- };
- editor.getSelectionModel().addSelectionListener(listener);
- Disposer.register(tree, new Disposable() {
- @Override
- public void dispose() {
- final FileEditor fileEditor = FileEditorManagerEx.getInstanceEx(project).getSelectedEditor(file);
- if (fileEditor instanceof PsiAwareTextEditorImpl) {
- ((PsiAwareTextEditorImpl)fileEditor).getEditor().getSelectionModel().removeSelectionListener(listener);
- }
+ }
+
+ @Override
+ public void errorOccurred(@NotNull String errorMessage) {
+ }
+ }, position);
}
- });
- }
+ }
+ };
+ ((SelectionModelImpl)editor.getSelectionModel()).addSelectionListener(listener, tree);
}
}
diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XWatchesViewImpl.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XWatchesViewImpl.java
index c510cd17c90a..8b94e2c4858a 100644
--- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XWatchesViewImpl.java
+++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/frame/XWatchesViewImpl.java
@@ -40,6 +40,7 @@ import com.intellij.xdebugger.frame.XStackFrame;
import com.intellij.xdebugger.impl.XDebugSessionImpl;
import com.intellij.xdebugger.impl.actions.XDebuggerActions;
import com.intellij.xdebugger.impl.breakpoints.XExpressionImpl;
+import com.intellij.xdebugger.impl.ui.XDebugSessionData;
import com.intellij.xdebugger.impl.ui.XDebugSessionTab;
import com.intellij.xdebugger.impl.ui.tree.XDebuggerTree;
import com.intellij.xdebugger.impl.ui.tree.XDebuggerTreePanel;
@@ -220,13 +221,9 @@ public class XWatchesViewImpl extends XDebugView implements DnDNativeTarget, XWa
@Override
public void addWatchExpression(@NotNull XExpression expression, int index, final boolean navigateToWatchNode) {
XDebugSession session = getSession(getTree());
- if (session == null) {
- return;
- }
-
- myRootNode.addWatchExpression(session.getDebugProcess().getEvaluator(), expression, index, navigateToWatchNode);
+ myRootNode.addWatchExpression(session != null ? session.getDebugProcess().getEvaluator() : null, expression, index, navigateToWatchNode);
updateSessionData();
- if (navigateToWatchNode) {
+ if (navigateToWatchNode && session != null) {
showWatchesTab((XDebugSessionImpl)session);
}
}
@@ -342,8 +339,15 @@ public class XWatchesViewImpl extends XDebugView implements DnDNativeTarget, XWa
}
XDebugSession session = getSession(getTree());
+ XExpression[] expressions = watchExpressions.toArray(new XExpression[watchExpressions.size()]);
if (session != null) {
- ((XDebugSessionImpl)session).setWatchExpressions(watchExpressions.toArray(new XExpression[watchExpressions.size()]));
+ ((XDebugSessionImpl)session).setWatchExpressions(expressions);
+ }
+ else {
+ XDebugSessionData data = getData(XDebugSessionData.DATA_KEY, getTree());
+ if (data != null) {
+ data.setWatchExpressions(expressions);
+ }
}
}
diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/settings/DebuggerConfigurable.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/settings/DebuggerConfigurable.java
index 58896a87f596..3d0db0abc7fb 100644
--- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/settings/DebuggerConfigurable.java
+++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/settings/DebuggerConfigurable.java
@@ -22,6 +22,7 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.xdebugger.XDebuggerBundle;
+import com.intellij.xdebugger.breakpoints.XBreakpointType;
import com.intellij.xdebugger.impl.DebuggerSupport;
import com.intellij.xdebugger.settings.DebuggerConfigurableProvider;
import com.intellij.xdebugger.settings.DebuggerSettingsCategory;
@@ -159,7 +160,7 @@ public class DebuggerConfigurable implements SearchableConfigurable.Parent {
@Override
public boolean isVisible() {
- return true;
+ return XBreakpointType.EXTENSION_POINT_NAME.getExtensions().length != 0;
}
@Override
diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/settings/DebuggerConfigurableProvider.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/settings/DebuggerConfigurableProvider.java
new file mode 100644
index 000000000000..bb747f92eab7
--- /dev/null
+++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/settings/DebuggerConfigurableProvider.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.xdebugger.impl.settings;
+
+import com.intellij.openapi.options.Configurable;
+import com.intellij.openapi.options.ConfigurableProvider;
+import com.intellij.xdebugger.breakpoints.XBreakpointType;
+import org.jetbrains.annotations.NotNull;
+
+public final class DebuggerConfigurableProvider extends ConfigurableProvider {
+ @NotNull
+ @Override
+ public Configurable createConfigurable() {
+ return new DebuggerConfigurable();
+ }
+
+ @Override
+ public boolean canCreateConfigurable() {
+ return XBreakpointType.EXTENSION_POINT_NAME.getExtensions().length != 0;
+ }
+}
diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/DebuggerSessionTabBase.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/DebuggerSessionTabBase.java
index 053f18dd14bf..2bdbb7faa80d 100644
--- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/DebuggerSessionTabBase.java
+++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/DebuggerSessionTabBase.java
@@ -16,26 +16,22 @@
package com.intellij.xdebugger.impl.ui;
import com.intellij.debugger.ui.DebuggerContentInfo;
-import com.intellij.diagnostic.logging.AdditionalTabComponent;
-import com.intellij.diagnostic.logging.DebuggerLogConsoleManager;
import com.intellij.execution.ExecutionManager;
import com.intellij.execution.configurations.RunConfigurationBase;
import com.intellij.execution.configurations.RunProfile;
import com.intellij.execution.executors.DefaultDebugExecutor;
-import com.intellij.execution.process.ProcessHandler;
-import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.runners.RunContentBuilder;
import com.intellij.execution.runners.RunTab;
-import com.intellij.execution.ui.*;
+import com.intellij.execution.ui.ConsoleViewContentType;
+import com.intellij.execution.ui.ExecutionConsole;
+import com.intellij.execution.ui.ObservableConsoleView;
import com.intellij.execution.ui.layout.LayoutAttractionPolicy;
import com.intellij.execution.ui.layout.LayoutViewOptions;
-import com.intellij.icons.AllIcons;
import com.intellij.ide.impl.ProjectUtil;
import com.intellij.ide.ui.customization.CustomActionsSchema;
import com.intellij.openapi.actionSystem.ActionGroup;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.ui.AppIcon;
@@ -44,20 +40,17 @@ import com.intellij.xdebugger.XDebuggerBundle;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import javax.swing.*;
import java.util.Collection;
/**
* @author nik
*/
-public abstract class DebuggerSessionTabBase extends RunTab implements DebuggerLogConsoleManager {
+public abstract class DebuggerSessionTabBase extends RunTab {
protected ExecutionConsole myConsole;
public DebuggerSessionTabBase(@NotNull Project project, @NotNull String runnerId, @NotNull String sessionName, @NotNull GlobalSearchScope searchScope) {
super(project, searchScope, runnerId, XDebuggerBundle.message("xdebugger.default.content.title"), sessionName);
- Disposer.register(project, this);
-
myUi.getDefaults()
.initTabDefaults(0, XDebuggerBundle.message("xdebugger.debugger.tab.title"), null)
.initFocusContent(DebuggerContentInfo.FRAME_CONTENT, XDebuggerUIConstants.LAYOUT_VIEW_BREAKPOINT_CONDITION)
@@ -68,32 +61,6 @@ public abstract class DebuggerSessionTabBase extends RunTab implements DebuggerL
return (ActionGroup)CustomActionsSchema.getInstance().getCorrectedAction(id);
}
- public abstract RunContentDescriptor getRunContentDescriptor();
-
- @Override
- public ProcessHandler getProcessHandler() {
- return getRunContentDescriptor().getProcessHandler();
- }
-
- @Override
- protected Content createLogContent(AdditionalTabComponent tabComponent, String id, Icon icon) {
- Content result = super.createLogContent(tabComponent, id, icon);
- result.setCloseable(false);
- result.setDescription(tabComponent.getTooltip());
- return result;
- }
-
- @Override
- protected Icon getDefaultIcon() {
- return AllIcons.FileTypes.Text;
- }
-
- @Override
- @NotNull
- public RunnerLayoutUi getUi() {
- return myUi;
- }
-
protected void attachNotificationTo(final Content content) {
if (myConsole instanceof ObservableConsoleView) {
ObservableConsoleView observable = (ObservableConsoleView)myConsole;
@@ -107,12 +74,11 @@ public abstract class DebuggerSessionTabBase extends RunTab implements DebuggerL
}, content);
RunProfile profile = getRunProfile();
if (profile instanceof RunConfigurationBase && !ApplicationManager.getApplication().isUnitTestMode()) {
- final RunConfigurationBase runConfigurationBase = (RunConfigurationBase)profile;
- observable.addChangeListener(new RunContentBuilder.ConsoleToFrontListener(runConfigurationBase,
- getProject(),
+ observable.addChangeListener(new RunContentBuilder.ConsoleToFrontListener((RunConfigurationBase)profile,
+ myProject,
DefaultDebugExecutor.getDebugExecutorInstance(),
myRunContentDescriptor,
- getUi()),
+ myUi),
content);
}
}
@@ -120,21 +86,20 @@ public abstract class DebuggerSessionTabBase extends RunTab implements DebuggerL
@Nullable
protected RunProfile getRunProfile() {
- ExecutionEnvironment environment = getEnvironment();
- return environment != null ? environment.getRunProfile() : null;
+ return myEnvironment != null ? myEnvironment.getRunProfile() : null;
}
public void toFront(boolean focus) {
if (!ApplicationManager.getApplication().isUnitTestMode()) {
- ExecutionManager.getInstance(getProject()).getContentManager().toFrontRunContent(DefaultDebugExecutor.getDebugExecutorInstance(), myRunContentDescriptor);
+ ExecutionManager.getInstance(myProject).getContentManager().toFrontRunContent(DefaultDebugExecutor.getDebugExecutorInstance(), myRunContentDescriptor);
if (focus) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
boolean focusWnd = Registry.is("debugger.mayBringFrameToFrontOnBreakpoint");
- ProjectUtil.focusProjectWindow(getProject(), focusWnd);
+ ProjectUtil.focusProjectWindow(myProject, focusWnd);
if (!focusWnd) {
- AppIcon.getInstance().requestAttention(getProject(), true);
+ AppIcon.getInstance().requestAttention(myProject, true);
}
}
});
diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java
index 1a4505f6d85b..881ed56bad3d 100644
--- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java
+++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/XDebugSessionTab.java
@@ -20,8 +20,8 @@ import com.intellij.execution.Executor;
import com.intellij.execution.executors.DefaultDebugExecutor;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.runners.RunContentBuilder;
-import com.intellij.execution.ui.ExecutionConsole;
import com.intellij.execution.ui.RunContentDescriptor;
+import com.intellij.execution.ui.RunnerLayoutUi;
import com.intellij.execution.ui.actions.CloseAction;
import com.intellij.execution.ui.layout.PlaceInGrid;
import com.intellij.execution.ui.layout.impl.ViewImpl;
@@ -83,6 +83,11 @@ public class XDebugSessionTab extends DebuggerSessionTabBase {
return new XDebugSessionTab(session, icon, environment);
}
+ @NotNull
+ public RunnerLayoutUi getUi() {
+ return myUi;
+ }
+
private XDebugSessionTab(@NotNull XDebugSessionImpl session,
@Nullable Icon icon,
@Nullable ExecutionEnvironment environment) {
@@ -95,7 +100,7 @@ public class XDebugSessionTab extends DebuggerSessionTabBase {
myUi.addContent(createWatchesContent(session), 0, PlaceInGrid.right, false);
for (XDebugView view : myViews) {
- Disposer.register(this, view);
+ Disposer.register(myRunContentDescriptor, view);
}
attachToSession(session);
@@ -115,20 +120,19 @@ public class XDebugSessionTab extends DebuggerSessionTabBase {
}
}
}
- }, this);
+ }, myRunContentDescriptor);
rebuildViews();
}
private void setSession(@NotNull XDebugSessionImpl session, @Nullable ExecutionEnvironment environment, @Nullable Icon icon) {
- if (environment != null) {
- setEnvironment(environment);
- }
-
+ myEnvironment = environment;
mySession = session;
mySessionData = session.getSessionData();
myConsole = session.getConsoleView();
myRunContentDescriptor = new RunContentDescriptor(myConsole, session.getDebugProcess().getProcessHandler(), myUi.getComponent(), session.getSessionName(), icon);
+ Disposer.register(myRunContentDescriptor, this);
+ Disposer.register(myProject, myRunContentDescriptor);
}
@Nullable
@@ -180,7 +184,7 @@ public class XDebugSessionTab extends DebuggerSessionTabBase {
@NotNull
private Content createFramesContent() {
- XFramesView framesView = new XFramesView(getProject());
+ XFramesView framesView = new XFramesView(myProject);
myViews.add(framesView);
Content framesContent = myUi.createContent(DebuggerContentInfo.FRAME_CONTENT, framesView.getMainPanel(),
XDebuggerBundle.message("debugger.session.tab.frames.title"), AllIcons.Debugger.Frame, null);
@@ -188,12 +192,8 @@ public class XDebugSessionTab extends DebuggerSessionTabBase {
return framesContent;
}
- public ExecutionConsole getConsole() {
- return myConsole;
- }
-
public void rebuildViews() {
- AppUIUtil.invokeLaterIfProjectAlive(getProject(), new Runnable() {
+ AppUIUtil.invokeLaterIfProjectAlive(myProject, new Runnable() {
@Override
public void run() {
for (XDebugView view : myViews) {
@@ -209,7 +209,7 @@ public class XDebugSessionTab extends DebuggerSessionTabBase {
private void attachToSession(@NotNull XDebugSessionImpl session) {
for (XDebugView view : myViews) {
- session.addSessionListener(new XDebugViewSessionListener(view, session), this);
+ session.addSessionListener(new XDebugViewSessionListener(view), myRunContentDescriptor);
}
XDebugTabLayouter layouter = session.getDebugProcess().createTabLayouter();
@@ -225,8 +225,7 @@ public class XDebugSessionTab extends DebuggerSessionTabBase {
DefaultActionGroup leftToolbar = new DefaultActionGroup();
final Executor debugExecutor = DefaultDebugExecutor.getDebugExecutorInstance();
- ExecutionEnvironment environment = getEnvironment();
- if (environment != null) {
+ if (myEnvironment != null) {
leftToolbar.add(ActionManager.getInstance().getAction(IdeActions.ACTION_RERUN));
List<AnAction> additionalRestartActions = session.getRestartActions();
if (!additionalRestartActions.isEmpty()) {
@@ -247,24 +246,12 @@ public class XDebugSessionTab extends DebuggerSessionTabBase {
leftToolbar.add(myUi.getOptions().getLayoutActions());
final AnAction[] commonSettings = myUi.getOptions().getSettingsActionsList();
- final AnAction commonSettingsList = myUi.getOptions().getSettingsActions();
-
- final DefaultActionGroup settings = new DefaultActionGroup("DebuggerSettings", commonSettings.length > 0) {
- @Override
- public void update(AnActionEvent e) {
- e.getPresentation().setText(ActionsBundle.message("group.XDebugger.settings.text"));
- e.getPresentation().setIcon(commonSettingsList.getTemplatePresentation().getIcon());
- }
-
- @Override
- public boolean isDumbAware() {
- return true;
- }
- };
- for (AnAction each : commonSettings) {
- settings.add(each);
- }
+ DefaultActionGroup settings = new DefaultActionGroup(ActionsBundle.message("group.XDebugger.settings.text"), true);
+ settings.getTemplatePresentation().setIcon(myUi.getOptions().getSettingsActions().getTemplatePresentation().getIcon());
if (commonSettings.length > 0) {
+ for (AnAction each : commonSettings) {
+ settings.add(each);
+ }
settings.addSeparator();
}
if (!session.getDebugProcess().isValuesCustomSorted()) {
@@ -276,18 +263,18 @@ public class XDebugSessionTab extends DebuggerSessionTabBase {
leftToolbar.addSeparator();
leftToolbar.add(PinToolwindowTabAction.getPinAction());
- leftToolbar.add(new CloseAction(environment != null ? environment.getExecutor() : debugExecutor, myRunContentDescriptor, getProject()));
+ leftToolbar.add(new CloseAction(myEnvironment != null ? myEnvironment.getExecutor() : debugExecutor, myRunContentDescriptor, myProject));
leftToolbar.add(new ContextHelpAction(debugExecutor.getHelpId()));
DefaultActionGroup topToolbar = new DefaultActionGroup();
topToolbar.addAll(getCustomizedActionGroup(XDebuggerActions.TOOL_WINDOW_TOP_TOOLBAR_GROUP));
- session.getDebugProcess().registerAdditionalActions(leftToolbar, topToolbar);
+ session.getDebugProcess().registerAdditionalActions(leftToolbar, topToolbar, settings);
myUi.getOptions().setLeftToolbar(leftToolbar, ActionPlaces.DEBUGGER_TOOLBAR);
myUi.getOptions().setTopToolbar(topToolbar, ActionPlaces.DEBUGGER_TOOLBAR);
- if (environment != null) {
- initLogConsoles(environment.getRunProfile(), myRunContentDescriptor.getProcessHandler(), myConsole);
+ if (myEnvironment != null) {
+ initLogConsoles(myEnvironment.getRunProfile(), myRunContentDescriptor, myConsole);
}
}
@@ -296,7 +283,6 @@ public class XDebugSessionTab extends DebuggerSessionTabBase {
mySession = null;
}
- @Override
@Nullable
public RunContentDescriptor getRunContentDescriptor() {
return myRunContentDescriptor;
diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/ValueMarkerPresentationDialog.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/ValueMarkerPresentationDialog.java
index 4e164cc7fd15..e135bb1f4629 100644
--- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/ValueMarkerPresentationDialog.java
+++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/ValueMarkerPresentationDialog.java
@@ -17,12 +17,14 @@ package com.intellij.xdebugger.impl.ui.tree;
import org.jetbrains.annotations.Nullable;
+import java.awt.Component;
+
/**
* @author nik
*/
public class ValueMarkerPresentationDialog extends ValueMarkerPresentationDialogBase {
- public ValueMarkerPresentationDialog(@Nullable String defaultText) {
- super(defaultText);
+ public ValueMarkerPresentationDialog(@Nullable Component parent, @Nullable String defaultText) {
+ super(parent, defaultText);
init();
}
}
diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/ValueMarkerPresentationDialogBase.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/ValueMarkerPresentationDialogBase.java
index 8bb4327e36ff..fc7303460cbf 100644
--- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/ValueMarkerPresentationDialogBase.java
+++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/ValueMarkerPresentationDialogBase.java
@@ -38,8 +38,8 @@ public abstract class ValueMarkerPresentationDialogBase extends DialogWrapper {
private FixedSizeButton myChooseColorButton;
private JPanel mySamplePanel;
- public ValueMarkerPresentationDialogBase(final @Nullable String defaultText) {
- super(true);
+ public ValueMarkerPresentationDialogBase(@Nullable Component parent, final @Nullable String defaultText) {
+ super(parent, true);
setTitle("Select Object Label");
setModal(true);
myLabelField.getDocument().addDocumentListener(new DocumentAdapter() {
diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/WatchesRootNode.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/WatchesRootNode.java
index cf67f7d5fdb5..2e4e168b8d84 100644
--- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/WatchesRootNode.java
+++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/WatchesRootNode.java
@@ -188,9 +188,7 @@ public class WatchesRootNode extends XDebuggerTreeNode {
fireNodeStructureChanged(messageNode);
}
XDebugSession session = XDebugView.getSession(myTree);
- if (session != null) {
- new WatchInplaceEditor(this, session, myWatchesView, messageNode, "watch", node).show();
- }
+ new WatchInplaceEditor(this, session, myWatchesView, messageNode, "watch", node).show();
}
private class MyEvaluationCallback extends XEvaluationCallbackBase {
diff --git a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XValueContainerNode.java b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XValueContainerNode.java
index a2fb3d51d253..5a7c4bb6d0d8 100644
--- a/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XValueContainerNode.java
+++ b/platform/xdebugger-impl/src/com/intellij/xdebugger/impl/ui/tree/nodes/XValueContainerNode.java
@@ -187,14 +187,14 @@ public abstract class XValueContainerNode<ValueContainer extends XValueContainer
myTemporaryMessageChildren != null ? myTemporaryMessageChildren : Collections.<MessageTreeNode>emptyList());
final int[] indices = getNodesIndices(allMessageChildren);
final TreeNode[] nodes = getChildNodes(indices);
- myMessageChildren = null;
- myTemporaryMessageChildren = null;
fireNodesRemoved(indices, nodes);
if (!temporary) {
myMessageChildren = messages;
+ myTemporaryMessageChildren = null;
}
else {
myTemporaryMessageChildren = messages;
+ myMessageChildren = null;
}
myCachedAllChildren = null;
fireNodesInserted(messages);
diff --git a/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XDebuggerTestUtil.java b/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XDebuggerTestUtil.java
index e47002649d5a..e11ac871e3b4 100644
--- a/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XDebuggerTestUtil.java
+++ b/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XDebuggerTestUtil.java
@@ -35,8 +35,8 @@ import com.intellij.xdebugger.frame.*;
import com.intellij.xdebugger.frame.XNamedValue;
import com.intellij.xdebugger.impl.XDebugSessionImpl;
import com.intellij.xdebugger.impl.breakpoints.XBreakpointUtil;
+import com.intellij.xdebugger.impl.breakpoints.XExpressionImpl;
import com.intellij.xdebugger.impl.breakpoints.XLineBreakpointImpl;
-import junit.framework.Assert;
import org.intellij.lang.annotations.Language;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -50,6 +50,8 @@ import java.util.List;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
+import static org.junit.Assert.*;
+
public class XDebuggerTestUtil {
private static final int TIMEOUT = 25000;
@@ -65,10 +67,9 @@ public class XDebuggerTestUtil {
XLineBreakpointType type = (XLineBreakpointType)XDebuggerUtil.getInstance().findBreakpointType(breakpointType);
XBreakpointManager manager = XDebuggerManager.getInstance(project).getBreakpointManager();
XLineBreakpointImpl breakpoint = (XLineBreakpointImpl)manager.findBreakpointAtLine(type, file, line);
- Assert.assertNotNull(breakpoint);
- Assert
- .assertEquals(validity ? AllIcons.Debugger.Db_verified_breakpoint : AllIcons.Debugger.Db_invalid_breakpoint, breakpoint.getIcon());
- Assert.assertEquals(errorMessage, breakpoint.getErrorMessage());
+ assertNotNull(breakpoint);
+ assertEquals(validity ? AllIcons.Debugger.Db_verified_breakpoint : AllIcons.Debugger.Db_invalid_breakpoint, breakpoint.getIcon());
+ assertEquals(errorMessage, breakpoint.getErrorMessage());
}
public static void toggleBreakpoint(Project project, VirtualFile file, int line) {
@@ -79,7 +80,7 @@ public class XDebuggerTestUtil {
final P properties,
final Class<? extends XBreakpointType<XBreakpoint<P>, P>> typeClass) {
return new WriteAction<XBreakpoint<P>>() {
- protected void run(final Result<XBreakpoint<P>> result) {
+ protected void run(@NotNull final Result<XBreakpoint<P>> result) {
result.setResult(XDebuggerManager.getInstance(project).getBreakpointManager().addBreakpoint(
XBreakpointType.EXTENSION_POINT_NAME.findExtension(typeClass), properties));
}
@@ -88,16 +89,16 @@ public class XDebuggerTestUtil {
public static void removeBreakpoint(final Project project, final XBreakpoint<?> breakpoint) {
new WriteAction() {
- protected void run(final Result result) {
+ protected void run(@NotNull final Result result) {
XDebuggerManager.getInstance(project).getBreakpointManager().removeBreakpoint(breakpoint);
}
}.execute();
}
public static void assertPosition(XSourcePosition pos, VirtualFile file, int line) throws IOException {
- Assert.assertNotNull("No current position", pos);
- Assert.assertEquals(new File(file.getPath()).getCanonicalPath(), new File(pos.getFile().getPath()).getCanonicalPath());
- if (line != -1) Assert.assertEquals(line, pos.getLine());
+ assertNotNull("No current position", pos);
+ assertEquals(new File(file.getPath()).getCanonicalPath(), new File(pos.getFile().getPath()).getCanonicalPath());
+ if (line != -1) assertEquals(line, pos.getLine());
}
public static void assertCurrentPosition(XDebugSession session, VirtualFile file, int line) throws IOException {
@@ -127,12 +128,23 @@ public class XDebuggerTestUtil {
return container.waitFor(timeout).first;
}
- public static Pair<XValue, String> evaluate(XDebugSession session, String expression) throws InterruptedException {
+ public static Pair<XValue, String> evaluate(XDebugSession session, XExpression expression) {
return evaluate(session, expression, TIMEOUT);
}
- public static Pair<XValue, String> evaluate(XDebugSession session, String expression, long timeout) throws InterruptedException {
- XDebuggerEvaluator evaluator = session.getCurrentStackFrame().getEvaluator();
+ public static Pair<XValue, String> evaluate(XDebugSession session, String expression) {
+ return evaluate(session, XExpressionImpl.fromText(expression), TIMEOUT);
+ }
+
+ public static Pair<XValue, String> evaluate(XDebugSession session, String expression, long timeout) {
+ return evaluate(session, XExpressionImpl.fromText(expression), timeout);
+ }
+
+ private static Pair<XValue, String> evaluate(XDebugSession session, XExpression expression, long timeout) {
+ XStackFrame frame = session.getCurrentStackFrame();
+ assertNotNull(frame);
+ XDebuggerEvaluator evaluator = frame.getEvaluator();
+ assertNotNull(evaluator);
XTestEvaluationCallback callback = new XTestEvaluationCallback();
evaluator.evaluate(expression, callback, session.getCurrentPosition());
return callback.waitFor(timeout);
@@ -189,10 +201,10 @@ public class XDebuggerTestUtil {
@Nullable Boolean hasChildren) throws InterruptedException {
XTestValueNode node = computePresentation(var);
- if (name != null) Assert.assertEquals(name, node.myName);
- if (type != null) Assert.assertEquals(type, node.myType);
- if (value != null) Assert.assertEquals(value, node.myValue);
- if (hasChildren != null) Assert.assertEquals((boolean)hasChildren, node.myHasChildren);
+ if (name != null) assertEquals(name, node.myName);
+ if (type != null) assertEquals(type, node.myType);
+ if (value != null) assertEquals(value, node.myValue);
+ if (hasChildren != null) assertEquals(hasChildren, node.myHasChildren);
}
public static void assertVariableValue(XValue var, @Nullable String name, @Nullable String value) throws InterruptedException {
@@ -221,10 +233,10 @@ public class XDebuggerTestUtil {
@Nullable String type,
@Nullable @Language("RegExp") String valuePattern) throws InterruptedException {
XTestValueNode node = computePresentation(var);
- if (name != null) Assert.assertEquals(name, node.myName);
- if (type != null) Assert.assertEquals(type, node.myType);
+ if (name != null) assertEquals(name, node.myName);
+ if (type != null) assertEquals(type, node.myType);
if (valuePattern != null) {
- Assert.assertTrue("Expected value" + valuePattern + " Actual value: " + node.myValue, node.myValue.matches(valuePattern));
+ assertTrue("Expected value" + valuePattern + " Actual value: " + node.myValue, node.myValue.matches(valuePattern));
}
}
@@ -239,10 +251,10 @@ public class XDebuggerTestUtil {
@Nullable @Language("RegExp") String typePattern) throws InterruptedException {
XTestValueNode node = computePresentation(var);
if (name != null) {
- Assert.assertEquals(name, node.myName);
+ assertEquals(name, node.myName);
}
if (typePattern != null) {
- Assert.assertTrue("Expected type: " + typePattern + " Actual type: " + node.myType, node.myType.matches(typePattern));
+ assertTrue("Expected type: " + typePattern + " Actual type: " + node.myType, node.myType.matches(typePattern));
}
}
@@ -273,7 +285,7 @@ public class XDebuggerTestUtil {
}
});
- Assert.assertEquals(value, result[0]);
+ assertEquals(value, result[0]);
}
public static void assertVariableFullValue(Collection<XValue> vars, @Nullable String name, @Nullable String value)
@@ -303,9 +315,9 @@ public class XDebuggerTestUtil {
}
expectedNames.removeAll(actualNames);
- UsefulTestCase.assertTrue("Missing variables:" + StringUtil.join(expectedNames, ", ")
- + "\nAll Variables: " + StringUtil.join(actualNames, ", "),
- expectedNames.isEmpty()
+ assertTrue("Missing variables:" + StringUtil.join(expectedNames, ", ")
+ + "\nAll Variables: " + StringUtil.join(actualNames, ", "),
+ expectedNames.isEmpty()
);
}
@@ -317,13 +329,23 @@ public class XDebuggerTestUtil {
value.computeSourcePosition(n);
}
});
- Assert.assertNotNull(n.myPosition);
- Assert.assertEquals(file, n.myPosition.getFile());
- Assert.assertEquals(offset, n.myPosition.getOffset());
+ assertNotNull(n.myPosition);
+ assertEquals(file, n.myPosition.getFile());
+ assertEquals(offset, n.myPosition.getOffset());
}
- public static boolean waitFor(Semaphore semaphore, long timeoutInMillis) throws InterruptedException {
- return semaphore.tryAcquire(timeoutInMillis, TimeUnit.MILLISECONDS);
+ public static boolean waitFor(Semaphore semaphore, long timeoutInMillis) {
+ long end = System.currentTimeMillis() + timeoutInMillis;
+ long remaining = timeoutInMillis;
+ do {
+ try {
+ return semaphore.tryAcquire(remaining, TimeUnit.MILLISECONDS);
+ }
+ catch (InterruptedException ignored) {
+ remaining = end - System.currentTimeMillis();
+ }
+ } while (remaining > 0);
+ return false;
}
public static void assertVariable(Collection<XValue> vars,
@@ -337,7 +359,7 @@ public class XDebuggerTestUtil {
@NotNull
public static String getConsoleText(final @NotNull ConsoleViewImpl consoleView) {
new WriteAction() {
- protected void run(Result result) throws Throwable {
+ protected void run(@NotNull Result result) throws Throwable {
consoleView.flushDeferredText();
}
}.execute();
@@ -356,7 +378,7 @@ public class XDebuggerTestUtil {
final T breakpointType = exceptionType.cast(type);
new WriteAction() {
@Override
- protected void run(Result result) throws Throwable {
+ protected void run(@NotNull Result result) throws Throwable {
breakpoint.set(breakpointManager.addBreakpoint(breakpointType, properties));
}
}.execute();
@@ -372,7 +394,7 @@ public class XDebuggerTestUtil {
for (final XBreakpoint b : breakpoints) {
new WriteAction() {
@Override
- protected void run(Result result) throws Throwable {
+ protected void run(@NotNull Result result) throws Throwable {
breakpointManager.removeBreakpoint(b);
}
}.execute();
@@ -406,7 +428,7 @@ public class XDebuggerTestUtil {
if (lineBreakpoint.getLine() == line) {
new WriteAction() {
@Override
- protected void run(Result result) throws Throwable {
+ protected void run(@NotNull Result result) throws Throwable {
lineBreakpoint.setCondition(condition);
}
}.execute();
@@ -424,7 +446,7 @@ public class XDebuggerTestUtil {
if (lineBreakpoint.getLine() == line) {
new WriteAction() {
@Override
- protected void run(Result result) throws Throwable {
+ protected void run(@NotNull Result result) throws Throwable {
lineBreakpoint.setLogExpression(logExpression);
lineBreakpoint.setLogMessage(true);
}
@@ -436,7 +458,7 @@ public class XDebuggerTestUtil {
public static void disposeDebugSession(final XDebugSession debugSession) {
new WriteAction() {
- protected void run(Result result) throws Throwable {
+ protected void run(@NotNull Result result) throws Throwable {
XDebugSessionImpl session = (XDebugSessionImpl)debugSession;
Disposer.dispose(session.getSessionTab());
Disposer.dispose(session.getConsoleView());
@@ -449,13 +471,13 @@ public class XDebuggerTestUtil {
@Nullable String type,
@Nullable String value,
@Nullable Boolean hasChildren) throws InterruptedException {
- Assert.assertNull(varAndErrorMessage.second);
+ assertNull(varAndErrorMessage.second);
assertVariable(varAndErrorMessage.first, name, type, value, hasChildren);
}
public static String assertVariableExpression(XValue desc, String expectedExpression) {
String expression = desc.getEvaluationExpression();
- Assert.assertEquals(expectedExpression, expression);
+ assertEquals(expectedExpression, expression);
return expression;
}
diff --git a/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XTestContainer.java b/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XTestContainer.java
index 32c65d8eb6fc..84c1fe8693e8 100644
--- a/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XTestContainer.java
+++ b/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XTestContainer.java
@@ -56,7 +56,7 @@ public class XTestContainer<T> {
return false;
}
- public Pair<List<T>, String> waitFor(long timeout) throws InterruptedException {
+ public Pair<List<T>, String> waitFor(long timeout) {
if (!XDebuggerTestUtil.waitFor(myFinished, timeout)) {
throw new AssertionError("Waiting timed out");
}
diff --git a/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XTestEvaluationCallback.java b/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XTestEvaluationCallback.java
index cb1b18e3795a..918648840790 100644
--- a/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XTestEvaluationCallback.java
+++ b/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XTestEvaluationCallback.java
@@ -2,11 +2,12 @@ package com.intellij.xdebugger;
import com.intellij.openapi.util.Pair;
import com.intellij.xdebugger.frame.XValue;
-import junit.framework.Assert;
import org.jetbrains.annotations.NotNull;
import java.util.concurrent.Semaphore;
+import static org.junit.Assert.*;
+
public class XTestEvaluationCallback extends com.intellij.xdebugger.impl.ui.tree.nodes.XEvaluationCallbackBase {
private XValue myResult;
private String myErrorMessage;
@@ -24,8 +25,8 @@ public class XTestEvaluationCallback extends com.intellij.xdebugger.impl.ui.tree
myFinished.release();
}
- public Pair<XValue, String> waitFor(long timeoutInMilliseconds) throws InterruptedException {
- Assert.assertTrue("timed out", XDebuggerTestUtil.waitFor(myFinished, timeoutInMilliseconds));
+ public Pair<XValue, String> waitFor(long timeoutInMilliseconds) {
+ assertTrue("timed out", XDebuggerTestUtil.waitFor(myFinished, timeoutInMilliseconds));
return Pair.create(myResult, myErrorMessage);
}
}
diff --git a/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XTestValueNode.java b/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XTestValueNode.java
index e1dbca415903..45ad3306831a 100644
--- a/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XTestValueNode.java
+++ b/platform/xdebugger-impl/testSrc/com/intellij/xdebugger/XTestValueNode.java
@@ -41,7 +41,7 @@ public class XTestValueNode extends XValueNodePresentationConfigurator.Configura
return false;
}
- public void waitFor(long timeoutInMillis) throws InterruptedException {
+ public void waitFor(long timeoutInMillis) {
if (!XDebuggerTestUtil.waitFor(myFinished, timeoutInMillis)) {
throw new AssertionError("Waiting timed out");
}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml
index c8d1f3695cd4..17ad0f7d5d36 100644
--- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml
@@ -1052,6 +1052,10 @@
key="abstract.method.call.in.constructor.display.name" groupBundle="messages.InspectionsBundle"
groupKey="group.names.initialization.issues" enabledByDefault="false" level="WARNING"
implementationClass="com.siyeh.ig.initialization.AbstractMethodCallInConstructorInspection"/>
+ <localInspection language="JAVA" shortName="DoubleBraceInitialization" bundle="com.siyeh.InspectionGadgetsBundle"
+ key="double.brace.initialization.display.name" groupBundle="messages.InspectionsBundle"
+ groupKey="group.names.initialization.issues" enabledByDefault="false" level="WARNING"
+ implementationClass="com.siyeh.ig.initialization.DoubleBraceInitializationInspection"/>
<localInspection language="JAVA" suppressId="InstanceVariableMayNotBeInitialized" shortName="InstanceVariableInitialization"
bundle="com.siyeh.InspectionGadgetsBundle" key="instance.variable.may.not.be.initialized.display.name"
groupBundle="messages.InspectionsBundle" groupKey="group.names.initialization.issues" enabledByDefault="false"
@@ -1153,10 +1157,6 @@
key="abstract.class.with.only.one.direct.inheritor.display.name" groupBundle="messages.InspectionsBundle"
groupKey="group.names.j2me.issues" enabledByDefault="false" level="WARNING"
implementationClass="com.siyeh.ig.j2me.AbstractClassWithOnlyOneDirectInheritorInspection"/>
- <localInspection language="JAVA" shortName="AnonymousInnerClassMayBeStatic" bundle="com.siyeh.InspectionGadgetsBundle"
- key="anonymous.inner.may.be.named.static.inner.class.display.name" groupBundle="messages.InspectionsBundle"
- groupKey="group.names.j2me.issues" enabledByDefault="false" level="WARNING"
- implementationClass="com.siyeh.ig.j2me.AnonymousInnerClassMayBeStaticInspection"/>
<localInspection language="JAVA" shortName="ArrayLengthInLoopCondition" bundle="com.siyeh.InspectionGadgetsBundle"
key="array.length.in.loop.condition.display.name" groupBundle="messages.InspectionsBundle"
groupKey="group.names.j2me.issues" enabledByDefault="false" level="WARNING"
@@ -1541,6 +1541,14 @@
implementationClass="com.siyeh.ig.maturity.UseOfObsoleteDateTimeApiInspection"/>
<!--group.names.memory.issues-->
+ <localInspection language="JAVA" shortName="AnonymousInnerClassMayBeStatic" bundle="com.siyeh.InspectionGadgetsBundle"
+ key="anonymous.inner.may.be.named.static.inner.class.display.name" groupBundle="messages.InspectionsBundle"
+ groupKey="group.names.memory.issues" enabledByDefault="false" level="WARNING"
+ implementationClass="com.siyeh.ig.memory.AnonymousInnerClassMayBeStaticInspection"/>
+ <localInspection language="JAVA" shortName="InnerClassMayBeStatic" bundle="com.siyeh.InspectionGadgetsBundle"
+ key="inner.class.may.be.static.display.name" groupBundle="messages.InspectionsBundle"
+ groupKey="group.names.memory.issues" enabledByDefault="false" level="WARNING" runForWholeFile="true"
+ implementationClass="com.siyeh.ig.memory.InnerClassMayBeStaticInspection"/>
<localInspection language="JAVA" shortName="StaticCollection" bundle="com.siyeh.InspectionGadgetsBundle" key="static.collection.display.name"
groupBundle="messages.InspectionsBundle" groupKey="group.names.memory.issues" enabledByDefault="false" level="WARNING"
implementationClass="com.siyeh.ig.memory.StaticCollectionInspection"/>
@@ -1908,10 +1916,6 @@
<localInspection language="JAVA" shortName="FieldMayBeStatic" bundle="com.siyeh.InspectionGadgetsBundle" key="field.may.be.static.display.name"
groupBundle="messages.InspectionsBundle" groupKey="group.names.performance.issues" enabledByDefault="false"
level="WARNING" implementationClass="com.siyeh.ig.performance.FieldMayBeStaticInspection"/>
- <localInspection language="JAVA" shortName="InnerClassMayBeStatic" bundle="com.siyeh.InspectionGadgetsBundle"
- key="inner.class.may.be.static.display.name" groupBundle="messages.InspectionsBundle"
- groupKey="group.names.performance.issues" enabledByDefault="false" level="WARNING" runForWholeFile="true"
- implementationClass="com.siyeh.ig.performance.InnerClassMayBeStaticInspection"/>
<localInspection language="JAVA" shortName="InstantiatingObjectToGetClassObject" bundle="com.siyeh.InspectionGadgetsBundle"
key="instantiating.object.to.get.class.object.display.name" groupBundle="messages.InspectionsBundle"
groupKey="group.names.performance.issues" enabledByDefault="true" level="WARNING"
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties
index 1df72421fd4d..949ae7667e76 100644
--- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties
@@ -445,8 +445,8 @@ use.processbuilder.class.problem.descriptor=Use of <code>#ref</code> is non-port
use.sun.classes.display.name=Use of sun.* classes
use.sun.classes.problem.descriptor=Use of Sun-supplied class <code>#ref</code> is non-portable #loc
abstract.class.with.only.one.direct.inheritor.display.name=Abstract class which has only one direct inheritor
-anonymous.inner.may.be.named.static.inner.class.display.name=Anonymous inner class may be a named static inner class
-anonymous.inner.may.be.named.static.inner.class.problem.descriptor=Anonymous inner class <code>#ref</code> may be a named static inner class #loc
+anonymous.inner.may.be.named.static.inner.class.display.name=Anonymous class may be a named 'static' inner class
+anonymous.inner.may.be.named.static.inner.class.problem.descriptor=Anonymous class <code>#ref</code> may be a named 'static' inner class #loc
array.length.in.loop.condition.display.name=Array.length in loop condition
array.length.in.loop.condition.problem.descriptor=Check of array <code>#ref</code> in loop condition #loc
large.array.allocation.no.outofmemoryerror.display.name=Large array allocation with no OutOfMemoryError check
@@ -992,7 +992,8 @@ constant.on.lhs.of.comparison.problem.descriptor=<code>#ref</code>: constant on
constant.on.rhs.of.comparison.problem.descriptor=<code>#ref</code>: constant on right side of comparison #loc
control.flow.statement.without.braces.problem.descriptor=<code>#ref</code> without braces #loc
missorted.modifiers.problem.descriptor=Missorted modifiers <code>#ref</code> #loc
-c.style.array.declaration.problem.descriptor=C-style array declaration <code>#ref</code> #loc
+cstyle.array.variable.declaration.problem.descriptor=C-style array declaration of {0, choice, 1#field|2#parameter|3#local variable} <code>#ref</code> #loc
+cstyle.array.method.declaration.problem.descriptor=C-style array declaration of the return type of method <code>#ref()</code>#loc
multiple.declaration.problem.descriptor=Multiple variables in one declaration #loc
multiple.typed.declaration.problem.descriptor=Variables of different types in one declaration #loc
serializable.inner.class.has.serial.version.uid.field.problem.descriptor=Inner class <code>#ref</code> does not define a 'serialVersionUID' field #loc
@@ -1290,7 +1291,7 @@ call.to.simple.getter.in.class.inline.quickfix=Inline call to getter
call.to.simple.setter.in.class.ignore.option=Ignore setter calls on other objects
call.to.private.setter.in.class.option=Only report when setter is private
call.to.simple.setter.in.class.inline.quickfix=Inline call to setter
-make.static.quickfix=Make static
+make.static.quickfix=Make 'static'
length.one.strings.in.concatenation.replace.quickfix=Replace with character
multiply.or.divide.by.power.of.two.replace.quickfix=Replace with shift
boolean.expression.can.be.simplified.problem.descriptor=<code>#ref</code> can be simplified to ''{0}'' #loc
@@ -1366,6 +1367,8 @@ implicit.call.to.super.make.explicit.quickfix=Make call to 'super()' explicit
missorted.modifiers.require.option=Require annotations to be sorted before keywords
missorted.modifiers.sort.quickfix=Sort modifiers
nested.method.call.ignore.option=Ignore nested method calls in field initializers
+ignore.calls.to.static.methods=Ignore calls to static methods
+ignore.calls.to.property.getters=Ignore calls to property getters
redundant.field.initialization.remove.quickfix=Remove initializer
redundant.implements.remove.quickfix=Remove redundant interface declaration
unnecessary.constructor.remove.quickfix=Remove redundant constructor
@@ -1691,8 +1694,8 @@ char.used.in.arithmetic.context.cast.quickfix=Insert cast to {0}
unnecessary.constant.array.creation.expression.display.name=Constant array creation expression can be replaced with array initializer
unnecessary.constant.array.creation.expression.problem.descriptor=<code>#ref</code> can be replaced with array initializer expression #loc
unnecessary.constant.array.creation.expression.quickfix=Replace with array initializer expression
-ambiguous.method.call.display.name=Inherited method called, while local method might have been expected
-ambiguous.method.call.problem.descriptor=Method <code>#ref()</code> from superclass ''{0}'' called, when method from class ''{1}'' might have been expected #loc
+ambiguous.method.call.display.name=Call to inherited method looks like call to local method
+ambiguous.method.call.problem.descriptor=Call to method <code>#ref()</code> from superclass ''{0}'' looks like call to method from class ''{1}'' #loc
ambiguous.method.call.quickfix=Add 'super' qualifier to method call
change.modifier.quickfix=Make ''{0}''
the.whole.project=the whole project
@@ -1969,10 +1972,10 @@ throws.runtime.exception.problem.descriptor=Unchecked exception <code>#ref</code
throws.runtime.exception.quickfix=Remove ''{0}'' from ''throws'' clause
throws.runtime.exception.move.quickfix=Move ''{0}'' to Javadoc ''@throws'' tag
empty.class.ignore.parameterization.option=Ignore class if it is a parameterization of a super type
-ambiguous.field.access.display.name=Inherited field accessed while local variable, parameter or field access from surrounding class might be expected
-ambiguous.field.access.hides.local.variable.problem.descriptor=Field <code>#ref</code> from superclass ''{0}'' accessed, while local variable access might be expected #loc
-ambiguous.field.access.hides.parameter.problem.descriptor=Field <code>#ref</code> from superclass ''{0}'' accessed, while parameter access might be expected #loc
-ambiguous.field.access.hides.field.problem.descriptor=Field <code>#ref</code> from superclass ''{0}'' accessed, while field access from surrounding class might be expected #loc
+ambiguous.field.access.display.name=Access of inherited field looks like access of element in surrounding code
+ambiguous.field.access.hides.local.variable.problem.descriptor=Access of field <code>#ref</code> from superclass ''{0}'' looks like access of local variable #loc
+ambiguous.field.access.hides.parameter.problem.descriptor=Access of field <code>#ref</code> from superclass ''{0}'' looks like access of parameter #loc
+ambiguous.field.access.hides.field.problem.descriptor=Access of field <code>#ref</code> from superclass ''{0}'' looks access of field from surrounding class #loc
ambiguous.field.access.quickfix=Add 'super' qualifier to field access
string.builder.replaceable.by.string.quickfix=Replace 'StringBuilder' with 'String'
string.buffer.replaceable.by.string.quickfix=Replace 'StringBuffer' with 'String'
@@ -2111,3 +2114,6 @@ junit3.method.naming.convention.display.name=JUnit 3 test method naming conventi
junit3.method.naming.convention.problem.descriptor.short=JUnit 3 test method name <code>#ref</code> is too short ({0} < {1}) #loc
junit3.method.naming.convention.problem.descriptor.long=JUnit 3 test method name <code>#ref</code> is too long ({0} > {1}) #loc
junit3.method.naming.convention.problem.descriptor.regex.mismatch=JUnit 3 test method name <code>#ref</code> doesn''t match regex ''{0}'' #loc
+introduce.holder.class.quickfix=Introduce holder class
+double.brace.initialization.display.name=Double brace initialization
+double.brace.initialization.quickfix=Replace with regular initialization
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/ResultSetIndexZeroInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/ResultSetIndexZeroInspection.java
index 626d4508e731..a72f297e483c 100644
--- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/ResultSetIndexZeroInspection.java
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/ResultSetIndexZeroInspection.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2012 Dave Griffith, Bas Leijdekkers
+ * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -87,11 +87,11 @@ public class ResultSetIndexZeroInspection extends BaseInspection {
final PsiExpression qualifier = methodExpression.getQualifierExpression();
if (resultSet) {
if (TypeUtils.expressionHasTypeOrSubtype(qualifier, "java.sql.ResultSet")) {
- registerError(argument, Boolean.valueOf(resultSet));
+ registerError(argument, Boolean.TRUE);
}
- } else {
+ } else if (arguments.length > 1) {
if (TypeUtils.expressionHasTypeOrSubtype(qualifier, "java.sql.PreparedStatement")) {
- registerError(argument, Boolean.valueOf(resultSet));
+ registerError(argument, Boolean.FALSE);
}
}
}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/StringEqualityInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/StringEqualityInspection.java
index 0ac07245fd8f..f94f495993d7 100644
--- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/StringEqualityInspection.java
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/StringEqualityInspection.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2012 Dave Griffith, Bas Leijdekkers
+ * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +18,6 @@ package com.siyeh.ig.bugs;
import com.intellij.psi.PsiBinaryExpression;
import com.intellij.psi.PsiExpression;
import com.intellij.psi.PsiJavaToken;
-import com.intellij.psi.PsiKeyword;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
@@ -73,12 +72,7 @@ public class StringEqualityInspection extends BaseInspection {
if (rhs == null || !ExpressionUtils.hasStringType(rhs)) {
return;
}
- final String lhsText = lhs.getText();
- if (PsiKeyword.NULL.equals(lhsText)) {
- return;
- }
- final String rhsText = rhs.getText();
- if (PsiKeyword.NULL.equals(rhsText)) {
+ if (ExpressionUtils.isNullLiteral(lhs) || ExpressionUtils.isNullLiteral(rhs)) {
return;
}
final PsiJavaToken sign = expression.getOperationSign();
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/ClassWithOnlyPrivateConstructorsInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/ClassWithOnlyPrivateConstructorsInspectionBase.java
index 6d091699ce82..b6583b4ede75 100644
--- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/ClassWithOnlyPrivateConstructorsInspectionBase.java
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/ClassWithOnlyPrivateConstructorsInspectionBase.java
@@ -54,6 +54,9 @@ public class ClassWithOnlyPrivateConstructorsInspectionBase extends BaseInspecti
@Override
public void visitClass(PsiClass aClass) {
super.visitClass(aClass);
+ if (aClass.isEnum()) {
+ return;
+ }
final PsiMethod[] constructors = aClass.getConstructors();
if (constructors.length == 0) {
return;
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/controlflow/LoopConditionNotUpdatedInsideLoopInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/controlflow/LoopConditionNotUpdatedInsideLoopInspection.java
index 46969fd5bcfc..57c635b7d461 100644
--- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/controlflow/LoopConditionNotUpdatedInsideLoopInspection.java
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/controlflow/LoopConditionNotUpdatedInsideLoopInspection.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2006-2013 Bas Leijdekkers
+ * Copyright 2006-2014 Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@ import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
import com.siyeh.ig.psiutils.BoolUtils;
+import com.siyeh.ig.psiutils.ExpressionUtils;
import com.siyeh.ig.psiutils.IteratorUtils;
import com.siyeh.ig.psiutils.VariableAccessUtils;
import org.jetbrains.annotations.NotNull;
@@ -118,8 +119,7 @@ public class LoopConditionNotUpdatedInsideLoopInspection
if (condition == null) {
return false;
}
- if (PsiUtil.isConstantExpression(condition) ||
- PsiKeyword.NULL.equals(condition.getText())) {
+ if (PsiUtil.isConstantExpression(condition) || ExpressionUtils.isNullLiteral(condition)) {
return true;
}
if (condition instanceof PsiInstanceOfExpression) {
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/initialization/DoubleBraceInitializationInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/initialization/DoubleBraceInitializationInspection.java
new file mode 100644
index 000000000000..bdf58e720d8d
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/initialization/DoubleBraceInitializationInspection.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.initialization;
+
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.*;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.InspectionGadgetsFix;
+import com.siyeh.ig.psiutils.ParenthesesUtils;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author Bas Leijdekkers
+ */
+public class DoubleBraceInitializationInspection extends BaseInspection {
+ @Nls
+ @NotNull
+ @Override
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message("double.brace.initialization.display.name");
+ }
+
+ @NotNull
+ @Override
+ protected String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message("double.brace.initialization.display.name");
+ }
+
+ @Nullable
+ @Override
+ protected InspectionGadgetsFix buildFix(Object... infos) {
+ final PsiClass aClass = (PsiClass)infos[0];
+ final PsiElement parent = PsiTreeUtil.skipParentsOfType(aClass, PsiNewExpression.class, ParenthesesUtils.class);
+ if (!(parent instanceof PsiVariable) && !(parent instanceof PsiAssignmentExpression)) {
+ return null;
+ }
+ return new DoubleBraceInitializationFix();
+ }
+
+ private static class DoubleBraceInitializationFix extends InspectionGadgetsFix {
+
+ @NotNull
+ @Override
+ public String getName() {
+ return InspectionGadgetsBundle.message("double.brace.initialization.quickfix");
+ }
+
+ @NotNull
+ @Override
+ public String getFamilyName() {
+ return getName();
+ }
+
+ @Override
+ protected void doFix(Project project, ProblemDescriptor descriptor) {
+ final PsiElement element = descriptor.getPsiElement().getParent();
+ if (!(element instanceof PsiAnonymousClass)) {
+ return;
+ }
+ final PsiAnonymousClass aClass = (PsiAnonymousClass)element;
+ final PsiElement parent = aClass.getParent();
+ if (!(parent instanceof PsiNewExpression)) {
+ return;
+ }
+ final PsiNewExpression newExpression = (PsiNewExpression)parent;
+ final PsiElement ancestor = PsiTreeUtil.skipParentsOfType(newExpression, ParenthesesUtils.class);
+ final String qualifierText;
+ if (ancestor instanceof PsiVariable) {
+ qualifierText = ((PsiVariable)ancestor).getName();
+ }
+ else if (ancestor instanceof PsiAssignmentExpression) {
+ final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression)ancestor;
+ final PsiExpression lhs = ParenthesesUtils.stripParentheses(assignmentExpression.getLExpression());
+ if (!(lhs instanceof PsiReferenceExpression)) {
+ return;
+ }
+ final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)lhs;
+ final PsiElement target = referenceExpression.resolve();
+ if (!(target instanceof PsiVariable)) {
+ return;
+ }
+ qualifierText = referenceExpression.getText();
+ }
+ else {
+ return;
+ }
+ final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
+ final PsiJavaCodeReferenceElement baseClassReference = aClass.getBaseClassReference();
+ final PsiElement baseClassTarget = baseClassReference.resolve();
+ if (!(baseClassTarget instanceof PsiClass)) {
+ return;
+ }
+ final PsiExpressionList argumentList = aClass.getArgumentList();
+ if (argumentList == null) {
+ return;
+ }
+ qualifyReferences(aClass, (PsiClass) baseClassTarget, qualifierText);
+ final PsiClassInitializer initializer = aClass.getInitializers()[0];
+ final PsiCodeBlock body = initializer.getBody();
+ PsiElement child = body.getLastBodyElement();
+ final PsiElement stop = body.getFirstBodyElement();
+ final PsiElement anchor = PsiTreeUtil.getParentOfType(aClass, PsiMember.class, PsiStatement.class);
+ if (anchor == null) {
+ return;
+ }
+ if (anchor instanceof PsiMember) {
+ final PsiMember member = (PsiMember)anchor;
+ final PsiClassInitializer newInitializer = factory.createClassInitializer();
+ if (member.hasModifierProperty(PsiModifier.STATIC)) {
+ final PsiModifierList modifierList = newInitializer.getModifierList();
+ if (modifierList != null) {
+ modifierList.setModifierProperty(PsiModifier.STATIC, true);
+ }
+ }
+ final PsiCodeBlock initializerBody = newInitializer.getBody();
+ while (child != null && !child.equals(stop)) {
+ initializerBody.add(child);
+ child = child.getPrevSibling();
+ }
+ member.getParent().addAfter(newInitializer, member);
+ }
+ else {
+ final PsiElement container = anchor.getParent();
+ while (child != null && !child.equals(stop)) {
+ container.addAfter(child, anchor);
+ child = child.getPrevSibling();
+ }
+ }
+ final PsiExpression newNewExpression =
+ factory.createExpressionFromText("new " + baseClassReference.getText() + argumentList.getText(), aClass);
+ newExpression.replace(newNewExpression);
+ }
+
+ private static void qualifyReferences(PsiElement element, final PsiClass target, final String qualifierText) {
+ final PsiElementFactory factory = JavaPsiFacade.getElementFactory(element.getProject());
+ element.accept(new JavaRecursiveElementVisitor() {
+ @Override
+ public void visitReferenceExpression(PsiReferenceExpression expression) {
+ super.visitReferenceExpression(expression);
+ if (expression.getQualifierExpression() != null) {
+ return;
+ }
+ final PsiElement expressionTarget = expression.resolve();
+ if (!(expressionTarget instanceof PsiMember)) {
+ return;
+ }
+ final PsiMember member = (PsiMember)expressionTarget;
+ final PsiClass containingClass = member.getContainingClass();
+ if (!target.equals(containingClass)) {
+ return;
+ }
+ final PsiExpression newExpression = factory.createExpressionFromText(qualifierText + '.' + expression.getText(), expression);
+ expression.replace(newExpression);
+ }
+ });
+ }
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new DoubleBraceInitializationVisitor();
+ }
+
+ private static class DoubleBraceInitializationVisitor extends BaseInspectionVisitor {
+
+ @Override
+ public void visitAnonymousClass(PsiAnonymousClass aClass) {
+ super.visitAnonymousClass(aClass);
+ final PsiClassInitializer[] initializers = aClass.getInitializers();
+ if (initializers.length != 1) {
+ return;
+ }
+ final PsiClassInitializer initializer = initializers[0];
+ if (initializer.hasModifierProperty(PsiModifier.STATIC)) {
+ // don't warn on broken code
+ return;
+ }
+ final PsiField[] fields = aClass.getFields();
+ if (fields.length != 0) {
+ return;
+ }
+ final PsiMethod[] methods = aClass.getMethods();
+ if (methods.length != 0) {
+ return;
+ }
+ final PsiClass[] innerClasses = aClass.getInnerClasses();
+ if (innerClasses.length != 0) {
+ return;
+ }
+ final PsiJavaCodeReferenceElement reference = aClass.getBaseClassReference();
+ if (reference.resolve() == null) {
+ return;
+ }
+ registerClassError(aClass, aClass);
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/initialization/NonThreadSafeLazyInitializationInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/initialization/NonThreadSafeLazyInitializationInspection.java
deleted file mode 100644
index 2e0bebac17b9..000000000000
--- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/initialization/NonThreadSafeLazyInitializationInspection.java
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * Copyright 2003-2007 Dave Griffith, Bas Leijdekkers
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * 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.siyeh.ig.initialization;
-
-import com.intellij.codeInspection.ProblemDescriptor;
-import com.intellij.openapi.project.Project;
-import com.intellij.psi.*;
-import com.intellij.psi.search.searches.ReferencesSearch;
-import com.intellij.psi.tree.IElementType;
-import com.intellij.psi.util.PsiTreeUtil;
-import com.intellij.psi.util.PsiUtil;
-import com.intellij.util.IncorrectOperationException;
-import com.intellij.util.Processor;
-import com.siyeh.InspectionGadgetsBundle;
-import com.siyeh.ig.BaseInspection;
-import com.siyeh.ig.BaseInspectionVisitor;
-import com.siyeh.ig.InspectionGadgetsFix;
-import org.jetbrains.annotations.NonNls;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.Collection;
-
-public class NonThreadSafeLazyInitializationInspection
- extends BaseInspection {
-
- @Override
- @NotNull
- public String getDisplayName() {
- return InspectionGadgetsBundle.message(
- "non.thread.safe.lazy.initialization.display.name");
- }
-
- @Override
- @NotNull
- public String buildErrorString(Object... infos) {
- return InspectionGadgetsBundle.message(
- "non.thread.safe.lazy.initialization.problem.descriptor");
- }
-
- @Override
- public BaseInspectionVisitor buildVisitor() {
- return new UnsafeSafeLazyInitializationVisitor();
- }
-
- private static class UnsafeSafeLazyInitializationVisitor
- extends BaseInspectionVisitor {
-
- @Override
- public void visitAssignmentExpression(
- @NotNull PsiAssignmentExpression expression) {
- super.visitAssignmentExpression(expression);
- final PsiExpression lhs = expression.getLExpression();
- if (!(lhs instanceof PsiReferenceExpression)) {
- return;
- }
- final PsiReference reference = (PsiReference)lhs;
- final PsiElement referent = reference.resolve();
- if (!(referent instanceof PsiField)) {
- return;
- }
- final PsiField field = (PsiField)referent;
- if (!field.hasModifierProperty(PsiModifier.STATIC)) {
- return;
- }
- if (isInStaticInitializer(expression)) {
- return;
- }
- if (isInSynchronizedContext(expression)) {
- return;
- }
- if (!isLazy(expression, (PsiReferenceExpression)lhs)) {
- return;
- }
- boolean assignedOnce = isAssignedOnce(referent);
- boolean safeToDelete = isSafeToDeleteIfStatement(expression);
- registerError(lhs, assignedOnce && safeToDelete);
- }
-
- private static boolean isAssignedOnce(PsiElement referent) {
- final int[] writeCount = new int[1];
- return ReferencesSearch.search(referent).forEach(new Processor<PsiReference>() {
- @Override
- public boolean process(PsiReference reference) {
- PsiElement element = reference.getElement();
- if (!(element instanceof PsiExpression)) {
- return true;
- }
- if (!PsiUtil.isAccessedForWriting((PsiExpression)element)) {
- return true;
- }
- return ++writeCount[0] != 2;
- }
- });
- }
-
- private static boolean isSafeToDeleteIfStatement(PsiElement expression) {
- PsiIfStatement ifStatement = PsiTreeUtil.getParentOfType(expression, PsiIfStatement.class);
- if (ifStatement.getElseBranch() != null) {
- return false;
- }
- PsiStatement thenBranch = ifStatement.getThenBranch();
- if (thenBranch == null) return false;
- if (!(thenBranch instanceof PsiBlockStatement)) {
- return true;
- }
- return ((PsiBlockStatement)thenBranch).getCodeBlock().getStatements().length == 1;
- }
-
- private static boolean isLazy(PsiAssignmentExpression expression,
- PsiReferenceExpression lhs) {
- final PsiIfStatement ifStatement =
- PsiTreeUtil.getParentOfType(expression,
- PsiIfStatement.class);
- if (ifStatement == null) {
- return false;
- }
- final PsiExpression condition = ifStatement.getCondition();
- if (condition == null) {
- return false;
- }
- return isNullComparison(condition, lhs);
- }
-
- private static boolean isNullComparison(
- PsiExpression condition, PsiReferenceExpression reference) {
- if (!(condition instanceof PsiBinaryExpression)) {
- return false;
- }
- final PsiBinaryExpression comparison =
- (PsiBinaryExpression)condition;
- final IElementType tokenType = comparison.getOperationTokenType();
- if (!tokenType.equals(JavaTokenType.EQEQ)) {
- return false;
- }
- final PsiExpression lhs = comparison.getLOperand();
- final PsiExpression rhs = comparison.getROperand();
- if (rhs == null) {
- return false;
- }
- final String lhsText = lhs.getText();
- final String rhsText = rhs.getText();
- if (!PsiKeyword.NULL.equals(lhsText) &&
- !PsiKeyword.NULL.equals(rhsText)) {
- return false;
- }
- final String referenceText = reference.getText();
- return referenceText.equals(lhsText) ||
- referenceText.equals(rhsText);
- }
-
- private static boolean isInSynchronizedContext(PsiElement element) {
- final PsiSynchronizedStatement syncBlock =
- PsiTreeUtil.getParentOfType(element,
- PsiSynchronizedStatement.class);
- if (syncBlock != null) {
- return true;
- }
- final PsiMethod method =
- PsiTreeUtil.getParentOfType(element,
- PsiMethod.class);
- return method != null &&
- method.hasModifierProperty(PsiModifier.SYNCHRONIZED)
- && method.hasModifierProperty(PsiModifier.STATIC);
- }
-
- private static boolean isInStaticInitializer(PsiElement element) {
- final PsiClassInitializer initializer =
- PsiTreeUtil.getParentOfType(element,
- PsiClassInitializer.class);
- return initializer != null &&
- initializer.hasModifierProperty(PsiModifier.STATIC);
- }
- }
-
- @Override
- protected InspectionGadgetsFix buildFix(Object... infos) {
- boolean isApplicable = ((Boolean)infos[0]).booleanValue();
- return isApplicable ? new IntroduceHolderFix() : null;
- }
-
- private static class IntroduceHolderFix extends InspectionGadgetsFix {
- @Override
- protected void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException {
- PsiReferenceExpression expression = (PsiReferenceExpression)descriptor.getPsiElement();
- PsiElement resolved = expression.resolve();
- if (!(resolved instanceof PsiField)) return;
- PsiField field = (PsiField)resolved;
- String holderName = suggestHolderName(field);
- @NonNls String text = "private static class " + holderName
- + " {" +
- "private static final " + field.getType().getCanonicalText() + " " +
- field.getName() + " = " + ((PsiAssignmentExpression)expression.getParent()).getRExpression().getText() + ";"
- + "}";
- PsiElementFactory elementFactory = JavaPsiFacade.getInstance(field.getProject()).getElementFactory();
- PsiClass holder = elementFactory.createClassFromText(text, field).getInnerClasses()[0];
- PsiMethod method = PsiTreeUtil.getParentOfType(expression, PsiMethod.class);
- method.getParent().addBefore(holder, method);
-
- PsiIfStatement ifStatement = PsiTreeUtil.getParentOfType(expression, PsiIfStatement.class);
- ifStatement.delete();
-
- final PsiExpression holderReference = elementFactory.createExpressionFromText(holderName + "." + field.getName(), field);
- Collection<PsiReference> references = ReferencesSearch.search(field).findAll();
- for (PsiReference reference : references) {
- PsiElement element = reference.getElement();
- element.replace(holderReference);
- }
- field.delete();
- }
-
- @NonNls
- private static String suggestHolderName(PsiField field) {
- String string = field.getType().getDeepComponentType().getPresentableText();
- final int index = string.indexOf('<');
- if (index != -1) {
- string = string.substring(0, index);
- }
- return string + "Holder";
- }
-
- @Override
- @NotNull
- public String getName() {
- return "Introduce holder class";
- }
-
- @NotNull
- @Override
- public String getFamilyName() {
- return getName();
- }
- }
-} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/initialization/NonThreadSafeLazyInitializationInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/initialization/NonThreadSafeLazyInitializationInspectionBase.java
new file mode 100644
index 000000000000..f29c461bcf64
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/initialization/NonThreadSafeLazyInitializationInspectionBase.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.siyeh.ig.initialization;
+
+import com.intellij.psi.*;
+import com.intellij.psi.tree.IElementType;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.psiutils.ExpressionUtils;
+import com.siyeh.ig.psiutils.VariableAccessUtils;
+import org.jetbrains.annotations.NotNull;
+
+public class NonThreadSafeLazyInitializationInspectionBase extends BaseInspection {
+
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "non.thread.safe.lazy.initialization.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "non.thread.safe.lazy.initialization.problem.descriptor");
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new UnsafeSafeLazyInitializationVisitor();
+ }
+
+ private static class UnsafeSafeLazyInitializationVisitor
+ extends BaseInspectionVisitor {
+
+ @Override
+ public void visitAssignmentExpression(
+ @NotNull PsiAssignmentExpression expression) {
+ super.visitAssignmentExpression(expression);
+ final PsiExpression lhs = expression.getLExpression();
+ if (!(lhs instanceof PsiReferenceExpression)) {
+ return;
+ }
+ final PsiReferenceExpression reference = (PsiReferenceExpression)lhs;
+ final PsiElement referent = reference.resolve();
+ if (!(referent instanceof PsiField)) {
+ return;
+ }
+ final PsiField field = (PsiField)referent;
+ if (!field.hasModifierProperty(PsiModifier.STATIC)) {
+ return;
+ }
+ if (isInStaticInitializer(expression)) {
+ return;
+ }
+ if (isInSynchronizedContext(expression)) {
+ return;
+ }
+ final PsiStatement statement = PsiTreeUtil.getParentOfType(expression, PsiStatement.class);
+ final PsiElement parent =
+ PsiTreeUtil.skipParentsOfType(statement, PsiCodeBlock.class, PsiBlockStatement.class);
+ if (!(parent instanceof PsiIfStatement)) {
+ return;
+ }
+ final PsiIfStatement ifStatement = (PsiIfStatement)parent;
+ final PsiExpression condition = ifStatement.getCondition();
+ if (condition == null|| !isNullComparison(condition, field)) {
+ return;
+ }
+ registerError(lhs, ifStatement, field);
+ }
+
+ private static boolean isNullComparison(PsiExpression condition, PsiVariable variable) {
+ if (!(condition instanceof PsiBinaryExpression)) {
+ return false;
+ }
+ final PsiBinaryExpression comparison = (PsiBinaryExpression)condition;
+ final IElementType tokenType = comparison.getOperationTokenType();
+ if (!tokenType.equals(JavaTokenType.EQEQ)) {
+ return false;
+ }
+ final PsiExpression lhs = comparison.getLOperand();
+ final PsiExpression rhs = comparison.getROperand();
+ if (ExpressionUtils.isNullLiteral(rhs)) {
+ return VariableAccessUtils.evaluatesToVariable(lhs, variable);
+ }
+ else if (ExpressionUtils.isNullLiteral(lhs)) {
+ return VariableAccessUtils.evaluatesToVariable(rhs, variable);
+ }
+ return false;
+ }
+
+ private static boolean isInSynchronizedContext(PsiElement element) {
+ final PsiSynchronizedStatement syncBlock =
+ PsiTreeUtil.getParentOfType(element,
+ PsiSynchronizedStatement.class);
+ if (syncBlock != null) {
+ return true;
+ }
+ final PsiMethod method =
+ PsiTreeUtil.getParentOfType(element,
+ PsiMethod.class);
+ return method != null &&
+ method.hasModifierProperty(PsiModifier.SYNCHRONIZED)
+ && method.hasModifierProperty(PsiModifier.STATIC);
+ }
+
+ private static boolean isInStaticInitializer(PsiElement element) {
+ final PsiClassInitializer initializer =
+ PsiTreeUtil.getParentOfType(element,
+ PsiClassInitializer.class);
+ return initializer != null &&
+ initializer.hasModifierProperty(PsiModifier.STATIC);
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/j2me/AnonymousInnerClassMayBeStaticInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/j2me/AnonymousInnerClassMayBeStaticInspectionBase.java
deleted file mode 100644
index 4ea6a4c7290f..000000000000
--- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/j2me/AnonymousInnerClassMayBeStaticInspectionBase.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2000-2013 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.siyeh.ig.j2me;
-
-import com.intellij.psi.*;
-import com.intellij.psi.util.PsiTreeUtil;
-import com.siyeh.InspectionGadgetsBundle;
-import com.siyeh.ig.BaseInspection;
-import com.siyeh.ig.BaseInspectionVisitor;
-import com.siyeh.ig.performance.InnerClassReferenceVisitor;
-import org.jetbrains.annotations.NotNull;
-
-public class AnonymousInnerClassMayBeStaticInspectionBase extends BaseInspection {
- @Override
- @NotNull
- public String getDisplayName() {
- return InspectionGadgetsBundle.message(
- "anonymous.inner.may.be.named.static.inner.class.display.name");
- }
-
- @Override
- @NotNull
- public String buildErrorString(Object... infos) {
- return InspectionGadgetsBundle.message(
- "anonymous.inner.may.be.named.static.inner.class.problem.descriptor");
- }
-
- @Override
- public BaseInspectionVisitor buildVisitor() {
- return new AnonymousInnerClassMayBeStaticVisitor();
- }
-
- private static class AnonymousInnerClassMayBeStaticVisitor
- extends BaseInspectionVisitor {
-
- @Override
- public void visitClass(@NotNull PsiClass aClass) {
- if (!(aClass instanceof PsiAnonymousClass)) {
- return;
- }
- if (aClass instanceof PsiEnumConstantInitializer) {
- return;
- }
- final PsiMember containingMember =
- PsiTreeUtil.getParentOfType(aClass, PsiMember.class);
- if (containingMember == null ||
- containingMember.hasModifierProperty(PsiModifier.STATIC)) {
- return;
- }
- final PsiAnonymousClass anAnonymousClass =
- (PsiAnonymousClass)aClass;
- final InnerClassReferenceVisitor visitor =
- new InnerClassReferenceVisitor(anAnonymousClass);
- anAnonymousClass.accept(visitor);
- if (!visitor.canInnerClassBeStatic()) {
- return;
- }
- registerClassError(aClass);
- }
- }
-}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/javadoc/MissingPackageInfoInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/javadoc/MissingPackageInfoInspectionBase.java
index 1305663d7710..dcd737d983fd 100644
--- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/javadoc/MissingPackageInfoInspection.java
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/javadoc/MissingPackageInfoInspectionBase.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2013 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -40,7 +40,7 @@ import java.util.List;
/**
* @author Bas Leijdekkers
*/
-public class MissingPackageInfoInspection extends BaseGlobalInspection {
+public class MissingPackageInfoInspectionBase extends BaseGlobalInspection {
@Nls
@NotNull
@@ -105,12 +105,12 @@ public class MissingPackageInfoInspection extends BaseGlobalInspection {
@Nullable
@Override
public LocalInspectionTool getSharedLocalInspectionTool() {
- return new LocalMissingPackageInfoInspection(this);
+ return new LocalMissingPackageInfoInspectionBase(this);
}
- private static class LocalMissingPackageInfoInspection extends BaseSharedLocalInspection<MissingPackageInfoInspection> {
+ protected static class LocalMissingPackageInfoInspectionBase extends BaseSharedLocalInspection<MissingPackageInfoInspectionBase> {
- public LocalMissingPackageInfoInspection(MissingPackageInfoInspection settingsDelegate) {
+ public LocalMissingPackageInfoInspectionBase(MissingPackageInfoInspectionBase settingsDelegate) {
super(settingsDelegate);
}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/memory/AnonymousInnerClassMayBeStaticInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/memory/AnonymousInnerClassMayBeStaticInspectionBase.java
new file mode 100644
index 000000000000..974646bdcb2a
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/memory/AnonymousInnerClassMayBeStaticInspectionBase.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.memory;
+
+import com.intellij.psi.*;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.util.PsiUtil;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.BaseInspection;
+import com.siyeh.ig.BaseInspectionVisitor;
+import org.jetbrains.annotations.NotNull;
+
+public class AnonymousInnerClassMayBeStaticInspectionBase extends BaseInspection {
+ @Override
+ @NotNull
+ public String getDisplayName() {
+ return InspectionGadgetsBundle.message(
+ "anonymous.inner.may.be.named.static.inner.class.display.name");
+ }
+
+ @Override
+ @NotNull
+ public String buildErrorString(Object... infos) {
+ return InspectionGadgetsBundle.message(
+ "anonymous.inner.may.be.named.static.inner.class.problem.descriptor");
+ }
+
+ @Override
+ public BaseInspectionVisitor buildVisitor() {
+ return new AnonymousInnerClassMayBeStaticVisitor();
+ }
+
+ private static class AnonymousInnerClassMayBeStaticVisitor
+ extends BaseInspectionVisitor {
+
+ @Override
+ public void visitAnonymousClass(@NotNull PsiAnonymousClass anonymousClass) {
+ if (anonymousClass instanceof PsiEnumConstantInitializer) {
+ return;
+ }
+ final PsiMember containingMember = PsiTreeUtil.getParentOfType(anonymousClass, PsiMember.class);
+ if (containingMember == null || containingMember.hasModifierProperty(PsiModifier.STATIC)) {
+ return;
+ }
+ final PsiJavaCodeReferenceElement reference = anonymousClass.getBaseClassReference();
+ if (reference.resolve() == null) {
+ // don't warn on broken code
+ return;
+ }
+ final PsiClass containingClass = PsiTreeUtil.getParentOfType(anonymousClass, PsiClass.class);
+ if (containingClass == null) {
+ return;
+ }
+ if (containingClass.getContainingClass() != null && !containingClass.hasModifierProperty(PsiModifier.STATIC)) {
+ // strictly speaking can be named static inner class but not when part of the current containing class
+ return;
+ }
+ final InnerClassReferenceVisitor visitor = new InnerClassReferenceVisitor(anonymousClass);
+ anonymousClass.accept(visitor);
+ if (!visitor.canInnerClassBeStatic()) {
+ return;
+ }
+ if (hasReferenceToLocalClass(anonymousClass)) {
+ return;
+ }
+ registerClassError(anonymousClass);
+ }
+
+ private static boolean hasReferenceToLocalClass(PsiAnonymousClass anonymousClass) {
+ final LocalClassReferenceVisitor visitor = new LocalClassReferenceVisitor();
+ anonymousClass.accept(visitor);
+ return visitor.hasReferenceToLocalClass();
+ }
+
+ private static class LocalClassReferenceVisitor extends JavaRecursiveElementVisitor {
+
+ private boolean referenceToLocalClass = false;
+
+ @Override
+ public void visitReferenceElement(PsiJavaCodeReferenceElement reference) {
+ super.visitReferenceElement(reference);
+ if (reference.getQualifier() != null) {
+ return;
+ }
+ final PsiElement target = reference.resolve();
+ if (!(target instanceof PsiClass) || !PsiUtil.isLocalClass((PsiClass)target)) {
+ return;
+ }
+ referenceToLocalClass = true;
+ }
+
+ public boolean hasReferenceToLocalClass() {
+ return referenceToLocalClass;
+ }
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/InnerClassMayBeStaticInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/memory/InnerClassMayBeStaticInspection.java
index 2599327e4d7d..f588b120b8d5 100644
--- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/InnerClassMayBeStaticInspection.java
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/memory/InnerClassMayBeStaticInspection.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2013 Dave Griffith, Bas Leijdekkers
+ * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.siyeh.ig.performance;
+package com.siyeh.ig.memory;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInspection.ProblemDescriptor;
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/memory/InnerClassReferenceVisitor.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/memory/InnerClassReferenceVisitor.java
new file mode 100644
index 000000000000..6f1f817a7735
--- /dev/null
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/memory/InnerClassReferenceVisitor.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * 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.siyeh.ig.memory;
+
+import com.intellij.psi.*;
+import com.intellij.psi.util.InheritanceUtil;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.siyeh.ig.psiutils.ParenthesesUtils;
+import org.jetbrains.annotations.NotNull;
+
+class InnerClassReferenceVisitor extends JavaRecursiveElementVisitor {
+
+ private final PsiClass innerClass;
+ private boolean referencesStaticallyAccessible = true;
+
+ public InnerClassReferenceVisitor(@NotNull PsiClass innerClass) {
+ this.innerClass = innerClass;
+ }
+
+ public boolean canInnerClassBeStatic() {
+ final PsiClass superClass = innerClass.getSuperClass();
+ if (!isClassStaticallyAccessible(superClass)) {
+ return false;
+ }
+ return referencesStaticallyAccessible;
+ }
+
+ private boolean isClassStaticallyAccessible(PsiClass aClass) {
+ if (PsiTreeUtil.isAncestor(innerClass, aClass, false) || aClass.hasModifierProperty(PsiModifier.STATIC)) {
+ return true;
+ }
+ final PsiClass containingClass = aClass.getContainingClass();
+ return containingClass == null || InheritanceUtil.isInheritorOrSelf(innerClass, containingClass, true);
+ }
+
+ @Override
+ public void visitThisExpression(@NotNull PsiThisExpression expression) {
+ if (!referencesStaticallyAccessible) {
+ return;
+ }
+ super.visitThisExpression(expression);
+ if (hasContainingClassQualifier(expression)) {
+ referencesStaticallyAccessible = false;
+ }
+ }
+
+ @Override
+ public void visitSuperExpression(@NotNull PsiSuperExpression expression) {
+ if (!referencesStaticallyAccessible) {
+ return;
+ }
+ super.visitSuperExpression(expression);
+ if (hasContainingClassQualifier(expression)) {
+ referencesStaticallyAccessible = false;
+ }
+ }
+
+ private boolean hasContainingClassQualifier(PsiQualifiedExpression expression) {
+ final PsiJavaCodeReferenceElement qualifier = expression.getQualifier();
+ if (qualifier == null) {
+ return false;
+ }
+ return !innerClass.equals(qualifier.resolve());
+ }
+
+ @Override
+ public void visitReferenceExpression(PsiReferenceExpression expression) {
+ if (!referencesStaticallyAccessible) {
+ return;
+ }
+ super.visitReferenceExpression(expression);
+ final PsiExpression qualifierExpression = ParenthesesUtils.stripParentheses(expression.getQualifierExpression());
+ if (qualifierExpression != null) {
+ return;
+ }
+ final PsiElement target = expression.resolve();
+ if (target instanceof PsiLocalVariable || target instanceof PsiParameter) {
+ return;
+ }
+ if (target instanceof PsiMethod || target instanceof PsiField) {
+ final PsiMember member = (PsiMember)target;
+ if (member.hasModifierProperty(PsiModifier.STATIC) || PsiTreeUtil.isAncestor(innerClass, member, true)) {
+ return;
+ }
+ if (!member.hasModifierProperty(PsiModifier.PRIVATE)) {
+ final PsiClass containingClass = member.getContainingClass();
+ if (InheritanceUtil.isInheritorOrSelf(innerClass, containingClass, true)) {
+ return;
+ }
+ }
+ referencesStaticallyAccessible = false;
+ }
+ }
+
+ @Override
+ public void visitNewExpression(PsiNewExpression expression) {
+ if (!referencesStaticallyAccessible) {
+ return;
+ }
+ super.visitNewExpression(expression);
+ final PsiJavaCodeReferenceElement classReference = expression.getClassOrAnonymousClassReference();
+ if (classReference == null) {
+ return;
+ }
+ final PsiElement target = classReference.resolve();
+ if (!(target instanceof PsiClass)) {
+ return;
+ }
+ if (!isClassStaticallyAccessible((PsiClass)target)) {
+ referencesStaticallyAccessible = false;
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/InnerClassReferenceVisitor.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/InnerClassReferenceVisitor.java
deleted file mode 100644
index 45d89b4a4b1d..000000000000
--- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/InnerClassReferenceVisitor.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright 2003-2013 Dave Griffith, Bas Leijdekkers
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * 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.siyeh.ig.performance;
-
-import com.intellij.psi.*;
-import com.intellij.psi.util.InheritanceUtil;
-import com.intellij.psi.util.PsiTreeUtil;
-import com.siyeh.ig.psiutils.ClassUtils;
-import org.jetbrains.annotations.NotNull;
-
-public class InnerClassReferenceVisitor extends JavaRecursiveElementVisitor {
-
- private final PsiClass innerClass;
- private boolean referencesStaticallyAccessible = true;
-
- public InnerClassReferenceVisitor(PsiClass innerClass) {
- this.innerClass = innerClass;
- }
-
- public boolean canInnerClassBeStatic() {
- return referencesStaticallyAccessible;
- }
-
- private boolean isClassStaticallyAccessible(PsiClass aClass) {
- if (PsiTreeUtil.isAncestor(innerClass, aClass, false)) {
- return true;
- }
- if (aClass.getContainingClass() != null) {
- return aClass.hasModifierProperty(PsiModifier.STATIC);
- }
- if (InheritanceUtil.isInheritorOrSelf(innerClass, aClass, true)) {
- return true;
- }
- PsiClass classScope = aClass;
- final PsiClass outerClass = ClassUtils.getContainingClass(innerClass);
- while (classScope != null) {
- if (InheritanceUtil.isInheritorOrSelf(outerClass, classScope, true)) {
- return false;
- }
- final PsiElement scope = classScope.getScope();
- if (scope instanceof PsiClass) {
- classScope = (PsiClass)scope;
- }
- else {
- classScope = null;
- }
- }
- return true;
- }
-
- @Override
- public void visitThisExpression(@NotNull PsiThisExpression expression) {
- if (!referencesStaticallyAccessible) {
- return;
- }
- super.visitThisExpression(expression);
- if (hasContainingClassQualifier(expression)) {
- referencesStaticallyAccessible = false;
- }
- }
-
- @Override
- public void visitSuperExpression(@NotNull PsiSuperExpression expression) {
- if (!referencesStaticallyAccessible) {
- return;
- }
- super.visitSuperExpression(expression);
- if (hasContainingClassQualifier(expression)) {
- referencesStaticallyAccessible = false;
- }
- }
-
- private boolean hasContainingClassQualifier(PsiQualifiedExpression expression) {
- final PsiJavaCodeReferenceElement qualifier = expression.getQualifier();
- if (qualifier == null) {
- return false;
- }
- final PsiElement element = qualifier.resolve();
- if (!(element instanceof PsiClass)) {
- return false;
- }
- final PsiClass aClass = (PsiClass)element;
- return !aClass.equals(innerClass);
- }
-
- @Override
- public void visitReferenceElement(@NotNull PsiJavaCodeReferenceElement reference) {
- if (!referencesStaticallyAccessible) {
- return;
- }
- final PsiElement parent = reference.getParent();
- if (parent instanceof PsiThisExpression || parent instanceof PsiSuperExpression) {
- return;
- }
- super.visitReferenceElement(reference);
-
- final PsiElement qualifier = reference.getQualifier();
- if (qualifier instanceof PsiSuperExpression) {
- return;
- }
- if (qualifier instanceof PsiReferenceExpression) {
- final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)qualifier;
- final PsiElement resolvedExpression = referenceExpression.resolve();
- if (!(resolvedExpression instanceof PsiField) && !(resolvedExpression instanceof PsiMethod)) {
- return;
- }
- }
- final PsiElement element = reference.resolve();
- if (element instanceof PsiMethod || element instanceof PsiField) {
- final PsiMember member = (PsiMember)element;
- if (member.hasModifierProperty(PsiModifier.STATIC)) {
- return;
- }
- final PsiClass containingClass = member.getContainingClass();
- if (innerClass.equals(containingClass)) {
- return;
- }
- if (member.hasModifierProperty(PsiModifier.PRIVATE)) {
- referencesStaticallyAccessible = false;
- return;
- }
- referencesStaticallyAccessible &= isClassStaticallyAccessible(containingClass);
- }
- else if (element instanceof PsiLocalVariable || element instanceof PsiParameter) {
- final PsiElement containingMethod = PsiTreeUtil.getParentOfType(reference, PsiMethod.class);
- final PsiElement referencedMethod = PsiTreeUtil.getParentOfType(element, PsiMethod.class);
- if (containingMethod != null && referencedMethod != null && !containingMethod.equals(referencedMethod)) {
- referencesStaticallyAccessible = false;
- }
- }
- else if (element instanceof PsiClass) {
- final PsiClass aClass = (PsiClass)element;
- referencesStaticallyAccessible &= isClassStaticallyAccessible(aClass);
- }
- }
-}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ClassUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ClassUtils.java
index 40daa3332896..4656d0c4610a 100644
--- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ClassUtils.java
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ClassUtils.java
@@ -19,6 +19,7 @@ import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.TypeConversionUtil;
import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.Nullable;
import java.util.HashSet;
@@ -80,7 +81,7 @@ public class ClassUtils {
private ClassUtils() {}
@Nullable
- public static PsiClass findClass(String fqClassName, PsiElement context) {
+ public static PsiClass findClass(@NonNls String fqClassName, PsiElement context) {
return JavaPsiFacade.getInstance(context.getProject()).findClass(fqClassName, context.getResolveScope());
}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ExpressionUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ExpressionUtils.java
index fc6d2580b3e9..242bec97a398 100644
--- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ExpressionUtils.java
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ExpressionUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2005-2013 Bas Leijdekkers
+ * Copyright 2005-2014 Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -198,11 +198,8 @@ public class ExpressionUtils {
}
public static boolean isNullLiteral(@Nullable PsiExpression expression) {
- if (!(expression instanceof PsiLiteralExpression)) {
- return false;
- }
- final String text = expression.getText();
- return PsiKeyword.NULL.equals(text);
+ expression = ParenthesesUtils.stripParentheses(expression);
+ return expression != null && PsiType.NULL.equals(expression.getType());
}
public static boolean isZero(@Nullable PsiExpression expression) {
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/CStyleArrayDeclarationInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/CStyleArrayDeclarationInspection.java
index e4e91685878b..fca66288aaef 100644
--- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/CStyleArrayDeclarationInspection.java
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/CStyleArrayDeclarationInspection.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2007 Dave Griffith, Bas Leijdekkers
+ * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,20 +16,24 @@
package com.siyeh.ig.style;
import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel;
import com.intellij.openapi.project.Project;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiType;
-import com.intellij.psi.PsiTypeElement;
-import com.intellij.psi.PsiVariable;
-import com.intellij.util.IncorrectOperationException;
+import com.intellij.psi.*;
+import com.intellij.psi.codeStyle.CodeStyleManager;
+import com.intellij.psi.tree.IElementType;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
import com.siyeh.ig.InspectionGadgetsFix;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
public class CStyleArrayDeclarationInspection extends BaseInspection {
+ public boolean ignoreVariables = false;
+
@Override
@NotNull
public String getDisplayName() {
@@ -40,8 +44,18 @@ public class CStyleArrayDeclarationInspection extends BaseInspection {
@Override
@NotNull
protected String buildErrorString(Object... infos) {
- return InspectionGadgetsBundle.message(
- "c.style.array.declaration.problem.descriptor");
+ final Object info = infos[0];
+ if (info instanceof PsiMethod) {
+ return InspectionGadgetsBundle.message("cstyle.array.method.declaration.problem.descriptor");
+ }
+ final int choice = info instanceof PsiField ? 1 : info instanceof PsiParameter ? 2 : 3;
+ return InspectionGadgetsBundle.message("cstyle.array.variable.declaration.problem.descriptor", Integer.valueOf(choice));
+ }
+
+ @Nullable
+ @Override
+ public JComponent createOptionsPanel() {
+ return new SingleCheckboxOptionsPanel("Ignore C-style declarations in variables", this, "ignoreVariables");
}
@Override
@@ -65,12 +79,38 @@ public class CStyleArrayDeclarationInspection extends BaseInspection {
}
@Override
- public void doFix(Project project, ProblemDescriptor descriptor)
- throws IncorrectOperationException {
- final PsiElement nameElement = descriptor.getPsiElement();
- final PsiVariable var = (PsiVariable)nameElement.getParent();
- assert var != null;
- var.normalizeDeclaration();
+ public void doFix(Project project, ProblemDescriptor descriptor) {
+ final PsiElement element = descriptor.getPsiElement().getParent();
+ if (element instanceof PsiVariable) {
+ final PsiVariable variable = (PsiVariable)element;
+ variable.normalizeDeclaration();
+ CodeStyleManager.getInstance(project).reformat(variable);
+ }
+ else if (element instanceof PsiMethod) {
+ final PsiMethod method = (PsiMethod)element;
+ final PsiTypeElement returnTypeElement = method.getReturnTypeElement();
+ if (returnTypeElement == null) {
+ return;
+ }
+ final PsiType returnType = method.getReturnType();
+ if (returnType == null) {
+ return;
+ }
+ PsiElement child = method.getParameterList();
+ while (!(child instanceof PsiCodeBlock)) {
+ final PsiElement element1 = child;
+ child = child.getNextSibling();
+ if (element1 instanceof PsiJavaToken) {
+ final PsiJavaToken token = (PsiJavaToken)element1;
+ final IElementType tokenType = token.getTokenType();
+ if (JavaTokenType.LBRACKET.equals(tokenType) || JavaTokenType.RBRACKET.equals(tokenType)) {
+ token.delete();
+ }
+ }
+ }
+ final PsiTypeElement typeElement = JavaPsiFacade.getElementFactory(project).createTypeElement(returnType);
+ returnTypeElement.replace(typeElement);
+ }
}
}
@@ -79,17 +119,19 @@ public class CStyleArrayDeclarationInspection extends BaseInspection {
return new CStyleArrayDeclarationVisitor();
}
- private static class CStyleArrayDeclarationVisitor
- extends BaseInspectionVisitor {
+ private class CStyleArrayDeclarationVisitor extends BaseInspectionVisitor {
@Override
- public void visitVariable(@NotNull PsiVariable var) {
- super.visitVariable(var);
- final PsiType declaredType = var.getType();
+ public void visitVariable(@NotNull PsiVariable variable) {
+ super.visitVariable(variable);
+ if (ignoreVariables) {
+ return;
+ }
+ final PsiType declaredType = variable.getType();
if (declaredType.getArrayDimensions() == 0) {
return;
}
- final PsiTypeElement typeElement = var.getTypeElement();
+ final PsiTypeElement typeElement = variable.getTypeElement();
if (typeElement == null) {
return; // Could be true for enum constants.
}
@@ -97,7 +139,25 @@ public class CStyleArrayDeclarationInspection extends BaseInspection {
if (elementType.equals(declaredType)) {
return;
}
- registerVariableError(var);
+ registerVariableError(variable, variable);
+ }
+
+ @Override
+ public void visitMethod(PsiMethod method) {
+ super.visitMethod(method);
+ final PsiType returnType = method.getReturnType();
+ if (returnType == null || returnType.getArrayDimensions() == 0) {
+ return;
+ }
+ final PsiTypeElement typeElement = method.getReturnTypeElement();
+ if (typeElement == null) {
+ return;
+ }
+ final PsiType type = typeElement.getType();
+ if (type.equals(returnType)) {
+ return;
+ }
+ registerMethodError(method, method);
}
}
} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/NestedMethodCallInspectionBase.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/NestedMethodCallInspectionBase.java
index 484c1f8fefe0..57659d05923a 100644
--- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/NestedMethodCallInspectionBase.java
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/NestedMethodCallInspectionBase.java
@@ -16,6 +16,7 @@
package com.siyeh.ig.style;
import com.intellij.psi.*;
+import com.intellij.psi.util.PropertyUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
@@ -29,6 +30,12 @@ public class NestedMethodCallInspectionBase extends BaseInspection {
*/
public boolean m_ignoreFieldInitializations = true;
+ @SuppressWarnings("PublicField")
+ public boolean ignoreStaticMethods = false;
+
+ @SuppressWarnings("PublicField")
+ public boolean ignoreGetterCalls = false;
+
@Override
@NotNull
public String getDisplayName() {
@@ -82,6 +89,18 @@ public class NestedMethodCallInspectionBase extends BaseInspection {
return;
}
}
+ final PsiMethod method = expression.resolveMethod();
+ if (method == null) {
+ return;
+ }
+ if (ignoreStaticMethods || ignoreGetterCalls) {
+ if (ignoreStaticMethods && method.hasModifierProperty(PsiModifier.STATIC)) {
+ return;
+ }
+ if (ignoreGetterCalls && PropertyUtil.isSimpleGetter(method)) {
+ return;
+ }
+ }
registerMethodCallError(expression);
}
}
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/DoubleCheckedLockingInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/DoubleCheckedLockingInspection.java
index 0036f4a41f99..d9f5242d3ab6 100644
--- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/DoubleCheckedLockingInspection.java
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/DoubleCheckedLockingInspection.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2010 Dave Griffith, Bas Leijdekkers
+ * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,7 +20,6 @@ import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.tree.IElementType;
-import com.intellij.util.IncorrectOperationException;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
@@ -74,17 +73,16 @@ public class DoubleCheckedLockingInspection extends BaseInspection {
private static class DoubleCheckedLockingFix extends InspectionGadgetsFix {
- private final PsiField field;
+ private final String myFieldName;
private DoubleCheckedLockingFix(PsiField field) {
- this.field = field;
+ myFieldName = field.getName();
}
@Override
@NotNull
public String getName() {
- return InspectionGadgetsBundle.message(
- "double.checked.locking.quickfix", field.getName());
+ return InspectionGadgetsBundle.message("double.checked.locking.quickfix", myFieldName);
}
@NotNull
@@ -94,8 +92,21 @@ public class DoubleCheckedLockingInspection extends BaseInspection {
}
@Override
- protected void doFix(Project project, ProblemDescriptor descriptor)
- throws IncorrectOperationException {
+ protected void doFix(Project project, ProblemDescriptor descriptor) {
+ final PsiElement element = descriptor.getPsiElement();
+ final PsiElement parent = element.getParent();
+ if (!(parent instanceof PsiIfStatement)) {
+ return;
+ }
+ final PsiIfStatement ifStatement = (PsiIfStatement)parent;
+ final PsiExpression condition = ifStatement.getCondition();
+ if (condition == null) {
+ return;
+ }
+ final PsiField field = findCheckedField(condition);
+ if (field == null) {
+ return;
+ }
final PsiModifierList modifierList = field.getModifierList();
if (modifierList == null) {
return;
@@ -104,13 +115,55 @@ public class DoubleCheckedLockingInspection extends BaseInspection {
}
}
+ @Nullable
+ private static PsiField findCheckedField(PsiExpression expression) {
+ if (expression instanceof PsiReferenceExpression) {
+ final PsiReferenceExpression referenceExpression =
+ (PsiReferenceExpression)expression;
+ final PsiElement target = referenceExpression.resolve();
+ if (!(target instanceof PsiField)) {
+ return null;
+ }
+ return (PsiField)target;
+ }
+ else if (expression instanceof PsiBinaryExpression) {
+ final PsiBinaryExpression binaryExpression =
+ (PsiBinaryExpression)expression;
+ final IElementType tokenType =
+ binaryExpression.getOperationTokenType();
+ if (!JavaTokenType.EQEQ.equals(tokenType)
+ && !JavaTokenType.NE.equals(tokenType)) {
+ return null;
+ }
+ final PsiExpression lhs = binaryExpression.getLOperand();
+ final PsiExpression rhs = binaryExpression.getROperand();
+ final PsiField field = findCheckedField(lhs);
+ if (field != null) {
+ return field;
+ }
+ return findCheckedField(rhs);
+ }
+ else if (expression instanceof PsiPrefixExpression) {
+ final PsiPrefixExpression prefixExpression =
+ (PsiPrefixExpression)expression;
+ final IElementType tokenType =
+ prefixExpression.getOperationTokenType();
+ if (!JavaTokenType.EXCL.equals(tokenType)) {
+ return null;
+ }
+ return findCheckedField(prefixExpression.getOperand());
+ }
+ else {
+ return null;
+ }
+ }
+
@Override
public BaseInspectionVisitor buildVisitor() {
return new DoubleCheckedLockingVisitor();
}
- private class DoubleCheckedLockingVisitor
- extends BaseInspectionVisitor {
+ private class DoubleCheckedLockingVisitor extends BaseInspectionVisitor {
@Override
public void visitIfStatement(
@@ -161,48 +214,5 @@ public class DoubleCheckedLockingInspection extends BaseInspection {
}
registerStatementError(statement, field);
}
-
- @Nullable
- private PsiField findCheckedField(PsiExpression expression) {
- if (expression instanceof PsiReferenceExpression) {
- final PsiReferenceExpression referenceExpression =
- (PsiReferenceExpression)expression;
- final PsiElement target = referenceExpression.resolve();
- if (!(target instanceof PsiField)) {
- return null;
- }
- return (PsiField)target;
- }
- else if (expression instanceof PsiBinaryExpression) {
- final PsiBinaryExpression binaryExpression =
- (PsiBinaryExpression)expression;
- final IElementType tokenType =
- binaryExpression.getOperationTokenType();
- if (!JavaTokenType.EQEQ.equals(tokenType)
- && !JavaTokenType.NE.equals(tokenType)) {
- return null;
- }
- final PsiExpression lhs = binaryExpression.getLOperand();
- final PsiExpression rhs = binaryExpression.getROperand();
- final PsiField field = findCheckedField(lhs);
- if (field != null) {
- return field;
- }
- return findCheckedField(rhs);
- }
- else if (expression instanceof PsiPrefixExpression) {
- final PsiPrefixExpression prefixExpression =
- (PsiPrefixExpression)expression;
- final IElementType tokenType =
- prefixExpression.getOperationTokenType();
- if (!JavaTokenType.EXCL.equals(tokenType)) {
- return null;
- }
- return findCheckedField(prefixExpression.getOperand());
- }
- else {
- return null;
- }
- }
}
} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/initialization/NonThreadSafeLazyInitializationInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/initialization/NonThreadSafeLazyInitializationInspection.java
new file mode 100644
index 000000000000..7b2355930287
--- /dev/null
+++ b/plugins/InspectionGadgets/src/com/siyeh/ig/initialization/NonThreadSafeLazyInitializationInspection.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.initialization;
+
+import com.intellij.codeInsight.CodeInsightUtilCore;
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.fileEditor.FileEditorManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Pass;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.*;
+import com.intellij.psi.search.searches.ReferencesSearch;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.util.PsiUtil;
+import com.intellij.refactoring.rename.RenamePsiElementProcessor;
+import com.intellij.refactoring.rename.inplace.MemberInplaceRenamer;
+import com.intellij.util.Processor;
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.InspectionGadgetsFix;
+import com.siyeh.ig.psiutils.ControlFlowUtils;
+import com.siyeh.ig.psiutils.ParenthesesUtils;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.LinkedHashSet;
+
+/**
+ * @author Bas Leijdekkers
+ */
+public class NonThreadSafeLazyInitializationInspection extends NonThreadSafeLazyInitializationInspectionBase {
+
+ @Override
+ protected InspectionGadgetsFix buildFix(Object... infos) {
+ final PsiIfStatement ifStatement = (PsiIfStatement)infos[0];
+ final PsiField field = (PsiField)infos[1];
+ if (!isStaticAndAssignedOnce(field) || !isSafeToDeleteIfStatement(ifStatement, field)) {
+ return null;
+ }
+ return new IntroduceHolderFix();
+ }
+
+ private static boolean isStaticAndAssignedOnce(PsiField field) {
+ if (!field.hasModifierProperty(PsiModifier.STATIC)) {
+ return false;
+ }
+ final int[] writeCount = new int[1];
+ return ReferencesSearch.search(field).forEach(new Processor<PsiReference>() {
+ @Override
+ public boolean process(PsiReference reference) {
+ final PsiElement element = reference.getElement();
+ if (!(element instanceof PsiExpression) || !PsiUtil.isAccessedForWriting((PsiExpression)element)) {
+ return true;
+ }
+ return ++writeCount[0] != 2;
+ }
+ });
+ }
+
+ private static boolean isSafeToDeleteIfStatement(PsiIfStatement ifStatement, PsiField field) {
+ if (ifStatement.getElseBranch() != null) {
+ return false;
+ }
+ final PsiStatement thenBranch = ifStatement.getThenBranch();
+ if (thenBranch == null) {
+ return false;
+ }
+ final PsiStatement statement = ControlFlowUtils.stripBraces(thenBranch);
+ if (!(statement instanceof PsiExpressionStatement)) {
+ return false;
+ }
+ final PsiExpressionStatement expressionStatement = (PsiExpressionStatement)statement;
+ return isSimpleAssignment(expressionStatement, field);
+ }
+
+ private static boolean isSimpleAssignment(PsiExpressionStatement expressionStatement, PsiField field) {
+ final PsiExpression expression = expressionStatement.getExpression();
+ if (!(expression instanceof PsiAssignmentExpression)) {
+ return false;
+ }
+ final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression)expression;
+ final PsiExpression lhs = ParenthesesUtils.stripParentheses(assignmentExpression.getLExpression());
+ if (!(lhs instanceof PsiReferenceExpression)) {
+ return false;
+ }
+ final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)lhs;
+ final PsiElement target = referenceExpression.resolve();
+ if (!field.equals(target)) {
+ return false;
+ }
+ final Collection<PsiReferenceExpression> referenceChildren =
+ PsiTreeUtil.findChildrenOfType(assignmentExpression.getRExpression(), PsiReferenceExpression.class);
+ for (PsiReferenceExpression child : referenceChildren) {
+ final PsiElement target2 = child.resolve();
+ if (!(target2 instanceof PsiMember)) {
+ return false;
+ }
+ final PsiMember member = (PsiMember)target2;
+ if (!member.hasModifierProperty(PsiModifier.STATIC)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static class IntroduceHolderFix extends InspectionGadgetsFix {
+
+ @Override
+ protected void doFix(Project project, ProblemDescriptor descriptor) {
+ final PsiReferenceExpression expression = (PsiReferenceExpression)descriptor.getPsiElement();
+ final PsiElement resolved = expression.resolve();
+ if (!(resolved instanceof PsiField)) {
+ return;
+ }
+ final PsiField field = (PsiField)resolved;
+ @NonNls final String holderName = StringUtil.capitalize(field.getName()) + "Holder";
+ final PsiElement expressionParent = expression.getParent();
+ if (!(expressionParent instanceof PsiAssignmentExpression)) {
+ return;
+ }
+ final PsiAssignmentExpression assignmentExpression = (PsiAssignmentExpression)expressionParent;
+ final PsiExpression rhs = assignmentExpression.getRExpression();
+ if (rhs == null) {
+ return;
+ }
+ @NonNls final String text = "private static class " + holderName + " {" +
+ "private static final " + field.getType().getCanonicalText() + " " +
+ field.getName() + " = " + rhs.getText() + ";}";
+ final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(field.getProject());
+ final PsiClass holder = elementFactory.createClassFromText(text, field).getInnerClasses()[0];
+ final PsiMethod method = PsiTreeUtil.getParentOfType(expression, PsiMethod.class);
+ if (method == null) {
+ return;
+ }
+ final PsiClass holderClass = (PsiClass)method.getParent().addBefore(holder, method);
+
+ final PsiIfStatement ifStatement = PsiTreeUtil.getParentOfType(expression, PsiIfStatement.class);
+ if (ifStatement != null) {
+ ifStatement.delete();
+ }
+
+ final PsiExpression holderReference = elementFactory.createExpressionFromText(holderName + "." + field.getName(), field);
+ for (PsiReference reference : ReferencesSearch.search(field).findAll()) {
+ reference.getElement().replace(holderReference);
+ }
+ field.delete();
+
+ if (!isOnTheFly()) {
+ return;
+ }
+ invokeInplaceRename(holderClass, holderName, suggestHolderName(field));
+ }
+
+ private static void invokeInplaceRename(PsiNameIdentifierOwner nameIdentifierOwner, final String... suggestedNames) {
+ final PsiNameIdentifierOwner elementToRename = CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(nameIdentifierOwner);
+ final Editor editor = FileEditorManager.getInstance(nameIdentifierOwner.getProject()).getSelectedTextEditor();
+ if (editor == null) {
+ return;
+ }
+ final PsiElement identifier = elementToRename.getNameIdentifier();
+ if (identifier == null) {
+ return;
+ }
+ editor.getCaretModel().moveToOffset(identifier.getTextOffset());
+ final RenamePsiElementProcessor processor = RenamePsiElementProcessor.forElement(elementToRename);
+ if (!processor.isInplaceRenameSupported()) {
+ return;
+ }
+ processor.substituteElementToRename(elementToRename, editor, new Pass<PsiElement>() {
+ @Override
+ public void pass(PsiElement substitutedElement) {
+ final MemberInplaceRenamer renamer = new MemberInplaceRenamer(elementToRename, substitutedElement, editor);
+ final LinkedHashSet<String> nameSuggestions = new LinkedHashSet<String>(Arrays.asList(suggestedNames));
+ renamer.performInplaceRefactoring(nameSuggestions);
+ }
+ });
+ }
+
+ @NonNls
+ private static String suggestHolderName(PsiField field) {
+ String string = field.getType().getDeepComponentType().getPresentableText();
+ final int index = string.indexOf('<');
+ if (index != -1) {
+ string = string.substring(0, index);
+ }
+ return string + "Holder";
+ }
+
+ @Override
+ @NotNull
+ public String getName() {
+ return InspectionGadgetsBundle.message("introduce.holder.class.quickfix");
+ }
+
+ @NotNull
+ @Override
+ public String getFamilyName() {
+ return getName();
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/javadoc/MissingPackageInfoInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/javadoc/MissingPackageInfoInspection.java
new file mode 100644
index 000000000000..2c498c207913
--- /dev/null
+++ b/plugins/InspectionGadgets/src/com/siyeh/ig/javadoc/MissingPackageInfoInspection.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.javadoc;
+
+import com.intellij.codeInspection.LocalInspectionTool;
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.ide.DataManager;
+import com.intellij.ide.actions.CreatePackageInfoAction;
+import com.intellij.openapi.actionSystem.ActionManager;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.actionSystem.Presentation;
+import com.intellij.openapi.project.Project;
+import com.intellij.util.Consumer;
+import com.siyeh.ig.InspectionGadgetsFix;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author Bas Leijdekkers
+ */
+public class MissingPackageInfoInspection extends MissingPackageInfoInspectionBase {
+
+ @Nullable
+ @Override
+ public LocalInspectionTool getSharedLocalInspectionTool() {
+ return new LocalMissingPackageInfoInspection(this);
+ }
+
+ private class LocalMissingPackageInfoInspection extends LocalMissingPackageInfoInspectionBase {
+
+ public LocalMissingPackageInfoInspection(MissingPackageInfoInspectionBase settingsDelegate) {
+ super(settingsDelegate);
+ }
+
+ @Nullable
+ @Override
+ protected InspectionGadgetsFix buildFix(Object... infos) {
+ return new InspectionGadgetsFix() {
+ @NotNull
+ @Override
+ public String getName() {
+ return "Create 'package-info.java'";
+ }
+
+ @NotNull
+ @Override
+ public String getFamilyName() {
+ return getName();
+ }
+
+ @Override
+ protected boolean prepareForWriting() {
+ return false;
+ }
+
+ @Override
+ protected void doFix(Project project, ProblemDescriptor descriptor) {
+ DataManager.getInstance().getDataContextFromFocus().doWhenDone(new Consumer<DataContext>() {
+ @Override
+ public void consume(DataContext context) {
+ final AnActionEvent event = new AnActionEvent(null, context, "", new Presentation(), ActionManager.getInstance(), 0);
+ new CreatePackageInfoAction().actionPerformed(event);
+ }
+ });
+ }
+ };
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/j2me/AnonymousInnerClassMayBeStaticInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/memory/AnonymousInnerClassMayBeStaticInspection.java
index 6862eaf3fd14..f403f1326bd0 100644
--- a/plugins/InspectionGadgets/src/com/siyeh/ig/j2me/AnonymousInnerClassMayBeStaticInspection.java
+++ b/plugins/InspectionGadgets/src/com/siyeh/ig/memory/AnonymousInnerClassMayBeStaticInspection.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2008 Dave Griffith, Bas Leijdekkers
+ * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.siyeh.ig.j2me;
+package com.siyeh.ig.memory;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.InspectionGadgetsFix;
diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/style/NestedMethodCallInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/style/NestedMethodCallInspection.java
index bcdcf61c9175..097a24573328 100644
--- a/plugins/InspectionGadgets/src/com/siyeh/ig/style/NestedMethodCallInspection.java
+++ b/plugins/InspectionGadgets/src/com/siyeh/ig/style/NestedMethodCallInspection.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2012 Dave Griffith, Bas Leijdekkers
+ * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,7 +15,7 @@
*/
package com.siyeh.ig.style;
-import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel;
+import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.InspectionGadgetsFix;
import com.siyeh.ig.fixes.IntroduceVariableFix;
@@ -26,8 +26,11 @@ public class NestedMethodCallInspection extends NestedMethodCallInspectionBase {
@Override
public JComponent createOptionsPanel() {
- return new SingleCheckboxOptionsPanel(InspectionGadgetsBundle.message("nested.method.call.ignore.option"),
- this, "m_ignoreFieldInitializations");
+ final MultipleCheckboxOptionsPanel panel = new MultipleCheckboxOptionsPanel(this);
+ panel.addCheckbox(InspectionGadgetsBundle.message("nested.method.call.ignore.option"), "m_ignoreFieldInitializations");
+ panel.addCheckbox(InspectionGadgetsBundle.message("ignore.calls.to.static.methods"), "ignoreStaticMethods");
+ panel.addCheckbox(InspectionGadgetsBundle.message("ignore.calls.to.property.getters"), "ignoreGetterCalls");
+ return panel;
}
@Override
diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/AmbiguousFieldAccess.html b/plugins/InspectionGadgets/src/inspectionDescriptions/AmbiguousFieldAccess.html
index b0f698b74e7e..c8c714b78f40 100644
--- a/plugins/InspectionGadgets/src/inspectionDescriptions/AmbiguousFieldAccess.html
+++ b/plugins/InspectionGadgets/src/inspectionDescriptions/AmbiguousFieldAccess.html
@@ -1,9 +1,9 @@
<html>
<body>
-Reports field accesses of a super class where a local variable, parameter or field of the same name is available
-in the surrounding class. In this case a cursory reader of the code may think that a variable in the surrounding class is
-accessed, when in fact a field from the super class is accessed. To make the intent of the code more clear it is recommended to add a
-<b>this</b> qualifier to the field access call.
+Reports ambiguous accesses of a super class field from an inner or anonymous class, where a local variable, parameter or field with identical name is available
+in the surrounding code. In this situation a cursory examination of the code may suggest that an element in the surrounding code is
+accessed, when in actual fact a field from the super class is accessed. To clarify the intent of the code it is recommended to add a
+<b>super</b> qualifier to the field access.
<p>Example:
<pre><code>
<b>class</b> X {
diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/AmbiguousMethodCall.html b/plugins/InspectionGadgets/src/inspectionDescriptions/AmbiguousMethodCall.html
index 47bb71c5aee4..e1384463c5e1 100644
--- a/plugins/InspectionGadgets/src/inspectionDescriptions/AmbiguousMethodCall.html
+++ b/plugins/InspectionGadgets/src/inspectionDescriptions/AmbiguousMethodCall.html
@@ -1,10 +1,10 @@
<html>
<body>
-Reports any method calls to super methods where a method
-with the same name is available in the surrounding class. In this case a cursory
-reader of the code may think that a method in the surrounding class is
-called, when in fact a method from the super class is called. To make the
-intent of the code more clear it is recommended to add a
+Reports ambiguous method calls to a super method from an inner or anonymous class, where a method
+with identical name is available in the surrounding class. In this situation a cursory
+examination of the code may suggest a method in the surrounding class is
+called, when in actual fact a method from the super class is called. To clarify the
+intent of the code it is recommended to add a
<b>super</b> qualifier to the method call.
<!-- tooltip end -->
<p>
diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/AnonymousInnerClassMayBeStatic.html b/plugins/InspectionGadgets/src/inspectionDescriptions/AnonymousInnerClassMayBeStatic.html
index 9311966c365b..a0794ca5dfc8 100644
--- a/plugins/InspectionGadgets/src/inspectionDescriptions/AnonymousInnerClassMayBeStatic.html
+++ b/plugins/InspectionGadgets/src/inspectionDescriptions/AnonymousInnerClassMayBeStatic.html
@@ -1,11 +1,10 @@
<html>
<body>
-This inspection is intended for J2ME and other highly resource constrained environments.
-Applying the results of this inspection without consideration might have negative effects on code clarity and design.
+Reports any anonymous classes which may safely be made into a named <b>static</b> inner class.
+An anonymous class may be <b>static</b> if it doesn't explicitly reference its enclosing instance or local variables from its surrounding method.
<p>
-Reports any anonymous inner classes which may safely be made into a named
-<b>static</b> inner class. An inner class may be static if it doesn't reference
-its enclosing class instance or local variables. A static inner class uses slightly less memory.
+A <b>static</b> inner class does not keep an implicit reference to its enclosing instance.
+This prevents a common cause of memory leaks and uses less memory per instance of the class.
<!-- tooltip end -->
<p>
diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/CStyleArrayDeclaration.html b/plugins/InspectionGadgets/src/inspectionDescriptions/CStyleArrayDeclaration.html
index 6b8f3ff43b2a..7320abc37f19 100644
--- a/plugins/InspectionGadgets/src/inspectionDescriptions/CStyleArrayDeclaration.html
+++ b/plugins/InspectionGadgets/src/inspectionDescriptions/CStyleArrayDeclaration.html
@@ -1,9 +1,18 @@
<html>
<body>
-Reports array declarations made using C-style syntax, with the array indicator attached to the variable,
-rather than Java-style syntax, with the array indicator attached to the type.
+Reports array declarations made using C-style syntax,
+with the array indicator brackets positioned after the variable name or after the method parameter list.
+For example:
+<code><pre>
+ <b>public</b> String process(String value[])[] {
+ return value;
+ }
+</pre></code>
+Most code styles prefer Java-style array declarations, with the array indicator brackets attached to the type name.
<!-- tooltip end -->
<p>
+Use the checkbox below to only report C-style array declaration of method return types.
+<p>
</body>
</html> \ No newline at end of file
diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/DoubleBraceInitialization.html b/plugins/InspectionGadgets/src/inspectionDescriptions/DoubleBraceInitialization.html
new file mode 100644
index 000000000000..e2cf8b607f66
--- /dev/null
+++ b/plugins/InspectionGadgets/src/inspectionDescriptions/DoubleBraceInitialization.html
@@ -0,0 +1,13 @@
+<html>
+<body>
+Reports <a href="http://www.c2.com/cgi/wiki?DoubleBraceInitialization">Double Brace Initialization</a>.
+Double brace initialization can cause memory leaks when used from a non-<b>static</b> context,
+because the anonymous <b>class</b> created will maintain a reference to the surrounding object.
+It has worse performance than regular initialization because of the additional class loading required.
+It can cause <b>equals()</b> comparisons to fail, if the <b>equals()</b> method does not accept subclasses as parameter (see link above).
+And finally, it cannot be combined with Java 7 diamond operator, because that cannot be used with anonymous classes.
+<!-- tooltip end -->
+<p>
+ <small>New in 14</small>
+</body>
+</html> \ No newline at end of file
diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/DoubleCheckedLocking.html b/plugins/InspectionGadgets/src/inspectionDescriptions/DoubleCheckedLocking.html
index efa4d7a0ec34..e50edd8a9fc3 100644
--- a/plugins/InspectionGadgets/src/inspectionDescriptions/DoubleCheckedLocking.html
+++ b/plugins/InspectionGadgets/src/inspectionDescriptions/DoubleCheckedLocking.html
@@ -6,9 +6,9 @@ discussion of double-checked locking and why it is unsafe, see
">http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html</a>
<!-- tooltip end -->
<p>
-Use the checkbox below to ignore double-checked locking on volatile fields. Using
-a volatile field for double-checked locking works correctly on virtual machines which
-implement the new Java Memory Model.
+Use the checkbox below to ignore double-checked locking on <b>volatile</b> fields. Using
+a <b>volatile</b> field for double-checked locking works correctly on virtual machines which
+implement the Java Memory Model.
<p>
</body>
diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/InnerClassMayBeStatic.html b/plugins/InspectionGadgets/src/inspectionDescriptions/InnerClassMayBeStatic.html
index 8d81ee6a4292..578f60b2d618 100644
--- a/plugins/InspectionGadgets/src/inspectionDescriptions/InnerClassMayBeStatic.html
+++ b/plugins/InspectionGadgets/src/inspectionDescriptions/InnerClassMayBeStatic.html
@@ -1,8 +1,10 @@
<html>
<body>
-Reports any inner classes which may safely be made
-<b>static</b>. An inner class may be static if it doesn't reference
-its enclosing class instance. A static inner class uses slightly less memory.
+Reports any inner classes which may safely be made <b>static</b>.
+An inner class may be <b>static</b> if it doesn't reference its enclosing instance.
+<p>
+A <b>static</b> inner class does not keep an implicit reference to its enclosing instance.
+This prevents a common cause of memory leaks and uses less memory per instance of the class.
<!-- tooltip end -->
<p>
diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/NonThreadSafeLazyInitialization.html b/plugins/InspectionGadgets/src/inspectionDescriptions/NonThreadSafeLazyInitialization.html
index f203aa949764..a1d87f3e9d1b 100644
--- a/plugins/InspectionGadgets/src/inspectionDescriptions/NonThreadSafeLazyInitialization.html
+++ b/plugins/InspectionGadgets/src/inspectionDescriptions/NonThreadSafeLazyInitialization.html
@@ -1,16 +1,16 @@
<html>
<body>
-Reports static variables being lazily initialized
-in an non-thread-safe manner. Lazy initialization of static variables should be done
+Reports <b>static</b> variables being lazily initialized
+in an non-thread-safe manner. Lazy initialization of <b>static</b> variables should be done
in an appropriate synchronization construct, to prevent different threads from
performing conflicting initialization.
<p>
-If applicable, quick-fix is suggested
-which introduces static holder pattern described in
+If applicable, a quickfix is suggested
+which introduces the static holder pattern described in
<a href="http://en.wikipedia.org/wiki/Initialization_on_demand_holder_idiom">
http://en.wikipedia.org/wiki/Initialization_on_demand_holder_idiom
</a>
-where the JVM guarantees thread-safety of such initializations.
+where the JVM guarantees the thread-safety of such initializations.
<!-- tooltip end -->
<p>
diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/PropertyValueSetToItself.html b/plugins/InspectionGadgets/src/inspectionDescriptions/PropertyValueSetToItself.html
index c72e160a9b8c..60964e59716c 100644
--- a/plugins/InspectionGadgets/src/inspectionDescriptions/PropertyValueSetToItself.html
+++ b/plugins/InspectionGadgets/src/inspectionDescriptions/PropertyValueSetToItself.html
@@ -1,8 +1,8 @@
<html>
<body>
-Reports calls on a setter with the value of same objects getter.
+Reports calls on a setter with the value of the same object's getter.
For example: <code>bean.setPayerId(bean.getPayerId());</code>
-In regular circumstances this code is a no-op and probably not what was intented..
+In regular circumstances this code is a no-op and probably not what was intended.
<!-- tooltip end -->
<p>
<small>New in 14</small>
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/Argument.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/Argument.java
new file mode 100644
index 000000000000..766ea62ea51d
--- /dev/null
+++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/Argument.java
@@ -0,0 +1,12 @@
+public class Argument {
+
+ void m(A a) {}
+ void n() {
+ m(new A<caret>() {{ setI(1); setJ(2); }});
+ }
+
+ class A {
+ void setI(int i) {}
+ void setJ(int j) {}
+ }
+} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/Field.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/Field.after.java
new file mode 100644
index 000000000000..804a5e59d66b
--- /dev/null
+++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/Field.after.java
@@ -0,0 +1,12 @@
+import java.util.ArrayList;
+import java.util.List;
+
+public class Field {
+ static final List<Integer> list = new ArrayList<Integer>();
+
+ static {
+ for (int i = 0; i < 10; i++) {
+ list.add(i);
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/Field.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/Field.java
new file mode 100644
index 000000000000..4f75edf20f18
--- /dev/null
+++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/Field.java
@@ -0,0 +1,10 @@
+import java.util.ArrayList;
+import java.util.List;
+
+public class Field {
+ static final List<Integer> list = new <caret>ArrayList<Integer>() {{
+ for (int i = 0; i < 10; i++) {
+ add(i);
+ }
+ }};
+} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/LocalVariable.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/LocalVariable.after.java
new file mode 100644
index 000000000000..92f47c31f39c
--- /dev/null
+++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/LocalVariable.after.java
@@ -0,0 +1,13 @@
+import java.util.HashMap;
+
+public class LocalVariable {
+
+ void m() {
+ final HashMap<String, String> map = new HashMap();// comment
+ map.put("a", "b");
+ map.put("a", "b");
+ map.put("a", "b");
+ map.put("a", "b");
+
+ }
+} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/LocalVariable.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/LocalVariable.java
new file mode 100644
index 000000000000..12b6f415a4a9
--- /dev/null
+++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/initialization/double_brace_initialization/LocalVariable.java
@@ -0,0 +1,14 @@
+import java.util.HashMap;
+
+public class LocalVariable {
+
+ void m() {
+ final HashMap<String, String> map = new HashMap<caret>() {{
+ // comment
+ put("a", "b");
+ put("a", "b");
+ put("a", "b");
+ put("a", "b");
+ }};
+ }
+} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/inner_class_static/Simple.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/memory/inner_class_static/Simple.after.java
index 973bfc5b6e06..2b2ebd86b79a 100644
--- a/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/inner_class_static/Simple.after.java
+++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/memory/inner_class_static/Simple.after.java
@@ -1,4 +1,4 @@
-package performance.inner_class_static;
+package memory.inner_class_static;
class Simple {
static class Inner {}
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/inner_class_static/Simple.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/memory/inner_class_static/Simple.java
index c183bdb0986f..e08255ca8562 100644
--- a/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/inner_class_static/Simple.java
+++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/memory/inner_class_static/Simple.java
@@ -1,4 +1,4 @@
-package performance.inner_class_static;
+package memory.inner_class_static;
class Simple {
class Inner<caret> {}
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/style/cstyle_array_declaration/FieldWithWhitespace.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/style/cstyle_array_declaration/FieldWithWhitespace.after.java
new file mode 100644
index 000000000000..3a3984b1a64c
--- /dev/null
+++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/style/cstyle_array_declaration/FieldWithWhitespace.after.java
@@ -0,0 +1,4 @@
+class FieldWithWhitespace {
+
+ String[] s;
+} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/style/cstyle_array_declaration/FieldWithWhitespace.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/style/cstyle_array_declaration/FieldWithWhitespace.java
new file mode 100644
index 000000000000..1f02831d6632
--- /dev/null
+++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/style/cstyle_array_declaration/FieldWithWhitespace.java
@@ -0,0 +1,4 @@
+class FieldWithWhitespace {
+
+ String s<caret> [];
+} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/style/cstyle_array_declaration/SimpleMethod.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/style/cstyle_array_declaration/SimpleMethod.after.java
new file mode 100644
index 000000000000..0b918a955215
--- /dev/null
+++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/style/cstyle_array_declaration/SimpleMethod.after.java
@@ -0,0 +1,6 @@
+public class SimpleMethod {
+
+ public String[] ohGod(String[] a) {
+ return a;
+ }
+} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/style/cstyle_array_declaration/SimpleMethod.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/style/cstyle_array_declaration/SimpleMethod.java
new file mode 100644
index 000000000000..5d0ac265b2fc
--- /dev/null
+++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/style/cstyle_array_declaration/SimpleMethod.java
@@ -0,0 +1,6 @@
+public class SimpleMethod {
+
+ public String ohGod<caret>(String[] a)[] {
+ return a;
+ }
+} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/threading/make_field_volatile/Simple.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/threading/make_field_volatile/Simple.after.java
new file mode 100644
index 000000000000..f33e30331623
--- /dev/null
+++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/threading/make_field_volatile/Simple.after.java
@@ -0,0 +1,19 @@
+public class Simple
+{
+ private static volatile Object s_instance;
+
+ public static Object foo()
+ {
+ if(s_instance == null)
+ {
+ synchronized(Simple.class)
+ {
+ if(s_instance == null)
+ {
+ s_instance = new Object();
+ }
+ }
+ }
+ return s_instance;
+ }
+}
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/threading/make_field_volatile/Simple.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/threading/make_field_volatile/Simple.java
new file mode 100644
index 000000000000..b514dc20378a
--- /dev/null
+++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/threading/make_field_volatile/Simple.java
@@ -0,0 +1,19 @@
+public class Simple
+{
+ private static Object s_instance;
+
+ public static Object foo()
+ {
+ if<caret>(s_instance == null)
+ {
+ synchronized(Simple.class)
+ {
+ if(s_instance == null)
+ {
+ s_instance = new Object();
+ }
+ }
+ }
+ return s_instance;
+ }
+}
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/threading/non_thread_safe_lazy_initialization/InstanceVariableReferenced.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/threading/non_thread_safe_lazy_initialization/InstanceVariableReferenced.java
new file mode 100644
index 000000000000..f72c45f2f395
--- /dev/null
+++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/threading/non_thread_safe_lazy_initialization/InstanceVariableReferenced.java
@@ -0,0 +1,16 @@
+public class InstanceVariableReferenced {
+
+ private static Object example;
+ private String s = "yes";
+
+ public Object getInstance() {
+ if (example == null) {
+ example<caret> = getString(s);
+ }
+ return example
+ }
+
+ private static String getString(String s) {
+ return new String(s);
+ }
+} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/threading/non_thread_safe_lazy_initialization/LocalVariableReferenced.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/threading/non_thread_safe_lazy_initialization/LocalVariableReferenced.java
new file mode 100644
index 000000000000..929994a18ffe
--- /dev/null
+++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/threading/non_thread_safe_lazy_initialization/LocalVariableReferenced.java
@@ -0,0 +1,11 @@
+public class LocalVariableReferenced {
+
+ private static Object o;
+
+ public static Object getInstance(int i) {
+ if (o == null) {
+ o<caret> = "" + i;
+ }
+ return o;
+ }
+} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/threading/non_thread_safe_lazy_initialization/NestedAssignment.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/threading/non_thread_safe_lazy_initialization/NestedAssignment.java
new file mode 100644
index 000000000000..89f229fbd3f0
--- /dev/null
+++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/threading/non_thread_safe_lazy_initialization/NestedAssignment.java
@@ -0,0 +1,12 @@
+public class NestedAssignment {
+
+ private static Object o;
+
+ public static Object getInstance() {
+ Object local = null;
+ if (o == null) {
+ local = o<caret> = new Object();
+ }
+ return o;
+ }
+} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/threading/non_thread_safe_lazy_initialization/Normal.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/threading/non_thread_safe_lazy_initialization/Normal.after.java
new file mode 100644
index 000000000000..c4eefd2315d1
--- /dev/null
+++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/threading/non_thread_safe_lazy_initialization/Normal.after.java
@@ -0,0 +1,10 @@
+public class Normal {
+
+ private static class ExampleHolder {
+ private static final Object example = new Object();
+ }
+
+ public static Object getInstance() {
+ return ExampleHolder.example
+ }
+} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/threading/non_thread_safe_lazy_initialization/Normal.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/threading/non_thread_safe_lazy_initialization/Normal.java
new file mode 100644
index 000000000000..44587c1653bc
--- /dev/null
+++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/threading/non_thread_safe_lazy_initialization/Normal.java
@@ -0,0 +1,10 @@
+public class Normal {
+ private static Object example;
+
+ public static Object getInstance() {
+ if (example == null) {
+ example<caret> = new Object();
+ }
+ return example
+ }
+} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/threading/non_thread_safe_lazy_initialization/StaticVariableReferenced.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/threading/non_thread_safe_lazy_initialization/StaticVariableReferenced.after.java
new file mode 100644
index 000000000000..0120971b7081
--- /dev/null
+++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/threading/non_thread_safe_lazy_initialization/StaticVariableReferenced.after.java
@@ -0,0 +1,16 @@
+public class StaticVariableReferenced {
+
+ private static String s = "yes";
+
+ private static class ExampleHolder {
+ private static final Object example = getString(s);
+ }
+
+ public static Object getInstance() {
+ return ExampleHolder.example
+ }
+
+ private static String getString(String s) {
+ return new String(s);
+ }
+} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/threading/non_thread_safe_lazy_initialization/StaticVariableReferenced.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/threading/non_thread_safe_lazy_initialization/StaticVariableReferenced.java
new file mode 100644
index 000000000000..a13113785c0d
--- /dev/null
+++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/threading/non_thread_safe_lazy_initialization/StaticVariableReferenced.java
@@ -0,0 +1,16 @@
+public class StaticVariableReferenced {
+
+ private static Object example;
+ private static String s = "yes";
+
+ public static Object getInstance() {
+ if (example == null) {
+ example<caret> = getString(s);
+ }
+ return example
+ }
+
+ private static String getString(String s) {
+ return new String(s);
+ }
+} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/ResultSetIndexZeroInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/ResultSetIndexZeroInspection.java
deleted file mode 100644
index cbb5e0eaf8a8..000000000000
--- a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/ResultSetIndexZeroInspection.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.siyeh.igtest.bugs;
-
-import java.sql.ResultSet;
-import java.sql.SQLException;
-
-public class ResultSetIndexZeroInspection {
- private static final int COLUMN_INDEX = 0;
-
- public void foo(ResultSet resultSet) throws SQLException {
- resultSet.getInt(0);
- resultSet.getInt(COLUMN_INDEX);
- resultSet.getInt(3);
- }
-}
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/result_set_index_zero/ResultSetIndexZero.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/result_set_index_zero/ResultSetIndexZero.java
new file mode 100644
index 000000000000..de087faef79e
--- /dev/null
+++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/result_set_index_zero/ResultSetIndexZero.java
@@ -0,0 +1,21 @@
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+public class ResultSetIndexZero {
+ private static final int COLUMN_INDEX = 0;
+
+ public void foo(ResultSet resultSet) throws SQLException {
+ resultSet.getInt(<warning descr="Use of index '0' in JDBC ResultSet">0</warning>);
+ resultSet.getInt(<warning descr="Use of index '0' in JDBC ResultSet">COLUMN_INDEX</warning>);
+ resultSet.getInt(3);
+ }
+
+ void foo(PreparedStatement ps) throws SQLException {
+ ps.setQueryTimeout(0);
+ ps.setFetchDirection(0);
+ ps.setFetchSize(0);
+ ps.setMaxFieldSize(0);
+ ps.setMaxRows(0);
+ }
+}
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/string_equality/StringEquality.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/string_equality/StringEquality.java
index d32c969b9261..17c4b5127c3b 100644
--- a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/string_equality/StringEquality.java
+++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/string_equality/StringEquality.java
@@ -4,7 +4,11 @@ public class StringEquality {
void foo(String s, String t) {
final boolean a = s == null;
- final boolean b = t == s;
- final boolean c = t ==
+ final boolean b = t <warning descr="String values are compared using '==', not 'equals()'">==</warning> s;
+ final boolean c = t ==<EOLError descr="Expression expected"></EOLError><EOLError descr="';' expected"></EOLError>
+ }
+
+ void notEquals(String s, String t) {
+ boolean a = s <warning descr="String values are compared using '!=', not 'equals()'">!=</warning> t;
}
}
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/string_equality/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/string_equality/expected.xml
deleted file mode 100644
index 0eb665c7cff4..000000000000
--- a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/string_equality/expected.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<problems>
- <problem>
- <file>StringEquality.java</file>
- <line>7</line>
- <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">String comparison using '==', instead of 'equals()'</problem_class>
- <description>String values are compared using &lt;code&gt;==&lt;/code&gt;, not '.equals()' #loc</description>
- </problem>
-</problems> \ No newline at end of file
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/NestedMethodCallInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/NestedMethodCallInspection.java
deleted file mode 100644
index e700bc5c683f..000000000000
--- a/plugins/InspectionGadgets/test/com/siyeh/igtest/confusing/NestedMethodCallInspection.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.siyeh.igtest.confusing;
-
-import java.util.ArrayList;
-
-public class NestedMethodCallInspection extends ArrayList{
- private int baz = bar(foo());
-
- public NestedMethodCallInspection(int initialCapacity) {
- super(Math.abs(initialCapacity));
- }
-
- public NestedMethodCallInspection() {
- this(Math.abs(3));
- }
-
- public int foo()
- {
- return 3;
- }
- public int bar(int val)
- {
- return 3+val;
- }
-
- public int baz()
- {
- bar(Math.abs(3));
- return bar(foo());
- }
-
- public int barangus()
- {
- return bar(foo()+3);
- }
-}
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/double_brace_initialization/DoubleBraceInitialization.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/double_brace_initialization/DoubleBraceInitialization.java
new file mode 100644
index 000000000000..f216f84e2f67
--- /dev/null
+++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/double_brace_initialization/DoubleBraceInitialization.java
@@ -0,0 +1,32 @@
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+public class DoubleBraceInitialization {
+
+ void foo() {
+ final HashMap map = new <warning descr="Double brace initialization">HashMap</warning>() {{
+ // comment
+ put("a", "b");
+ put("a", "b");
+ put("a", "b");
+ put("a", "b");
+ }};
+ }
+
+ static final List<Integer> list = new <warning descr="Double brace initialization">ArrayList<Integer></warning>() {{
+ for (int i = 0; i < 10; i++) {
+ add(i);
+ }
+ }};
+
+ void m(A a) {}
+ void n() {
+ m(new <warning descr="Double brace initialization">A</warning>() {{ setI(1); setJ(2); }});
+ }
+
+ class A {
+ void setI(int i) {}
+ void setJ(int j) {}
+ }
+} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/non_thread_safe_lazy_initialization/NonThreadSafeLazyInitialization.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/non_thread_safe_lazy_initialization/NonThreadSafeLazyInitialization.java
new file mode 100644
index 000000000000..9b5987966ca6
--- /dev/null
+++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/initialization/non_thread_safe_lazy_initialization/NonThreadSafeLazyInitialization.java
@@ -0,0 +1,64 @@
+package com.siyeh.igtest.threading;
+
+public class NonThreadSafeLazyInitialization {
+ private static Object foo;
+ private Object instance;
+
+ public Object getInstance() {
+ if (instance == null) {
+ instance = new Object();
+ }
+ return instance;
+ }
+
+ static
+ {
+ if (foo == null) {
+ foo = new Object();
+ }
+
+ }
+
+ {
+ if (foo == null) {
+ <warning descr="Lazy initialization of 'static' field 'foo' is not thread-safe">foo</warning> = new Object();
+ }
+
+ }
+
+ public void instMethod() {
+ if (foo == null) {
+ <warning descr="Lazy initialization of 'static' field 'foo' is not thread-safe">foo</warning> = new Object();
+ }
+ }
+
+ public static void staticMethod() {
+ if (foo == null) {
+ <warning descr="Lazy initialization of 'static' field 'foo' is not thread-safe">foo</warning> = new Object();
+ }
+ }
+
+ public void lockedInstMethod() {
+ synchronized (NonThreadSafeLazyInitialization.class) {
+ if (foo == null) {
+ foo = new Object();
+ }
+ }
+ }
+
+ private static String example = null;
+
+ public Object getInstance2() {
+ if (foo == null) {
+ while (true) {
+ foo = "";
+ }
+ }
+ return foo;
+ }
+
+ public Object getInstance3() {
+ if (foo == null) <warning descr="Lazy initialization of 'static' field 'foo' is not thread-safe">foo</warning> = "";
+ return foo;
+ }
+}
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/memory/anonymous_inner_class_may_be_static/AnonymousInnerClassMayBeStatic.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/memory/anonymous_inner_class_may_be_static/AnonymousInnerClassMayBeStatic.java
new file mode 100644
index 000000000000..4641642c09c5
--- /dev/null
+++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/memory/anonymous_inner_class_may_be_static/AnonymousInnerClassMayBeStatic.java
@@ -0,0 +1,93 @@
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+public class AnonymousInnerClassMayBeStatic {
+
+ public void foo()
+ {
+ final Runnable runnable = new <warning descr="Anonymous class 'Runnable' may be a named 'static' inner class">Runnable</warning>(){
+ public void run() {
+ }
+ };
+ runnable.run();
+ new A() {};
+ new <warning descr="Anonymous class 'B' may be a named 'static' inner class">B</warning>() {};
+ new <error descr="Cannot resolve symbol 'C'">C</error>() {};
+ String localVar = "";
+ new <warning descr="Anonymous class 'B' may be a named 'static' inner class">B</warning> () {
+ void f() {
+ System.out.println(localVar);
+ }
+ };
+ }
+
+ class A {}
+ static class B {}
+
+ void m() {
+ class C {
+ }
+ new B() {
+ void bla() {
+ C b; // reference to local class
+ }
+ };
+ new <warning descr="Anonymous class 'B' may be a named 'static' inner class">B</warning>() {
+ void bla() {
+ AnonymousInnerClassMayBeStatic.n();
+ }
+ };
+ }
+
+ static void n() {}
+
+ class D {
+ {new E().m();}
+ class E {
+ private void m() {}
+ }
+ }
+
+ class CC {}
+ static class BB<T> {
+ void m() {
+ new <warning descr="Anonymous class 'BB<CC>' may be a named 'static' inner class">BB<CC></warning>() {
+ class Z {}
+ };
+ }
+ }
+
+ String t = "";
+
+ void m(int p) {
+ String s = null;
+ new <warning descr="Anonymous class 'Object' may be a named 'static' inner class">Object</warning>() {
+ private int a = 1;
+ void f() {
+ System.out.println(a);
+ System.out.println(p);
+ System.out.println(s);
+ this.g();
+ }
+
+ private void g() {}
+ };
+ }
+
+ void sort(List<String> list) {
+ Collections.sort(list, new <warning descr="Anonymous class 'Comparator<String>' may be a named 'static' inner class">Comparator<String></warning>() {
+ @Override
+ public int compare(String o1, String o2) {
+ return o1.toString().compareToIgnoreCase(o2.toString());
+ }
+ });
+ }
+}
+class One {
+ class Two {
+ void foo() {
+ new Object() {};
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/memory/inner_class_may_be_static/InnerClassMayBeStatic.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/memory/inner_class_may_be_static/InnerClassMayBeStatic.java
new file mode 100644
index 000000000000..dc0b97443b4e
--- /dev/null
+++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/memory/inner_class_may_be_static/InnerClassMayBeStatic.java
@@ -0,0 +1,140 @@
+package com.siyeh.igtest.memory.inner_class_may_be_static;
+
+import javax.swing.*;
+
+public class InnerClassMayBeStatic {
+ class <warning descr="Inner class 'Nested' may be 'static'">Nested</warning> {
+ public void foo() {
+ bar("InnerClassMayBeStaticInspection.this");
+ }
+
+ private void bar(String string) {
+ }
+ }
+}
+
+class IDEADEV_5513 {
+
+ private static class Inner {
+
+ private boolean b = false;
+
+ private class InnerInner {
+
+ public void foo() {
+ b = true;
+ }
+ }
+ }
+}
+
+class C extends JComponent {
+ private class I {
+ public void foo() {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ repaint();
+ }
+ });
+ }
+ }
+}
+class D {
+
+ void foo() {
+ new Object() {
+ class Y {}
+ };
+ }
+}
+class StaticInnerClass {
+
+ private int foo;
+ int bar;
+
+ public class Baz extends StaticInnerClass {
+ Baz() {
+ foo = -1;
+ }
+ }
+ class <warning descr="Inner class 'C' may be 'static'">C</warning> extends StaticInnerClass {{
+ bar = 1;
+ }}
+}
+class SomeBeanUnitTest {
+
+ private class <warning descr="Inner class 'BeanCreator' may be 'static'">BeanCreator</warning> {
+
+ public BeanCreator withQuery() {
+ return null;
+ }
+ }
+}
+class Outer {
+ class <warning descr="Inner class 'A' may be 'static'">A</warning> { // may be static
+ B b;
+ }
+ class B extends A {} // may not be static
+
+ class <warning descr="Inner class 'C' may be 'static'">C</warning> { // may be static
+ D b;
+ class D extends C {}
+ }
+
+ static class E {
+ G.F b;
+ class <warning descr="Inner class 'G' may be 'static'">G</warning> { // may be static
+ class F extends E {}
+ }
+ }
+
+ class <warning descr="Inner class 'H' may be 'static'">H</warning> { // may be static
+ J.I b;
+ class J {
+ class I extends H {}
+ }
+ }
+}
+class Complex {
+ class C {
+ void m() {
+ Complex.super.toString();
+ }
+ }
+ int i;
+ static void n() {
+ }
+
+ private class <warning descr="Inner class 'A' may be 'static'">A</warning> {
+ private A() {
+ }
+ }
+
+ class <warning descr="Inner class 'B' may be 'static'">B</warning> {
+ }
+
+ class <warning descr="Inner class 'F' may be 'static'">F</warning> extends Complex {
+ class G {
+ }
+
+ {
+ A a = (A) null;
+ G g = (G) null;
+ new A() {};
+ new B();
+
+ i = 10;
+ new E().m();
+ Complex.n();
+ }
+
+ void m(A a) {
+ a.toString();
+ }
+
+ class E {
+ private void m() {
+ }
+ }
+ }
+}
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/inner_class_may_be_static/InnerClassMayBeStaticInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/inner_class_may_be_static/InnerClassMayBeStaticInspection.java
deleted file mode 100644
index 0db367ce4757..000000000000
--- a/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/inner_class_may_be_static/InnerClassMayBeStaticInspection.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package com.siyeh.igtest.performance.inner_class_may_be_static;
-
-import javax.swing.*;
-
-public class InnerClassMayBeStaticInspection {
- class Nested {
- public void foo() {
- bar("InnerClassMayBeStaticInspection.this");
- }
-
- private void bar(String string) {
- }
- }
-}
-
-class IDEADEV_5513 {
-
- private static class Inner {
-
- private boolean b = false;
-
- private class InnerInner {
-
- public void foo() {
- b = true;
- }
- }
- }
-}
-
-class C extends JComponent {
- private class I {
- public void foo() {
- SwingUtilities.invokeLater(new Runnable() {
- public void run() {
- repaint();
- }
- });
- }
- }
-}
-class D {
-
- void foo() {
- new Object() {
- class Y {}
- };
- }
-}
-class StaticInnerClass {
-
- private int foo;
- int bar;
-
- public class Baz extends StaticInnerClass {
- Baz() {
- foo = -1;
- }
- }
- class C extends StaticInnerClass {{
- bar = 1;
- }}
-}
-class SomeBeanUnitTest {
-
- private class BeanCreator {
-
- public BeanCreator withQuery() {
- return null;
- }
- }
-}
-class Outer {
- class A { // may not be static
- B b;
- }
- class B extends A {} // may not be static
-
- class C { // may be static
- D b;
- class D extends C {}
- }
-
- static class E {
- G.F b;
- class G { // may be static
- class F extends E {}
- }
- }
-
- class H { // may be static
- J.I b;
- class J {
- class I extends H {}
- }
- }
-}
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/inner_class_may_be_static/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/inner_class_may_be_static/expected.xml
deleted file mode 100644
index 0eb4ed32494c..000000000000
--- a/plugins/InspectionGadgets/test/com/siyeh/igtest/performance/inner_class_may_be_static/expected.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<problems>
- <problem>
- <file>InnerClassMayBeStaticInspection.java</file>
- <line>6</line>
- <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Inner class may be 'static'</problem_class>
- <description>Inner class &lt;code&gt;Nested&lt;/code&gt; may be 'static' #loc</description>
- </problem>
-
- <problem>
- <file>InnerClassMayBeStaticInspection.java</file>
- <line>60</line>
- <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Inner class may be 'static'</problem_class>
- <description>Inner class &lt;code&gt;C&lt;/code&gt; may be 'static' #loc</description>
- </problem>
-
- <problem>
- <file>InnerClassMayBeStaticInspection.java</file>
- <line>66</line>
- <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Inner class may be 'static'</problem_class>
- <description>Inner class &lt;code&gt;BeanCreator&lt;/code&gt; may be 'static' #loc</description>
- </problem>
-
- <problem>
- <file>InnerClassMayBeStaticInspection.java</file>
- <line>79</line>
- <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Inner class may be 'static'</problem_class>
- <description>Inner class &lt;code&gt;C&lt;/code&gt; may be 'static' #loc</description>
- </problem>
-
- <problem>
- <file>InnerClassMayBeStaticInspection.java</file>
- <line>86</line>
- <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Inner class may be 'static'</problem_class>
- <description>Inner class &lt;code&gt;G&lt;/code&gt; may be 'static' #loc</description>
- </problem>
-
- <problem>
- <file>InnerClassMayBeStaticInspection.java</file>
- <line>91</line>
- <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Inner class may be 'static'</problem_class>
- <description>Inner class &lt;code&gt;H&lt;/code&gt; may be 'static' #loc</description>
- </problem>
-</problems> \ No newline at end of file
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/style/CStyleArrayDeclarationInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/CStyleArrayDeclarationInspection.java
deleted file mode 100644
index 00d3e0ec97d4..000000000000
--- a/plugins/InspectionGadgets/test/com/siyeh/igtest/style/CStyleArrayDeclarationInspection.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.siyeh.igtest.style;
-
-public class CStyleArrayDeclarationInspection
-{
- private int[] m_foo;
- private int m_bar[];
-
- public CStyleArrayDeclarationInspection(int[] bar, int[] foo)
- {
- m_bar = bar;
- m_foo = foo;
- for(int i = 0; i < bar.length; i++)
- {
- m_foo[i] = m_bar[i];
- }
-
- }
-
- public void foo()
- {
- final int foo[] = new int[3];
- final int[] bar = new int[3];
-
- for(int i = 0; i < bar.length; i++)
- {
- foo[i] = bar[i];
- }
- }
-
- public void bar(int foo[], int[] bar)
- {
-
- }
-}
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/style/cstyle_array_declaration/CStyleArrayDeclaration.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/cstyle_array_declaration/CStyleArrayDeclaration.java
new file mode 100644
index 000000000000..8a01835a2106
--- /dev/null
+++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/cstyle_array_declaration/CStyleArrayDeclaration.java
@@ -0,0 +1,38 @@
+package com.siyeh.igtest.style;
+
+public class CStyleArrayDeclaration
+{
+ private int[] m_foo;
+ private int <warning descr="C-style array declaration of field 'm_bar'">m_bar</warning>[];
+
+ public CStyleArrayDeclaration(int[] bar, int[] foo)
+ {
+ m_bar = bar;
+ m_foo = foo;
+ for(int i = 0; i < bar.length; i++)
+ {
+ m_foo[i] = m_bar[i];
+ }
+
+ }
+
+ public void foo()
+ {
+ final int <warning descr="C-style array declaration of local variable 'foo'">foo</warning>[] = new int[3];
+ final int[] bar = new int[3];
+
+ for(int i = 0; i < bar.length; i++)
+ {
+ foo[i] = bar[i];
+ }
+ }
+
+ public void bar(int <warning descr="C-style array declaration of parameter 'foo'">foo</warning>[], int[] bar)
+ {
+
+ }
+
+ String <warning descr="C-style array declaration of the return type of method 'ohGod()'">ohGod</warning>(String[] a)[] {
+ return a;
+ }
+}
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/style/nested_method_call/NestedMethodCall.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/nested_method_call/NestedMethodCall.java
new file mode 100644
index 000000000000..2548443e805b
--- /dev/null
+++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/nested_method_call/NestedMethodCall.java
@@ -0,0 +1,43 @@
+
+import java.util.ArrayList;
+
+public class NestedMethodCall extends ArrayList{
+ private int baz = bar(foo());
+
+ public NestedMethodCall(int initialCapacity) {
+ super(Math.abs(initialCapacity));
+ }
+
+ public NestedMethodCall() {
+ this(Math.abs(3));
+ }
+
+ public int foo()
+ {
+ return 3;
+ }
+ public int bar(int val)
+ {
+ return 3+val;
+ }
+
+ public int baz()
+ {
+ bar(Math.abs(3));
+ return bar(<warning descr="Nested method call 'foo()'">foo</warning>());
+ }
+
+ public int barangus()
+ {
+ return bar(<warning descr="Nested method call 'foo()'">foo</warning>()+3);
+ }
+
+ private int value = 1;
+ public int getValue() {
+ return value;
+ }
+
+ public int apex() {
+ return bar(getValue());
+ }
+}
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/NonThreadSafeLazyInitializationInspection.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/NonThreadSafeLazyInitializationInspection.java
deleted file mode 100644
index 20d62f94cb4e..000000000000
--- a/plugins/InspectionGadgets/test/com/siyeh/igtest/threading/NonThreadSafeLazyInitializationInspection.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.siyeh.igtest.threading;
-
-public class NonThreadSafeLazyInitializationInspection {
- private static Object foo;
-
- static
- {
- if (foo == null) {
- foo = new Object();
- }
-
- }
-
- {
- if (foo == null) {
- foo = new Object();
- }
-
- }
-
- public void instMethod() {
- if (foo == null) {
- foo = new Object();
- }
- }
-
- public void lockedInstMethod() {
- synchronized (NonThreadSafeLazyInitializationInspection.class) {
- if (foo == null) {
- foo = new Object();
- }
- }
- }
-}
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/ambiguous/AmbiguousMethodCall.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/ambiguous/AmbiguousMethodCall.java
index 1d1eb0ad0369..20c181077969 100644
--- a/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/ambiguous/AmbiguousMethodCall.java
+++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/ambiguous/AmbiguousMethodCall.java
@@ -8,7 +8,7 @@ public class AmbiguousMethodCall {
class Inner extends Y {
{
- m(); // ambiguous
+ <warning descr="Call to method 'm()' from superclass 'Y' looks like call to method from class 'X'">m</warning>(); // ambiguous
}
}
}
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/ambiguous/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/ambiguous/expected.xml
deleted file mode 100644
index a0ee7b7d2789..000000000000
--- a/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/ambiguous/expected.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<problems>
- <problem>
- <file>AmbiguousMethodCall.java</file>
- <line>11</line>
- <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Inherited method called which hides method in outer class</problem_class>
- <description>Method &lt;code&gt;m()&lt;/code&gt; from super class 'Y' called, when method from class 'X' might have been expected #loc</description>
- </problem>
-
-</problems> \ No newline at end of file
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/ambiguous_field_access/AmbiguousFieldAccess.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/ambiguous_field_access/AmbiguousFieldAccess.java
index 3292bfd60a0b..3090a6415135 100644
--- a/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/ambiguous_field_access/AmbiguousFieldAccess.java
+++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/ambiguous_field_access/AmbiguousFieldAccess.java
@@ -11,11 +11,26 @@ class Bar {
void foo(java.util.List<String> name) {
for(String name1: name) {
doSome(new Foo() {{
- set(name);
+ set(<warning descr="Access of field 'name' from superclass 'Foo' looks like access of parameter">name</warning>);
}});
}
}
+ void foo() {
+ String name = "name";
+ new Foo() {{
+ System.out.println(<warning descr="Access of field 'name' from superclass 'Foo' looks like access of local variable">name</warning>);
+ }};
+ }
+
+ void bar() {
+ new Foo() {
+ void foo() {
+ System.out.println(<warning descr="Access of field 'name' from superclass 'Foo' looks access of field from surrounding class">name</warning>);
+ }
+ };
+ }
+
private void doSome(Foo foo) {
}
} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/ambiguous_field_access/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/ambiguous_field_access/expected.xml
deleted file mode 100644
index 9929fd781f8b..000000000000
--- a/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/ambiguous_field_access/expected.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<problems>
- <problem>
- <file>AmbiguousFieldAccess.java</file>
- <line>14</line>
- <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Inherited field accessed while local variable, parameter or field access from surrounding class might be expected</problem_class>
- <description>Field &lt;code&gt;name&lt;/code&gt; from super class 'Foo' accessed, while parameter access might be expected #loc</description>
- </problem>
-</problems> \ No newline at end of file
diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/IGQuickFixesTestCase.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/IGQuickFixesTestCase.java
index 2ce63ec4814e..47fd152debec 100644
--- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/IGQuickFixesTestCase.java
+++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/IGQuickFixesTestCase.java
@@ -16,15 +16,21 @@
package com.siyeh.ig;
import com.intellij.codeInsight.intention.IntentionAction;
+import com.intellij.codeInspection.ex.QuickFixWrapper;
import com.intellij.ide.highlighter.JavaFileType;
import com.intellij.openapi.application.PluginPathManager;
+import com.intellij.openapi.util.Condition;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.testFramework.builders.JavaModuleFixtureBuilder;
import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase;
import com.intellij.util.ArrayUtil;
+import com.intellij.util.containers.ContainerUtil;
import org.intellij.lang.annotations.Language;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
+import org.junit.Assert;
+
+import java.util.List;
/**
* @author anna
@@ -73,6 +79,17 @@ public abstract class IGQuickFixesTestCase extends JavaCodeInsightFixtureTestCas
return PluginPathManager.getPluginHomePath("InspectionGadgets") + "/test/com/siyeh/igfixes/";
}
+ protected void assertQuickfixNotAvailable() {
+ assertQuickfixNotAvailable(myDefaultHint);
+ }
+
+ protected void assertQuickfixNotAvailable(final String quickfixName) {
+ final String testName = getTestName(false);
+ myFixture.configureByFile(getRelativePath() + "/" + testName + ".java");
+ assertEmpty("Quickfix \'" + quickfixName + "\' is available but should not",
+ myFixture.filterAvailableIntentions(quickfixName));
+ }
+
protected void doTest() {
assertNotNull(myDefaultHint);
final String testName = getTestName(false);
@@ -86,12 +103,36 @@ public abstract class IGQuickFixesTestCase extends JavaCodeInsightFixtureTestCas
protected void doTest(final String testName, final String hint) {
myFixture.configureByFile(getRelativePath() + "/" + testName + ".java");
- final IntentionAction action = myFixture.findSingleIntention(hint);
+ final IntentionAction action = findIntention(hint);
assertNotNull(action);
myFixture.launchAction(action);
myFixture.checkResultByFile(getRelativePath() + "/" + testName + ".after.java");
}
+ public IntentionAction findIntention(@NotNull final String hint) {
+ final List<IntentionAction> availableIntentions =
+ ContainerUtil.findAll(myFixture.getAvailableIntentions(), new Condition<IntentionAction>() {
+ @Override
+ public boolean value(final IntentionAction intentionAction) {
+ return intentionAction instanceof QuickFixWrapper;
+ }
+ });
+ final List<IntentionAction> list = ContainerUtil.findAll(availableIntentions, new Condition<IntentionAction>() {
+ @Override
+ public boolean value(IntentionAction intentionAction) {
+ return intentionAction.getText().equals(hint);
+ }
+ });
+ if (list.isEmpty()) {
+ Assert.fail("\"" + hint + "\" not in " + list);
+ }
+ else if (list.size() > 1) {
+ Assert.fail("Too many quickfixes found for \"" + hint + "\": " + list + "]");
+ }
+ return list.get(0);
+ }
+
+
protected void doExpressionTest(
String hint,
@Language(value = "JAVA", prefix = "class $X$ {{System.out.print(", suffix = ");}}") @NotNull @NonNls String before,
@@ -109,7 +150,7 @@ public abstract class IGQuickFixesTestCase extends JavaCodeInsightFixtureTestCas
protected void doTest(String hint, @Language("JAVA") @NotNull @NonNls String before, @Language("JAVA") @NotNull @NonNls String after) {
before = before.replace("/**/", "<caret>");
myFixture.configureByText(JavaFileType.INSTANCE, before);
- final IntentionAction intention = myFixture.findSingleIntention(hint);
+ final IntentionAction intention = findIntention(hint);
assertNotNull(intention);
myFixture.launchAction(intention);
myFixture.checkResult(after);
diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/ResultSetIndexZeroInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/ResultSetIndexZeroInspectionTest.java
new file mode 100644
index 000000000000..07a1c7d7150e
--- /dev/null
+++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/ResultSetIndexZeroInspectionTest.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.bugs;
+
+import com.intellij.codeInspection.InspectionProfileEntry;
+import com.siyeh.ig.LightInspectionTestCase;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author Bas Leijdekkers
+ */
+public class ResultSetIndexZeroInspectionTest extends LightInspectionTestCase {
+
+ public void testResultSetIndexZero() { doTest(); }
+
+ @Nullable
+ @Override
+ protected InspectionProfileEntry getInspection() {
+ return new ResultSetIndexZeroInspection();
+ }
+}
diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/StringEqualityInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/StringEqualityInspectionTest.java
index 13aa1fa972ae..d17c0b31e19b 100644
--- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/StringEqualityInspectionTest.java
+++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/StringEqualityInspectionTest.java
@@ -1,10 +1,18 @@
package com.siyeh.ig.bugs;
-import com.siyeh.ig.IGInspectionTestCase;
+import com.intellij.codeInspection.InspectionProfileEntry;
+import com.siyeh.ig.LightInspectionTestCase;
+import org.jetbrains.annotations.Nullable;
-public class StringEqualityInspectionTest extends IGInspectionTestCase {
+public class StringEqualityInspectionTest extends LightInspectionTestCase {
- public void test() throws Exception {
- doTest("com/siyeh/igtest/bugs/string_equality", new StringEqualityInspection());
+ public void testStringEquality() {
+ doTest();
+ }
+
+ @Nullable
+ @Override
+ protected InspectionProfileEntry getInspection() {
+ return new StringEqualityInspection();
}
} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/classlayout/ClassWithOnlyPrivateConstructorsInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/classlayout/ClassWithOnlyPrivateConstructorsInspectionTest.java
index a177242537d2..397a2fe1d37e 100644
--- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/classlayout/ClassWithOnlyPrivateConstructorsInspectionTest.java
+++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/classlayout/ClassWithOnlyPrivateConstructorsInspectionTest.java
@@ -41,6 +41,14 @@ public class ClassWithOnlyPrivateConstructorsInspectionTest extends LightInspect
doTest("class X {}");
}
+ public void testEnum() {
+ doTest("enum Currencies {\n" +
+ " EURO, DOLLAR;\n" +
+ " private Currencies() {\n" +
+ " }\n" +
+ "}");
+ }
+
@Nullable
@Override
protected InspectionProfileEntry getInspection() {
diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/initialization/DoubleBraceInitializationFixTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/initialization/DoubleBraceInitializationFixTest.java
new file mode 100644
index 000000000000..afce138a7a82
--- /dev/null
+++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/initialization/DoubleBraceInitializationFixTest.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.fixes.initialization;
+
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.IGQuickFixesTestCase;
+import com.siyeh.ig.initialization.DoubleBraceInitializationInspection;
+
+/**
+ * @author Bas Leijdekkers
+ */
+public class DoubleBraceInitializationFixTest extends IGQuickFixesTestCase {
+
+ public void testLocalVariable() { doTest(); }
+ public void testField() { doTest(); }
+ public void testArgument() { assertQuickfixNotAvailable(); }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ myFixture.enableInspections(new DoubleBraceInitializationInspection());
+ myRelativePath = "initialization/double_brace_initialization";
+ myDefaultHint = InspectionGadgetsBundle.message("double.brace.initialization.quickfix");
+ }
+}
diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/performance/InnerClassMayBeStaticFixTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/memory/InnerClassMayBeStaticFixTest.java
index 92a27c5ac236..42c36bf212fb 100644
--- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/performance/InnerClassMayBeStaticFixTest.java
+++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/memory/InnerClassMayBeStaticFixTest.java
@@ -13,11 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.siyeh.ig.fixes.performance;
+package com.siyeh.ig.fixes.memory;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.IGQuickFixesTestCase;
-import com.siyeh.ig.performance.InnerClassMayBeStaticInspection;
+import com.siyeh.ig.memory.InnerClassMayBeStaticInspection;
/**
* @author Bas Leijdekkers
@@ -28,7 +28,7 @@ public class InnerClassMayBeStaticFixTest extends IGQuickFixesTestCase {
protected void setUp() throws Exception {
super.setUp();
myFixture.enableInspections(new InnerClassMayBeStaticInspection());
- myRelativePath = "performance/inner_class_static";
+ myRelativePath = "memory/inner_class_static";
myDefaultHint = InspectionGadgetsBundle.message("make.static.quickfix");
}
diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/style/CStyleArrayDeclarationFixTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/style/CStyleArrayDeclarationFixTest.java
new file mode 100644
index 000000000000..85a07f8e08c3
--- /dev/null
+++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/style/CStyleArrayDeclarationFixTest.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.fixes.style;
+
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.IGQuickFixesTestCase;
+import com.siyeh.ig.style.CStyleArrayDeclarationInspection;
+
+/**
+ * @author Bas Leijdekkers
+ */
+public class CStyleArrayDeclarationFixTest extends IGQuickFixesTestCase {
+
+ public void testSimpleMethod() { doTest(); }
+ public void testFieldWithWhitespace() { doTest(); }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ myFixture.enableInspections(new CStyleArrayDeclarationInspection());
+ myRelativePath = "style/cstyle_array_declaration";
+ myDefaultHint = InspectionGadgetsBundle.message("c.style.array.declaration.replace.quickfix");
+ }
+}
diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/threading/IntroduceHolderFixTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/threading/IntroduceHolderFixTest.java
new file mode 100644
index 000000000000..28557e5f35a1
--- /dev/null
+++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/threading/IntroduceHolderFixTest.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.fixes.threading;
+
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.IGQuickFixesTestCase;
+import com.siyeh.ig.initialization.NonThreadSafeLazyInitializationInspection;
+
+/**
+ * @author Bas Leijdekkers
+ */
+public class IntroduceHolderFixTest extends IGQuickFixesTestCase {
+
+ public void testNestedAssignment() { assertQuickfixNotAvailable(); }
+ public void testLocalVariableReferenced() { assertQuickfixNotAvailable(); }
+ public void testInstanceVariableReferenced() { assertQuickfixNotAvailable(); }
+ public void testStaticVariableReferenced() { doTest(); }
+ public void testNormal() { doTest(); }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ myFixture.enableInspections(new NonThreadSafeLazyInitializationInspection()
+ );
+ myDefaultHint = InspectionGadgetsBundle.message("introduce.holder.class.quickfix");
+ myRelativePath = "threading/non_thread_safe_lazy_initialization";
+ }
+}
diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/threading/MakeFieldVolatileFixTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/threading/MakeFieldVolatileFixTest.java
new file mode 100644
index 000000000000..4c9a623be4d5
--- /dev/null
+++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/threading/MakeFieldVolatileFixTest.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.fixes.threading;
+
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.IGQuickFixesTestCase;
+import com.siyeh.ig.threading.DoubleCheckedLockingInspection;
+
+/**
+ * @author Bas Leijdekkers
+ */
+public class MakeFieldVolatileFixTest extends IGQuickFixesTestCase {
+
+ public void testSimple() { doTest(InspectionGadgetsBundle.message("double.checked.locking.quickfix", "s_instance")); }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ final DoubleCheckedLockingInspection inspection = new DoubleCheckedLockingInspection();
+ inspection.ignoreOnVolatileVariables = true;
+ myFixture.enableInspections(inspection);
+ myRelativePath = "threading/make_field_volatile";
+ }
+}
diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/initialization/DoubleBraceInitializationInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/initialization/DoubleBraceInitializationInspectionTest.java
new file mode 100644
index 000000000000..532018d5c26e
--- /dev/null
+++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/initialization/DoubleBraceInitializationInspectionTest.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.initialization;
+
+import com.intellij.codeInspection.InspectionProfileEntry;
+import com.siyeh.ig.LightInspectionTestCase;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author Bas Leijdekkers
+ */
+public class DoubleBraceInitializationInspectionTest extends LightInspectionTestCase {
+
+ public void testDoubleBraceInitialization() { doTest(); }
+
+ @Nullable
+ @Override
+ protected InspectionProfileEntry getInspection() {
+ return new DoubleBraceInitializationInspection();
+ }
+}
diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/initialization/NonThreadSafeLazyInitializationInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/initialization/NonThreadSafeLazyInitializationInspectionTest.java
new file mode 100644
index 000000000000..331eb67dd5bf
--- /dev/null
+++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/initialization/NonThreadSafeLazyInitializationInspectionTest.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.initialization;
+
+import com.intellij.codeInspection.InspectionProfileEntry;
+import com.siyeh.ig.LightInspectionTestCase;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author Bas Leijdekkers
+ */
+public class NonThreadSafeLazyInitializationInspectionTest extends LightInspectionTestCase {
+
+ public void testNonThreadSafeLazyInitialization() { doTest(); }
+
+ @Nullable
+ @Override
+ protected InspectionProfileEntry getInspection() {
+ return new NonThreadSafeLazyInitializationInspection();
+ }
+}
diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/memory/AnonymousInnerClassMayBeStaticInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/memory/AnonymousInnerClassMayBeStaticInspectionTest.java
new file mode 100644
index 000000000000..6fe5d7314190
--- /dev/null
+++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/memory/AnonymousInnerClassMayBeStaticInspectionTest.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.memory;
+
+import com.intellij.codeInspection.InspectionProfileEntry;
+import com.siyeh.ig.LightInspectionTestCase;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author Bas Leijdekkers
+ */
+public class AnonymousInnerClassMayBeStaticInspectionTest extends LightInspectionTestCase {
+
+ public void testAnonymousInnerClassMayBeStatic() { doTest(); }
+
+ @Nullable
+ @Override
+ protected InspectionProfileEntry getInspection() {
+ return new AnonymousInnerClassMayBeStaticInspection();
+ }
+} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/memory/InnerClassMayBeStaticInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/memory/InnerClassMayBeStaticInspectionTest.java
new file mode 100644
index 000000000000..36f42d1f12ef
--- /dev/null
+++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/memory/InnerClassMayBeStaticInspectionTest.java
@@ -0,0 +1,16 @@
+package com.siyeh.ig.memory;
+
+import com.intellij.codeInspection.InspectionProfileEntry;
+import com.siyeh.ig.LightInspectionTestCase;
+import org.jetbrains.annotations.Nullable;
+
+public class InnerClassMayBeStaticInspectionTest extends LightInspectionTestCase {
+
+ public void testInnerClassMayBeStatic() { doTest(); }
+
+ @Nullable
+ @Override
+ protected InspectionProfileEntry getInspection() {
+ return new InnerClassMayBeStaticInspection();
+ }
+} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/performance/InnerClassMayBeStaticInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/performance/InnerClassMayBeStaticInspectionTest.java
deleted file mode 100644
index 02b57fd22746..000000000000
--- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/performance/InnerClassMayBeStaticInspectionTest.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.siyeh.ig.performance;
-
-import com.siyeh.ig.IGInspectionTestCase;
-
-public class InnerClassMayBeStaticInspectionTest extends IGInspectionTestCase {
-
- public void test() throws Exception {
- doTest("com/siyeh/igtest/performance/inner_class_may_be_static",
- new InnerClassMayBeStaticInspection());
- }
-} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/style/CStyleArrayDeclarationInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/style/CStyleArrayDeclarationInspectionTest.java
new file mode 100644
index 000000000000..613a0fc3bf3a
--- /dev/null
+++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/style/CStyleArrayDeclarationInspectionTest.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.style;
+
+import com.intellij.codeInspection.InspectionProfileEntry;
+import com.siyeh.ig.LightInspectionTestCase;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author Bas Leijdekkers
+ */
+public class CStyleArrayDeclarationInspectionTest extends LightInspectionTestCase {
+
+ public void testCStyleArrayDeclaration() { doTest(); }
+
+ @Nullable
+ @Override
+ protected InspectionProfileEntry getInspection() {
+ return new CStyleArrayDeclarationInspection();
+ }
+}
diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/style/NestedMethodCallInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/style/NestedMethodCallInspectionTest.java
new file mode 100644
index 000000000000..d67a0d43f7d3
--- /dev/null
+++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/style/NestedMethodCallInspectionTest.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ig.style;
+
+import com.intellij.codeInspection.InspectionProfileEntry;
+import com.siyeh.ig.LightInspectionTestCase;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author Bas Leijdekkers
+ */
+public class NestedMethodCallInspectionTest extends LightInspectionTestCase{
+
+ public void testNestedMethodCall() { doTest(); }
+
+ @Nullable
+ @Override
+ protected InspectionProfileEntry getInspection() {
+ final NestedMethodCallInspection inspection = new NestedMethodCallInspection();
+ inspection.ignoreStaticMethods = true;
+ inspection.ignoreGetterCalls = true;
+ return inspection;
+ }
+}
diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/visibility/AmbiguousFieldAccessInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/visibility/AmbiguousFieldAccessInspectionTest.java
index b3a13f462339..1007f54da048 100644
--- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/visibility/AmbiguousFieldAccessInspectionTest.java
+++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/visibility/AmbiguousFieldAccessInspectionTest.java
@@ -1,10 +1,16 @@
package com.siyeh.ig.visibility;
-import com.siyeh.ig.IGInspectionTestCase;
+import com.intellij.codeInspection.InspectionProfileEntry;
+import com.siyeh.ig.LightInspectionTestCase;
+import org.jetbrains.annotations.Nullable;
-public class AmbiguousFieldAccessInspectionTest extends IGInspectionTestCase {
+public class AmbiguousFieldAccessInspectionTest extends LightInspectionTestCase {
- public void test() throws Exception {
- doTest("com/siyeh/igtest/visibility/ambiguous_field_access", new AmbiguousFieldAccessInspection());
+ public void testAmbiguousFieldAccess() { doTest(); }
+
+ @Nullable
+ @Override
+ protected InspectionProfileEntry getInspection() {
+ return new AmbiguousFieldAccessInspection();
}
} \ No newline at end of file
diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/visibility/AmbiguousMethodCallInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/visibility/AmbiguousMethodCallInspectionTest.java
index 78610e8597d6..7c1c1327ccd7 100644
--- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/visibility/AmbiguousMethodCallInspectionTest.java
+++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/visibility/AmbiguousMethodCallInspectionTest.java
@@ -1,10 +1,21 @@
package com.siyeh.ig.visibility;
-import com.siyeh.ig.IGInspectionTestCase;
+import com.intellij.codeInspection.InspectionProfileEntry;
+import com.siyeh.ig.LightInspectionTestCase;
+import org.jetbrains.annotations.Nullable;
-public class AmbiguousMethodCallInspectionTest extends IGInspectionTestCase {
+public class AmbiguousMethodCallInspectionTest extends LightInspectionTestCase {
- public void test() throws Exception {
- doTest("com/siyeh/igtest/visibility/ambiguous", new AmbiguousMethodCallInspection());
+ public void testAmbiguousMethodCall() { doTest(); }
+
+ @Nullable
+ @Override
+ protected InspectionProfileEntry getInspection() {
+ return new AmbiguousMethodCallInspection();
+ }
+
+ @Override
+ protected String getBasePath() {
+ return "/plugins/InspectionGadgets/test/com/siyeh/igtest/visibility/ambiguous";
}
} \ No newline at end of file
diff --git a/plugins/IntentionPowerPak/src/META-INF/IntentionPowerPack.xml b/plugins/IntentionPowerPak/src/META-INF/IntentionPowerPack.xml
index 73e279fa91a9..95c585fef36c 100644
--- a/plugins/IntentionPowerPak/src/META-INF/IntentionPowerPack.xml
+++ b/plugins/IntentionPowerPak/src/META-INF/IntentionPowerPack.xml
@@ -104,6 +104,12 @@
</intentionAction>
<intentionAction>
+ <className>com.siyeh.ipp.equality.ReplaceEqualityWithSafeEqualsIntention</className>
+ <bundleName>com.siyeh.IntentionPowerPackBundle</bundleName>
+ <categoryKey>intention.category.boolean</categoryKey>
+ </intentionAction>
+
+ <intentionAction>
<className>com.siyeh.ipp.trivialif.ExpandBooleanIntention</className>
<bundleName>com.siyeh.IntentionPowerPackBundle</bundleName>
<categoryKey>intention.category.boolean</categoryKey>
diff --git a/plugins/IntentionPowerPak/src/com/siyeh/IntentionPowerPackBundle.properties b/plugins/IntentionPowerPak/src/com/siyeh/IntentionPowerPackBundle.properties
index 30e64929f8b2..923df3eb28f4 100644
--- a/plugins/IntentionPowerPak/src/com/siyeh/IntentionPowerPackBundle.properties
+++ b/plugins/IntentionPowerPak/src/com/siyeh/IntentionPowerPackBundle.properties
@@ -14,6 +14,7 @@ change.to.end.of.line.comment.intention.family.name=Replace with End Of Line Com
assert.to.if.intention.name=Replace 'assert' with 'if' statement
assert.to.if.intention.family.name=Replace Assert with If Statement
replace.equality.with.safe.equals.intention.name=Replace '==' with safe '.equals()'
+replace.equality.with.safe.not.equals.intention.name=Replace '!=' with safe '!equals()'
replace.equality.with.safe.equals.intention.family.name=Replace Equality with Safe Equals
replace.for.each.loop.with.indexed.for.loop.intention.name=Replace 'for each' loop with indexed 'for' loop
replace.for.each.loop.with.iterator.for.loop.intention.name=Replace 'for each' loop with iterator 'for' loop
@@ -40,7 +41,7 @@ replace.switch.with.if.intention.family.name=Replace Switch with If
simplify.variable.intention.name=Replace with Java-style array declaration
simplify.variable.intention.family.name=Replace with Java Style Array Declaration
constant.expression.intention.family.name=Compute Constant Value
-create.assert.intention.name=Create JUnit Assertion
+create.assert.intention.name=Create JUnit assertion
create.assert.intention.family.name=Create JUnit Assertion
simplify.if.else.intention.name=Simplify 'if else'
simplify.if.else.intention.family.name=Simplify If Else
@@ -81,7 +82,8 @@ char.to.string.intention.name=Replace character literal with string
char.to.string.intention.family.name=Replace Char with String
replace.if.with.conditional.intention.name=Replace 'if else' with '?:'
replace.if.with.conditional.intention.family.name=Replace If Else with Conditional
-replace.equality.with.equals.intention.name=Replace '==' with '.equals()'
+replace.equality.with.equals.intention.name=Replace '==' with 'equals()'
+replace.equality.with.not.equals.intention.name=Replace '!=' with '!equals()'
replace.equality.with.equals.intention.family.name=Replace Equality with Equals
make.call.chain.into.call.sequence.intention.name=Make method call chain into call sequence
make.call.chain.into.call.sequence.intention.family.name=Make Call Chain Into Call Sequence
diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/base/Intention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/base/Intention.java
index 9e1ef7f75f7b..579f36317b4a 100644
--- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/base/Intention.java
+++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/base/Intention.java
@@ -123,14 +123,6 @@ public abstract class Intention extends BaseElementAtCaretIntentionAction {
codeStyleManager.reformat(insertedElement);
}
- protected static void addStatementBefore(String newStatementText, PsiReturnStatement anchor) {
- final Project project = anchor.getProject();
- final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
- final PsiStatement newStatement = factory.createStatementFromText(newStatementText, anchor);
- final PsiElement addedStatement = anchor.getParent().addBefore(newStatement, anchor);
- CodeStyleManager.getInstance(project).reformat(addedStatement);
- }
-
@Nullable
PsiElement findMatchingElement(@Nullable PsiElement element, Editor editor) {
while (element != null) {
diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/decls/SimplifyVariableIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/decls/SimplifyVariableIntention.java
index f127b50fdd79..149d8067c882 100644
--- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/decls/SimplifyVariableIntention.java
+++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/decls/SimplifyVariableIntention.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2005 Dave Griffith
+ * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,7 +17,7 @@ package com.siyeh.ipp.decls;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiVariable;
-import com.intellij.util.IncorrectOperationException;
+import com.intellij.psi.codeStyle.CodeStyleManager;
import com.siyeh.ipp.base.Intention;
import com.siyeh.ipp.base.PsiElementPredicate;
import org.jetbrains.annotations.NotNull;
@@ -29,9 +29,9 @@ public class SimplifyVariableIntention extends Intention {
return new SimplifyVariablePredicate();
}
- public void processIntention(PsiElement element)
- throws IncorrectOperationException {
- final PsiVariable var = (PsiVariable)element;
- var.normalizeDeclaration();
+ public void processIntention(PsiElement element) {
+ final PsiVariable variable = (PsiVariable)element;
+ variable.normalizeDeclaration();
+ CodeStyleManager.getInstance(element.getProject()).reformat(variable);
}
} \ No newline at end of file
diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/equality/ObjectEqualityPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/equality/ObjectEqualityPredicate.java
index 18d55c35fe97..4bea8688ae32 100644
--- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/equality/ObjectEqualityPredicate.java
+++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/equality/ObjectEqualityPredicate.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2005 Dave Griffith
+ * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,7 +19,6 @@ import com.intellij.psi.*;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.TypeConversionUtil;
import com.siyeh.ipp.base.PsiElementPredicate;
-import com.siyeh.ipp.psiutils.ErrorUtil;
class ObjectEqualityPredicate implements PsiElementPredicate {
@@ -34,44 +33,15 @@ class ObjectEqualityPredicate implements PsiElementPredicate {
return false;
}
final PsiExpression lhs = expression.getLOperand();
- final String lhsText = lhs.getText();
- if (PsiKeyword.NULL.equals(lhsText)) {
- return false;
- }
final PsiType lhsType = lhs.getType();
- if (lhsType == null) {
+ if (lhsType == null || lhsType instanceof PsiPrimitiveType || TypeConversionUtil.isEnumType(lhsType)) {
return false;
}
final PsiExpression rhs = expression.getROperand();
if (rhs == null) {
return false;
}
- final String rhsText = rhs.getText();
- if (PsiKeyword.NULL.equals(rhsText)) {
- return false;
- }
final PsiType rhsType = rhs.getType();
- if (rhsType == null) {
- return false;
- }
- if (TypeConversionUtil.isPrimitiveAndNotNull(lhsType) ||
- TypeConversionUtil.isPrimitiveAndNotNull(rhsType)) {
- return false;
- }
- if (rhsType instanceof PsiClassType) {
- final PsiClassType rhsClassType = (PsiClassType)rhsType;
- final PsiClass rhsClass = rhsClassType.resolve();
- if (rhsClass != null && rhsClass.isEnum()) {
- return false;
- }
- }
- if (lhsType instanceof PsiClassType) {
- final PsiClassType lhsClassType = (PsiClassType)lhsType;
- final PsiClass lhsClass = lhsClassType.resolve();
- if (lhsClass != null && lhsClass.isEnum()) {
- return false;
- }
- }
- return !ErrorUtil.containsError(element);
+ return !(rhsType == null || rhsType instanceof PsiPrimitiveType || TypeConversionUtil.isEnumType(rhsType));
}
} \ No newline at end of file
diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/equality/ReplaceEqualityWithEqualsIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/equality/ReplaceEqualityWithEqualsIntention.java
index 9c0119a92797..d0f56b8cc305 100644
--- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/equality/ReplaceEqualityWithEqualsIntention.java
+++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/equality/ReplaceEqualityWithEqualsIntention.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2013 Dave Griffith, Bas Leijdekkers
+ * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,30 +15,37 @@
*/
package com.siyeh.ipp.equality;
-import com.intellij.psi.JavaTokenType;
-import com.intellij.psi.PsiBinaryExpression;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiExpression;
+import com.intellij.psi.*;
import com.intellij.psi.tree.IElementType;
-import com.intellij.util.IncorrectOperationException;
+import com.siyeh.IntentionPowerPackBundle;
import com.siyeh.ig.PsiReplacementUtil;
import com.siyeh.ig.psiutils.ParenthesesUtils;
-import com.siyeh.ipp.base.Intention;
+import com.siyeh.ipp.base.MutablyNamedIntention;
import com.siyeh.ipp.base.PsiElementPredicate;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
-public class ReplaceEqualityWithEqualsIntention extends Intention {
+public class ReplaceEqualityWithEqualsIntention extends MutablyNamedIntention {
+
+ @Override
+ protected String getTextForElement(PsiElement element) {
+ final PsiBinaryExpression binaryExpression = (PsiBinaryExpression)element;
+ final IElementType tokenType = binaryExpression.getOperationTokenType();
+ if (JavaTokenType.NE.equals(tokenType)) {
+ return IntentionPowerPackBundle.message("replace.equality.with.not.equals.intention.name");
+ }
+ else {
+ return IntentionPowerPackBundle.message("replace.equality.with.equals.intention.name");
+ }
+ }
@NotNull
public PsiElementPredicate getElementPredicate() {
return new ObjectEqualityPredicate();
}
- public void processIntention(PsiElement element)
- throws IncorrectOperationException {
- final PsiBinaryExpression exp =
- (PsiBinaryExpression)element;
+ public void processIntention(PsiElement element) {
+ final PsiBinaryExpression exp = (PsiBinaryExpression)element;
final PsiExpression lhs = exp.getLOperand();
final PsiExpression rhs = exp.getROperand();
if (rhs == null) {
diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/equality/ReplaceEqualityWithSafeEqualsIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/equality/ReplaceEqualityWithSafeEqualsIntention.java
index d14804ae2cda..12acaa006f54 100644
--- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/equality/ReplaceEqualityWithSafeEqualsIntention.java
+++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/equality/ReplaceEqualityWithSafeEqualsIntention.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2013 Dave Griffith, Bas Leijdekkers
+ * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,25 +17,36 @@ package com.siyeh.ipp.equality;
import com.intellij.psi.*;
import com.intellij.psi.tree.IElementType;
-import com.intellij.util.IncorrectOperationException;
+import com.intellij.psi.util.PsiUtil;
+import com.siyeh.IntentionPowerPackBundle;
import com.siyeh.ig.PsiReplacementUtil;
+import com.siyeh.ig.psiutils.ClassUtils;
import com.siyeh.ig.psiutils.ParenthesesUtils;
-import com.siyeh.ipp.base.Intention;
+import com.siyeh.ipp.base.MutablyNamedIntention;
import com.siyeh.ipp.base.PsiElementPredicate;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
-public class ReplaceEqualityWithSafeEqualsIntention extends Intention {
+public class ReplaceEqualityWithSafeEqualsIntention extends MutablyNamedIntention {
+
+ @Override
+ protected String getTextForElement(PsiElement element) {
+ final PsiBinaryExpression binaryExpression = (PsiBinaryExpression)element;
+ if (JavaTokenType.NE.equals(binaryExpression.getOperationTokenType())) {
+ return IntentionPowerPackBundle.message("replace.equality.with.safe.not.equals.intention.name");
+ }
+ else {
+ return IntentionPowerPackBundle.message("replace.equality.with.safe.equals.intention.name");
+ }
+ }
@NotNull
public PsiElementPredicate getElementPredicate() {
return new ObjectEqualityPredicate();
}
- public void processIntention(PsiElement element)
- throws IncorrectOperationException {
- final PsiBinaryExpression exp =
- (PsiBinaryExpression)element;
+ public void processIntention(PsiElement element) {
+ final PsiBinaryExpression exp = (PsiBinaryExpression)element;
final PsiExpression lhs = exp.getLOperand();
final PsiExpression rhs = exp.getROperand();
if (rhs == null) {
@@ -56,26 +67,26 @@ public class ReplaceEqualityWithSafeEqualsIntention extends Intention {
final PsiJavaToken operationSign = exp.getOperationSign();
final IElementType tokenType = operationSign.getTokenType();
final String signText = operationSign.getText();
- @NonNls final StringBuilder buffer = new StringBuilder(lhsText);
- buffer.append("==null?");
- buffer.append(rhsText);
- buffer.append(signText);
- buffer.append(" null:");
- if (tokenType.equals(JavaTokenType.NE)) {
- buffer.append('!');
- }
- if (ParenthesesUtils.getPrecedence(strippedLhs) >
- ParenthesesUtils.METHOD_CALL_PRECEDENCE) {
- buffer.append('(');
- buffer.append(lhsText);
- buffer.append(')');
+ @NonNls final StringBuilder newExpression = new StringBuilder();
+ if (PsiUtil.isLanguageLevel7OrHigher(element) && ClassUtils.findClass("java.util.Objects", element) != null) {
+ if (tokenType.equals(JavaTokenType.NE)) {
+ newExpression.append('!');
+ }
+ newExpression.append("java.util.Objects.equals(").append(lhsText).append(',').append(rhsText).append(')');
}
else {
- buffer.append(lhsText);
+ newExpression.append(lhsText).append("==null?").append(rhsText).append(signText).append(" null:");
+ if (tokenType.equals(JavaTokenType.NE)) {
+ newExpression.append('!');
+ }
+ if (ParenthesesUtils.getPrecedence(strippedLhs) > ParenthesesUtils.METHOD_CALL_PRECEDENCE) {
+ newExpression.append('(').append(lhsText).append(')');
+ }
+ else {
+ newExpression.append(lhsText);
+ }
+ newExpression.append(".equals(").append(rhsText).append(')');
}
- buffer.append(".equals(");
- buffer.append(rhsText);
- buffer.append(')');
- PsiReplacementUtil.replaceExpression(exp, buffer.toString());
+ PsiReplacementUtil.replaceExpressionAndShorten(exp, newExpression.toString());
}
} \ No newline at end of file
diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/initialization/SplitDeclarationAndInitializationIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/initialization/SplitDeclarationAndInitializationIntention.java
index 3bbc7a63bd65..aebb8f568814 100644
--- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/initialization/SplitDeclarationAndInitializationIntention.java
+++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/initialization/SplitDeclarationAndInitializationIntention.java
@@ -37,12 +37,11 @@ public class SplitDeclarationAndInitializationIntention extends Intention {
@Override
public void processIntention(@NotNull PsiElement element) {
final PsiField field = (PsiField)element.getParent();
- field.normalizeDeclaration();
- final PsiExpression initializer = RefactoringUtil.convertInitializerToNormalExpression(field.getInitializer(), field.getType());
+ final PsiExpression initializer = field.getInitializer();
if (initializer == null) {
return;
}
- final String initializerText = initializer.getText();
+ final String initializerText = RefactoringUtil.convertInitializerToNormalExpression(initializer, field.getType()).getText();
final PsiClass containingClass = field.getContainingClass();
if (containingClass == null) {
return;
@@ -96,9 +95,7 @@ public class SplitDeclarationAndInitializationIntention extends Intention {
}
}
initializer.delete();
- final CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(manager.getProject());
- codeStyleManager.reformat(field);
- codeStyleManager.reformat(classInitializer);
+ CodeStyleManager.getInstance(manager.getProject()).reformat(classInitializer);
HighlightUtil.highlightElement(addedElement,
IntentionPowerPackBundle.message(
"press.escape.to.remove.highlighting.message"));
diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/CreateAssertIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/CreateAssertIntention.java
index 55ae45e3f3bf..4be5442d03c1 100644
--- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/CreateAssertIntention.java
+++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/CreateAssertIntention.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2006 Dave Griffith, Bas Leijdekkers
+ * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,16 +16,15 @@
package com.siyeh.ipp.junit;
import com.intellij.psi.*;
-import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.tree.IElementType;
-import com.intellij.util.IncorrectOperationException;
-import com.intellij.codeInsight.AnnotationUtil;
import com.siyeh.ig.PsiReplacementUtil;
+import com.siyeh.ig.psiutils.ExpressionUtils;
+import com.siyeh.ig.psiutils.ImportUtils;
import com.siyeh.ipp.base.Intention;
import com.siyeh.ipp.base.PsiElementPredicate;
import com.siyeh.ipp.psiutils.BoolUtils;
-import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
public class CreateAssertIntention extends Intention {
@@ -34,28 +33,12 @@ public class CreateAssertIntention extends Intention {
return new CreateAssertPredicate();
}
- public void processIntention(PsiElement element)
- throws IncorrectOperationException {
- final PsiExpressionStatement statement =
- (PsiExpressionStatement)element;
- assert statement != null;
+ public void processIntention(PsiElement element) {
+ final PsiExpressionStatement statement = (PsiExpressionStatement)element;
final PsiExpression expression = statement.getExpression();
- final PsiMethod containingMethod =
- PsiTreeUtil.getParentOfType(statement, PsiMethod.class);
- final String specifierString;
- if (containingMethod != null &&
- AnnotationUtil.isAnnotated(containingMethod,
- "org.junit.Test", true)) {
- specifierString = "org.junit.Assert.";
- }
- else {
- specifierString = "";
- }
+ final String newStatement;
if (BoolUtils.isNegation(expression)) {
- @NonNls final String newExpression =
- specifierString + "assertFalse(" +
- BoolUtils.getNegatedExpressionText(expression) + ");";
- PsiReplacementUtil.replaceStatementAndShortenClassNames(statement, newExpression);
+ newStatement = buildNewStatement("assertFalse", element, BoolUtils.getNegatedExpressionText(expression));
}
else if (isNullComparison(expression)) {
final PsiBinaryExpression binaryExpression =
@@ -63,16 +46,19 @@ public class CreateAssertIntention extends Intention {
final PsiExpression lhs = binaryExpression.getLOperand();
final PsiExpression rhs = binaryExpression.getROperand();
final PsiExpression comparedExpression;
- if (isNull(lhs)) {
+ if (ExpressionUtils.isNullLiteral(lhs)) {
comparedExpression = rhs;
}
else {
comparedExpression = lhs;
}
assert comparedExpression != null;
- @NonNls final String newExpression = specifierString +
- "assertNull(" + comparedExpression.getText() + ");";
- PsiReplacementUtil.replaceStatementAndShortenClassNames(statement, newExpression);
+ if (JavaTokenType.EQEQ.equals(binaryExpression.getOperationTokenType())) {
+ newStatement = buildNewStatement("assertNull", element, comparedExpression.getText());
+ }
+ else {
+ newStatement = buildNewStatement("assertNotNull", element, comparedExpression.getText());
+ }
}
else if (isEqualityComparison(expression)) {
final PsiBinaryExpression binaryExpression =
@@ -91,23 +77,16 @@ public class CreateAssertIntention extends Intention {
}
assert comparingExpression != null;
final PsiType type = lhs.getType();
- @NonNls final String newExpression;
if (PsiType.DOUBLE.equals(type) || PsiType.FLOAT.equals(type)) {
- newExpression = specifierString + "assertEquals(" +
- comparedExpression.getText() + ", " +
- comparingExpression.getText() + ", 0.0);";
+ newStatement = buildNewStatement("assertEquals",
+ element, comparedExpression.getText(), comparingExpression.getText(), "0.0");
}
else if (type instanceof PsiPrimitiveType) {
- newExpression = specifierString + "assertEquals(" +
- comparedExpression.getText() + ", " +
- comparingExpression.getText() + ");";
+ newStatement = buildNewStatement("assertEquals", element, comparedExpression.getText(), comparingExpression.getText());
}
else {
- newExpression = specifierString + "assertSame(" +
- comparedExpression.getText() + ", " +
- comparingExpression.getText() + ");";
+ newStatement = buildNewStatement("assertSame", element, comparedExpression.getText(), comparingExpression.getText());
}
- PsiReplacementUtil.replaceStatementAndShortenClassNames(statement, newExpression);
}
else if (isEqualsExpression(expression)) {
final PsiMethodCallExpression call =
@@ -118,26 +97,55 @@ public class CreateAssertIntention extends Intention {
methodExpression.getQualifierExpression();
assert comparedExpression != null;
final PsiExpressionList argList = call.getArgumentList();
- final PsiExpression comparingExpression =
- argList.getExpressions()[0];
- @NonNls final String newExpression;
+ final PsiExpression comparingExpression = argList.getExpressions()[0];
if (comparingExpression instanceof PsiLiteralExpression) {
- newExpression = specifierString + "assertEquals(" +
- comparingExpression.getText() + ", " +
- comparedExpression.getText() + ");";
+ newStatement = buildNewStatement("assertEquals", element, comparingExpression.getText(), comparedExpression.getText());
+ }
+ else {
+ newStatement = buildNewStatement("assertEquals", element, comparedExpression.getText(), comparingExpression.getText());
+ }
+ }
+ else {
+ newStatement = buildNewStatement("assertTrue", element, expression.getText());
+ }
+ PsiReplacementUtil.replaceStatementAndShortenClassNames(statement, newStatement);
+ }
+
+ @NonNls
+ private static String buildNewStatement(@NonNls String memberName, PsiElement context, String... argumentTexts) {
+ final PsiElementFactory factory = JavaPsiFacade.getElementFactory(context.getProject());
+ final StringBuilder builder = new StringBuilder(memberName).append('(');
+ boolean comma = false;
+ for (String argumentText : argumentTexts) {
+ if (comma) {
+ builder.append(',');
}
else {
- newExpression = specifierString + "assertEquals(" +
- comparedExpression.getText() + ", " +
- comparingExpression.getText() + ");";
+ comma = true;
}
- PsiReplacementUtil.replaceStatementAndShortenClassNames(statement, newExpression);
+ builder.append(argumentText);
+ }
+ builder.append(')');
+ final String text = builder.toString();
+
+ final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)factory.createExpressionFromText(text, context);
+ final PsiMethod method = methodCallExpression.resolveMethod();
+ if (method != null || hasStaticImports(context) && ImportUtils.addStaticImport("org.junit.Assert", memberName, context)) {
+ return text + ';';
}
else {
- @NonNls final String newExpression =
- specifierString + "assertTrue(" + expression.getText() + ");";
- PsiReplacementUtil.replaceStatementAndShortenClassNames(statement, newExpression);
+ return "org.junit.Assert." + text + ';';
+ }
+ }
+
+ private static boolean hasStaticImports(PsiElement element) {
+ final PsiFile file = element.getContainingFile();
+ if (!(file instanceof PsiJavaFile)) {
+ return false;
}
+ final PsiJavaFile javaFile = (PsiJavaFile)file;
+ final PsiImportList importList = javaFile.getImportList();
+ return importList != null && importList.getImportStaticStatements().length > 0;
}
private static boolean isEqualsExpression(PsiExpression expression) {
@@ -176,25 +184,16 @@ public class CreateAssertIntention extends Intention {
if (!(expression instanceof PsiBinaryExpression)) {
return false;
}
- final PsiBinaryExpression binaryExpression =
- (PsiBinaryExpression)expression;
+ final PsiBinaryExpression binaryExpression = (PsiBinaryExpression)expression;
final IElementType tokenType = binaryExpression.getOperationTokenType();
- if (!JavaTokenType.EQEQ.equals(tokenType)) {
+ if (!JavaTokenType.EQEQ.equals(tokenType) && !JavaTokenType.NE.equals(tokenType)) {
return false;
}
final PsiExpression lhs = binaryExpression.getLOperand();
- if (isNull(lhs)) {
+ if (ExpressionUtils.isNullLiteral(lhs)) {
return true;
}
- final PsiExpression Rhs = binaryExpression.getROperand();
- return isNull(Rhs);
- }
-
- private static boolean isNull(PsiExpression expression) {
- if (!(expression instanceof PsiLiteralExpression)) {
- return false;
- }
- @NonNls final String text = expression.getText();
- return PsiKeyword.NULL.equals(text);
+ final PsiExpression rhs = binaryExpression.getROperand();
+ return ExpressionUtils.isNullLiteral(rhs);
}
}
diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/CreateAssertPredicate.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/CreateAssertPredicate.java
index 27f09f9c3b80..c21bb76aa1bc 100644
--- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/CreateAssertPredicate.java
+++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/junit/CreateAssertPredicate.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2009 Dave Griffith, Bas Leijdekkers
+ * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,14 +15,10 @@
*/
package com.siyeh.ipp.junit;
-import com.intellij.codeInsight.AnnotationUtil;
-import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
-import com.intellij.psi.search.GlobalSearchScope;
-import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiTreeUtil;
+import com.siyeh.ig.psiutils.TestUtils;
import com.siyeh.ipp.base.PsiElementPredicate;
-import org.jetbrains.annotations.NonNls;
class CreateAssertPredicate implements PsiElementPredicate {
@@ -41,50 +37,13 @@ class CreateAssertPredicate implements PsiElementPredicate {
if (!PsiType.BOOLEAN.equals(type)) {
return false;
}
- final PsiMethod containingMethod =
- PsiTreeUtil.getParentOfType(expression, PsiMethod.class);
- return isTestMethod(containingMethod);
- }
-
- private static boolean isTestMethod(PsiMethod method) {
- if (method == null) {
- return false;
- }
- if (AnnotationUtil.isAnnotated(method, "org.junit.Test", true)) {
- return true;
- }
- if (method.hasModifierProperty(PsiModifier.ABSTRACT) ||
- !method.hasModifierProperty(PsiModifier.PUBLIC)) {
- return false;
- }
- final PsiType returnType = method.getReturnType();
- if (returnType == null) {
- return false;
- }
- if (!returnType.equals(PsiType.VOID)) {
- return false;
- }
- final PsiParameterList parameterList = method.getParameterList();
- final PsiParameter[] parameters = parameterList.getParameters();
- if (parameters.length != 0) {
- return false;
- }
- @NonNls final String methodName = method.getName();
- if (!methodName.startsWith("test")) {
- return false;
- }
- final PsiClass containingClass = method.getContainingClass();
- return isTestClass(containingClass);
- }
-
- private static boolean isTestClass(PsiClass aClass) {
- if (aClass == null) {
- return false;
+ PsiMethod containingMethod = PsiTreeUtil.getParentOfType(expression, PsiMethod.class);
+ while (containingMethod != null) {
+ if (TestUtils.isJUnitTestMethod(containingMethod)) {
+ return true;
+ }
+ containingMethod = PsiTreeUtil.getParentOfType(containingMethod, PsiMethod.class);
}
- final Project project = aClass.getProject();
- final GlobalSearchScope scope = GlobalSearchScope.allScope(project);
- final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project);
- final PsiClass ancestorClass = psiFacade.findClass("junit.framework.TestCase", scope);
- return InheritanceUtil.isInheritorOrSelf(aClass, ancestorClass, true);
+ return false;
}
}
diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/decls/simplify_variable/FieldWithWhitespace.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/decls/simplify_variable/FieldWithWhitespace.java
new file mode 100644
index 000000000000..38de2d7356b7
--- /dev/null
+++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/decls/simplify_variable/FieldWithWhitespace.java
@@ -0,0 +1,4 @@
+public class FieldWithWhitespace {
+
+ private String ss<caret> [];
+} \ No newline at end of file
diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/decls/simplify_variable/FieldWithWhitespace_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/decls/simplify_variable/FieldWithWhitespace_after.java
new file mode 100644
index 000000000000..c53875ed975c
--- /dev/null
+++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/decls/simplify_variable/FieldWithWhitespace_after.java
@@ -0,0 +1,4 @@
+public class FieldWithWhitespace {
+
+ private String[] ss;
+} \ No newline at end of file
diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_equals/EnumComparison.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_equals/EnumComparison.java
new file mode 100644
index 000000000000..bf1f08c198c5
--- /dev/null
+++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_equals/EnumComparison.java
@@ -0,0 +1,8 @@
+public class EnumComparison {
+
+ enum E { A, B }
+
+ boolean a(E a, E b) {
+ return a ==<caret> b;
+ }
+} \ No newline at end of file
diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_equals/NegatedObjectComparison.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_equals/NegatedObjectComparison.java
new file mode 100644
index 000000000000..863fa48d0c78
--- /dev/null
+++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_equals/NegatedObjectComparison.java
@@ -0,0 +1,6 @@
+public class NegatedObjectComparison {
+
+ boolean a(Object a, Object b) {
+ return a !=<caret> b;
+ }
+} \ No newline at end of file
diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_equals/NegatedObjectComparison_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_equals/NegatedObjectComparison_after.java
new file mode 100644
index 000000000000..72eda7377647
--- /dev/null
+++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_equals/NegatedObjectComparison_after.java
@@ -0,0 +1,6 @@
+public class NegatedObjectComparison {
+
+ boolean a(Object a, Object b) {
+ return !a.equals(b);
+ }
+} \ No newline at end of file
diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_equals/NullComparison.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_equals/NullComparison.java
new file mode 100644
index 000000000000..559ec3aec144
--- /dev/null
+++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_equals/NullComparison.java
@@ -0,0 +1,6 @@
+public class NullComparison {
+
+ boolean a(Object a) {
+ return a ==<caret> null;
+ }
+} \ No newline at end of file
diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_equals/PrimitiveComparison.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_equals/PrimitiveComparison.java
new file mode 100644
index 000000000000..0f25977323ab
--- /dev/null
+++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_equals/PrimitiveComparison.java
@@ -0,0 +1,6 @@
+public class PrimitiveComparison {
+
+ boolean a(int i, int j) {
+ return i <caret>== j;
+ }
+} \ No newline at end of file
diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_equals/SimpleObjectComparison.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_equals/SimpleObjectComparison.java
new file mode 100644
index 000000000000..baccea789e04
--- /dev/null
+++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_equals/SimpleObjectComparison.java
@@ -0,0 +1,6 @@
+public class SimpleObjectComparison {
+
+ boolean a(Object a, Object b) {
+ return a == b<caret>;
+ }
+} \ No newline at end of file
diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_equals/SimpleObjectComparison_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_equals/SimpleObjectComparison_after.java
new file mode 100644
index 000000000000..ab1bcce4c87b
--- /dev/null
+++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_equals/SimpleObjectComparison_after.java
@@ -0,0 +1,6 @@
+public class SimpleObjectComparison {
+
+ boolean a(Object a, Object b) {
+ return a.equals(b);
+ }
+} \ No newline at end of file
diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_safe_equals/EnumComparison.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_safe_equals/EnumComparison.java
new file mode 100644
index 000000000000..43b16a421c25
--- /dev/null
+++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_safe_equals/EnumComparison.java
@@ -0,0 +1,10 @@
+package com.siyeh.ipp.equality.replace_equality_with_safe_equals;
+
+public class EnumComparison {
+
+ enum E { A, B }
+
+ boolean a(E a, E b) {
+ return a ==<caret> b;
+ }
+} \ No newline at end of file
diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_safe_equals/NegatedObjectComparison.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_safe_equals/NegatedObjectComparison.java
new file mode 100644
index 000000000000..018def909d05
--- /dev/null
+++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_safe_equals/NegatedObjectComparison.java
@@ -0,0 +1,8 @@
+package com.siyeh.ipp.equality.replace_equality_with_safe_equals;
+
+public class NegatedObjectComparison {
+
+ boolean a(Object a, Object b) {
+ return a !=<caret> b;
+ }
+} \ No newline at end of file
diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_safe_equals/NegatedObjectComparison_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_safe_equals/NegatedObjectComparison_after.java
new file mode 100644
index 000000000000..b7f48289a4b8
--- /dev/null
+++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_safe_equals/NegatedObjectComparison_after.java
@@ -0,0 +1,8 @@
+package com.siyeh.ipp.equality.replace_equality_with_safe_equals;
+
+public class NegatedObjectComparison {
+
+ boolean a(Object a, Object b) {
+ return a == null ? b != null : !a.equals(b);
+ }
+} \ No newline at end of file
diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_safe_equals/NullComparison.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_safe_equals/NullComparison.java
new file mode 100644
index 000000000000..10aeb19f6fed
--- /dev/null
+++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_safe_equals/NullComparison.java
@@ -0,0 +1,8 @@
+package com.siyeh.ipp.equality.replace_equality_with_safe_equals;
+
+public class NullComparison {
+
+ boolean a(Object a) {
+ return a ==<caret> null;
+ }
+} \ No newline at end of file
diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_safe_equals/PrimitiveComparison.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_safe_equals/PrimitiveComparison.java
new file mode 100644
index 000000000000..8ae058592d0a
--- /dev/null
+++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_safe_equals/PrimitiveComparison.java
@@ -0,0 +1,8 @@
+package com.siyeh.ipp.equality.replace_equality_with_safe_equals;
+
+public class PrimitiveComparison {
+
+ boolean a(int i, int j) {
+ return i <caret>== j;
+ }
+} \ No newline at end of file
diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_safe_equals/SimpleObjectComparison.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_safe_equals/SimpleObjectComparison.java
new file mode 100644
index 000000000000..304b06ff67a1
--- /dev/null
+++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_safe_equals/SimpleObjectComparison.java
@@ -0,0 +1,8 @@
+package com.siyeh.ipp.equality.replace_equality_with_safe_equals;
+
+public class SimpleObjectComparison {
+
+ boolean a(Object a, Object b) {
+ return a == b<caret>;
+ }
+} \ No newline at end of file
diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_safe_equals/SimpleObjectComparison_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_safe_equals/SimpleObjectComparison_after.java
new file mode 100644
index 000000000000..5ee0ddf5d6df
--- /dev/null
+++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/equality/replace_equality_with_safe_equals/SimpleObjectComparison_after.java
@@ -0,0 +1,8 @@
+package com.siyeh.ipp.equality.replace_equality_with_safe_equals;
+
+public class SimpleObjectComparison {
+
+ boolean a(Object a, Object b) {
+ return a == null ? b == null : a.equals(b);
+ }
+} \ No newline at end of file
diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/initialization/Array.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/initialization/Array.java
new file mode 100644
index 000000000000..486097f3f88a
--- /dev/null
+++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/initialization/Array.java
@@ -0,0 +1,3 @@
+class Array {
+ String s []<caret> = {};
+} \ No newline at end of file
diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/initialization/ArrayInitializer.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/initialization/ArrayInitializer.java
index 54eaa025b8e8..6ea7f3cf2dd7 100644
--- a/plugins/IntentionPowerPak/test/com/siyeh/ipp/initialization/ArrayInitializer.java
+++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/initialization/ArrayInitializer.java
@@ -1,3 +1,3 @@
class X {
- String s <caret>= {};
+ String s <caret>= {};
} \ No newline at end of file
diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/initialization/Array_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/initialization/Array_after.java
new file mode 100644
index 000000000000..6aeac61776f9
--- /dev/null
+++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/initialization/Array_after.java
@@ -0,0 +1,7 @@
+class Array {
+ String s [];
+
+ {
+ s = new String[]{};
+ }
+} \ No newline at end of file
diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/junit/create_assert/AnonymousClassJUnit3.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/junit/create_assert/AnonymousClassJUnit3.java
new file mode 100644
index 000000000000..d6c02fcfbe66
--- /dev/null
+++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/junit/create_assert/AnonymousClassJUnit3.java
@@ -0,0 +1,12 @@
+import junit.framework.TestCase;
+
+public class AnonymousClassJUnit3 extends TestCase {
+
+ public void test2BiggerThan1() {
+ new Object() {
+ void foo() {
+ 2 > 1<caret>
+ }
+ };
+ }
+} \ No newline at end of file
diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/junit/create_assert/AnonymousClassJUnit3_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/junit/create_assert/AnonymousClassJUnit3_after.java
new file mode 100644
index 000000000000..9821c9431820
--- /dev/null
+++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/junit/create_assert/AnonymousClassJUnit3_after.java
@@ -0,0 +1,12 @@
+import junit.framework.TestCase;
+
+public class AnonymousClassJUnit3 extends TestCase {
+
+ public void test2BiggerThan1() {
+ new Object() {
+ void foo() {
+ assertTrue(2 > 1);
+ }
+ };
+ }
+} \ No newline at end of file
diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/junit/create_assert/AnonymousClassJUnit4.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/junit/create_assert/AnonymousClassJUnit4.java
new file mode 100644
index 000000000000..e7b11eef3a87
--- /dev/null
+++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/junit/create_assert/AnonymousClassJUnit4.java
@@ -0,0 +1,11 @@
+public class AnonymousClassJUnit4 {
+
+ @org.junit.Test
+ public void test2BiggerThan1() {
+ new Object() {
+ void foo() {
+ 2 > 1<caret>
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/junit/create_assert/AnonymousClassJUnit4_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/junit/create_assert/AnonymousClassJUnit4_after.java
new file mode 100644
index 000000000000..787d0e6d6115
--- /dev/null
+++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/junit/create_assert/AnonymousClassJUnit4_after.java
@@ -0,0 +1,13 @@
+import org.junit.Assert;
+
+public class AnonymousClassJUnit4 {
+
+ @org.junit.Test
+ public void test2BiggerThan1() {
+ new Object() {
+ void foo() {
+ Assert.assertTrue(2 > 1);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/junit/create_assert/AssertFalse.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/junit/create_assert/AssertFalse.java
new file mode 100644
index 000000000000..76bddf465b6f
--- /dev/null
+++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/junit/create_assert/AssertFalse.java
@@ -0,0 +1,12 @@
+import junit.framework.TestCase;
+
+public class AssertFalse extends TestCase {
+
+ public void testOne() {
+ !result()<caret>
+ }
+
+ boolean result() {
+ return false;
+ }
+} \ No newline at end of file
diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/junit/create_assert/AssertFalse_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/junit/create_assert/AssertFalse_after.java
new file mode 100644
index 000000000000..6c1ad31f57a6
--- /dev/null
+++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/junit/create_assert/AssertFalse_after.java
@@ -0,0 +1,12 @@
+import junit.framework.TestCase;
+
+public class AssertFalse extends TestCase {
+
+ public void testOne() {
+ assertFalse(result());
+ }
+
+ boolean result() {
+ return false;
+ }
+} \ No newline at end of file
diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/junit/create_assert/StaticImportJUnit4.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/junit/create_assert/StaticImportJUnit4.java
new file mode 100644
index 000000000000..24abc14797f4
--- /dev/null
+++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/junit/create_assert/StaticImportJUnit4.java
@@ -0,0 +1,9 @@
+import static java.util.Collections.EMPTY_LIST;
+
+public class AnonymousClassJUnit4 {
+
+ @org.junit.Test
+ public void testNotNull() {
+ EMPTY_LIST != null<caret>
+ }
+} \ No newline at end of file
diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/junit/create_assert/StaticImportJUnit4_after.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/junit/create_assert/StaticImportJUnit4_after.java
new file mode 100644
index 000000000000..792a4f778816
--- /dev/null
+++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/junit/create_assert/StaticImportJUnit4_after.java
@@ -0,0 +1,10 @@
+import static java.util.Collections.EMPTY_LIST;
+import static org.junit.Assert.assertNotNull;
+
+public class AnonymousClassJUnit4 {
+
+ @org.junit.Test
+ public void testNotNull() {
+ assertNotNull(EMPTY_LIST);
+ }
+} \ No newline at end of file
diff --git a/plugins/IntentionPowerPak/test/com/siyeh/ipp/types/lambda2anonymous/Ambiguity.java b/plugins/IntentionPowerPak/test/com/siyeh/ipp/types/lambda2anonymous/Ambiguity.java
index 6df5c30ae69a..e8be7a9d0b0c 100644
--- a/plugins/IntentionPowerPak/test/com/siyeh/ipp/types/lambda2anonymous/Ambiguity.java
+++ b/plugins/IntentionPowerPak/test/com/siyeh/ipp/types/lambda2anonymous/Ambiguity.java
@@ -2,14 +2,14 @@ interface I1 {
void m();
}
-interface I2<X> {
- X m();
+interface I2 {
+ void m();
}
class Ambiguity1 {
static void m(I1 i1) {}
- static <T> void m(I2<T> i2) {}
+ static void m(I2 i2) {}
{
m((<caret>)->{throw new AssertionError();});
diff --git a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/decls/SimplifyVariableIntentionTest.java b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/decls/SimplifyVariableIntentionTest.java
new file mode 100644
index 000000000000..1d340724138b
--- /dev/null
+++ b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/decls/SimplifyVariableIntentionTest.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ipp.decls;
+
+import com.siyeh.IntentionPowerPackBundle;
+import com.siyeh.ipp.IPPTestCase;
+import junit.framework.TestCase;
+
+/**
+ * @author Bas Leijdekkers
+ */
+public class SimplifyVariableIntentionTest extends IPPTestCase {
+
+ public void testFieldWithWhitespace() { doTest(); }
+
+ @Override
+ protected String getIntentionName() {
+ return IntentionPowerPackBundle.message("simplify.variable.intention.name");
+ }
+
+ @Override
+ protected String getRelativePath() {
+ return "decls/simplify_variable";
+ }
+} \ No newline at end of file
diff --git a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/equality/ReplaceEqualityWithEqualsIntentionTest.java b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/equality/ReplaceEqualityWithEqualsIntentionTest.java
new file mode 100644
index 000000000000..f9150050fbdd
--- /dev/null
+++ b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/equality/ReplaceEqualityWithEqualsIntentionTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ipp.equality;
+
+import com.siyeh.IntentionPowerPackBundle;
+import com.siyeh.ipp.IPPTestCase;
+
+/**
+ * @see com.siyeh.ipp.equality.ReplaceEqualityWithEqualsIntention
+ * @author Bas Leijdekkers
+ */
+public class ReplaceEqualityWithEqualsIntentionTest extends IPPTestCase {
+
+ public void testEnumComparison() { assertIntentionNotAvailable(); }
+ public void testNullComparison() { assertIntentionNotAvailable(); }
+ public void testPrimitiveComparison() { assertIntentionNotAvailable(); }
+ public void testSimpleObjectComparison() { doTest(); }
+ public void testNegatedObjectComparison() { doTest(IntentionPowerPackBundle.message("replace.equality.with.not.equals.intention.name")); }
+
+ @Override
+ protected String getIntentionName() {
+ return IntentionPowerPackBundle.message("replace.equality.with.equals.intention.name");
+ }
+
+ @Override
+ protected String getRelativePath() {
+ return "equality/replace_equality_with_equals";
+ }
+} \ No newline at end of file
diff --git a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/equality/ReplaceEqualityWithSafeEqualsIntentionTest.java b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/equality/ReplaceEqualityWithSafeEqualsIntentionTest.java
new file mode 100644
index 000000000000..c2fe09148f9a
--- /dev/null
+++ b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/equality/ReplaceEqualityWithSafeEqualsIntentionTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ipp.equality;
+
+import com.siyeh.IntentionPowerPackBundle;
+import com.siyeh.ipp.IPPTestCase;
+
+/**
+ * @see com.siyeh.ipp.equality.ReplaceEqualityWithSafeEqualsIntention
+ * @author Bas Leijdekkers
+ */
+public class ReplaceEqualityWithSafeEqualsIntentionTest extends IPPTestCase {
+
+ public void testEnumComparison() { assertIntentionNotAvailable(); }
+ public void testNullComparison() { assertIntentionNotAvailable(); }
+ public void testPrimitiveComparison() { assertIntentionNotAvailable(); }
+ public void testSimpleObjectComparison() { doTest(); }
+ public void testNegatedObjectComparison() { doTest(IntentionPowerPackBundle.message("replace.equality.with.safe.not.equals.intention.name")); }
+
+ @Override
+ protected String getIntentionName() {
+ return IntentionPowerPackBundle.message("replace.equality.with.safe.equals.intention.name");
+ }
+
+ @Override
+ protected String getRelativePath() {
+ return "equality/replace_equality_with_safe_equals";
+ }
+} \ No newline at end of file
diff --git a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/initialization/SplitDeclarationAndInitializationIntentionTest.java b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/initialization/SplitDeclarationAndInitializationIntentionTest.java
index 63ac3c9acf9f..933d5e2e7964 100644
--- a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/initialization/SplitDeclarationAndInitializationIntentionTest.java
+++ b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/initialization/SplitDeclarationAndInitializationIntentionTest.java
@@ -25,6 +25,7 @@ import com.siyeh.ipp.IPPTestCase;
public class SplitDeclarationAndInitializationIntentionTest extends IPPTestCase {
public void testArrayInitializer() { doTest(); }
+ public void testArray() { doTest(); }
@Override
protected String getRelativePath() {
diff --git a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/junit/CreateAssertIntentionTest.java b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/junit/CreateAssertIntentionTest.java
new file mode 100644
index 000000000000..b67a451ce947
--- /dev/null
+++ b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/junit/CreateAssertIntentionTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.siyeh.ipp.junit;
+
+import com.siyeh.IntentionPowerPackBundle;
+import com.siyeh.ipp.IPPTestCase;
+
+/**
+ * @see CreateAssertIntention
+ * @author Bas Leijdekkers
+ */
+public class CreateAssertIntentionTest extends IPPTestCase {
+
+ public void testAnonymousClassJUnit3() { doTest(); }
+ public void testAnonymousClassJUnit4() { doTest(); }
+ public void testStaticImportJUnit4() { doTest(); }
+ public void testAssertFalse() { doTest(); }
+
+ @Override
+ protected String getRelativePath() {
+ return "junit/create_assert";
+ }
+
+ @Override
+ protected String getIntentionName() {
+ return IntentionPowerPackBundle.message("create.assert.intention.name");
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ myFixture.addClass("package org.junit;" +
+ "class Assert {" +
+ " public static void assertTrue(java.lang.String message, boolean condition) {}" +
+ " public static void assertNotNull(boolean condition) {}" +
+ "}");
+ myFixture.addClass("package org.junit;" +
+ "@Retention(RetentionPolicy.RUNTIME)" +
+ "@Target({ElementType.METHOD})" +
+ "public @interface Test {}");
+ myFixture.addClass("package junit.framework;" +
+ "public abstract class TestCase {" +
+ " static public void assertTrue(boolean condition) {}" +
+ " static public void assertFalse(boolean condition) {}"
+ );
+ }
+}
diff --git a/plugins/ShortcutPromoter/src/com/intellij/promoter/ShortcutPromoterManager.java b/plugins/ShortcutPromoter/src/com/intellij/promoter/ShortcutPromoterManager.java
index 227d96245080..3baafb1fe510 100644
--- a/plugins/ShortcutPromoter/src/com/intellij/promoter/ShortcutPromoterManager.java
+++ b/plugins/ShortcutPromoter/src/com/intellij/promoter/ShortcutPromoterManager.java
@@ -22,11 +22,7 @@ import java.util.LinkedHashMap;
*/
@State(
name = "ShortcutPromoterManager",
- roamingType = RoamingType.PER_PLATFORM,
- storages = {
- @Storage(
- file = StoragePathMacros.APP_CONFIG + "/promoter.xml"
- )}
+ storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/promoter.xml", roamingType = RoamingType.PER_PLATFORM)}
)
public class ShortcutPromoterManager implements ApplicationComponent, AnActionListener, ExportableApplicationComponent,
PersistentStateComponent<Element> {
@@ -97,10 +93,6 @@ public class ShortcutPromoterManager implements ApplicationComponent, AnActionLi
@Nullable
@Override
public Element getState() {
- if (myState.isEmpty()) {
- return null;
- }
-
final Element actions = new Element("actions");
for (String id : myState.keySet()) {
final Element action = new Element("action");
diff --git a/plugins/cvs/cvs-plugin/src/META-INF/plugin.xml b/plugins/cvs/cvs-plugin/src/META-INF/plugin.xml
index 1cefc9748ae4..d42cab21ddac 100644
--- a/plugins/cvs/cvs-plugin/src/META-INF/plugin.xml
+++ b/plugins/cvs/cvs-plugin/src/META-INF/plugin.xml
@@ -63,7 +63,7 @@
<add-to-group group-id="Vcs.Browse"/>
</action>
- <group id="CvsGlobalGroup" class="com.intellij.cvsSupport2.actions.Cvs2Group" test="CVS" popup="true">
+ <group id="CvsGlobalGroup" class="com.intellij.cvsSupport2.actions.Cvs2Group" popup="true">
<add-to-group group-id="VcsGlobalGroup" anchor="after" relative-to-action="Vcs.Specific"/>
<separator/>
<action id="GlobalSettings" class="com.intellij.cvsSupport2.actions.GlobalSettingsAction"/>
@@ -72,7 +72,7 @@
<separator/>
</group>
- <group id="CvsFilePopupGroup" class="com.intellij.cvsSupport2.actions.Cvs2Group" test="CVS" popup="true">
+ <group id="CvsFilePopupGroup" class="com.intellij.cvsSupport2.actions.Cvs2Group" popup="true">
<add-to-group group-id="VcsGroup" anchor="last"/>
</group>
@@ -80,8 +80,8 @@
<add-to-group group-id="UpdateActionGroup" anchor="last"/>
</action>
- <group id="AddOptionDialogActionGroup" test="">
- <action id="Cvs.Ignore" class="com.intellij.cvsSupport2.actions.IgnoreFileAction">
+ <group id="AddOptionDialogActionGroup">
+ <action id="Cvs.Ignore" class="com.intellij.cvsSupport2.actions.IgnoreFileAction">
<add-to-group group-id="Vcs.CheckinProjectPopup" anchor="last"/>
</action>
</group>
diff --git a/plugins/devkit/resources/org/jetbrains/idea/devkit/DevKitBundle.properties b/plugins/devkit/resources/org/jetbrains/idea/devkit/DevKitBundle.properties
index 6799f6d2415f..2d1f3de4e3d6 100644
--- a/plugins/devkit/resources/org/jetbrains/idea/devkit/DevKitBundle.properties
+++ b/plugins/devkit/resources/org/jetbrains/idea/devkit/DevKitBundle.properties
@@ -25,7 +25,7 @@ prepare.for.deployment.common=Preparing For Deployment
prepare.for.deployment=Prepare Plugin Module ''{0}'' For Deployment
prepare.for.deployment.all=Prepare All Plugin Modules For Deployment
saved.message.common={0} will be saved in selected directory
-saved.message= {0, choice, 1#Zip|2#Jar} for module ''{1}'' was saved to {2}
+saved.message= {0, choice, 1#Zip|2#JAR} for module ''{1}'' was saved to {2}
success.deployment.message=Plugin Module ''{0}'' Successfully Prepared For Deployment
success.deployment.message.all=All Plugins Successfully Prepared For Deployment
diff --git a/plugins/devkit/src/dom/Action.java b/plugins/devkit/src/dom/Action.java
index ac879140fd4b..e28f2d13b9b4 100644
--- a/plugins/devkit/src/dom/Action.java
+++ b/plugins/devkit/src/dom/Action.java
@@ -165,4 +165,7 @@ public interface Action extends DomElement {
@NotNull
GenericAttributeValue<String> getKeymap();
+
+ @NotNull
+ GenericAttributeValue<String> getProjectType();
}
diff --git a/plugins/devkit/src/dom/impl/ExtensionDomExtender.java b/plugins/devkit/src/dom/impl/ExtensionDomExtender.java
index f5c83ccb66bc..538ee7e70243 100644
--- a/plugins/devkit/src/dom/impl/ExtensionDomExtender.java
+++ b/plugins/devkit/src/dom/impl/ExtensionDomExtender.java
@@ -15,7 +15,7 @@
*/
package org.jetbrains.idea.devkit.dom.impl;
-import com.intellij.ide.plugins.PluginManager;
+import com.intellij.ide.plugins.PluginManagerCore;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
@@ -50,57 +50,6 @@ import java.util.*;
public class ExtensionDomExtender extends DomExtender<Extensions> {
private static final PsiClassConverter CLASS_CONVERTER = new PluginPsiClassConverter();
private static final Converter LANGUAGE_CONVERTER = new LanguageResolvingConverter();
-
- private static class MyRequired implements Required {
- @Override
- public boolean value() {
- return true;
- }
-
- @Override
- public boolean nonEmpty() {
- return true;
- }
-
- @Override
- public boolean identifier() {
- return false;
- }
-
- @Override
- public Class<? extends Annotation> annotationType() {
- return Required.class;
- }
- }
-
- private static class MyExtendClass extends ExtendClassImpl {
- private final String myInterfaceName;
-
- private MyExtendClass(String interfaceName) {
- myInterfaceName = interfaceName;
- }
-
- @Override
- public boolean allowAbstract() {
- return false;
- }
-
- @Override
- public boolean allowInterface() {
- return false;
- }
-
- @Override
- public boolean allowEnum() {
- return false;
- }
-
- @Override
- public String value() {
- return myInterfaceName;
- }
- }
-
private static final DomExtender EXTENSION_EXTENDER = new DomExtender() {
public void registerExtensions(@NotNull final DomElement domElement, @NotNull final DomExtensionsRegistrar registrar) {
final ExtensionPoint extensionPoint = (ExtensionPoint)domElement.getChildDescription().getDomDeclaration();
@@ -127,31 +76,6 @@ public class ExtensionDomExtender extends DomExtender<Extensions> {
}
};
-
- public void registerExtensions(@NotNull final Extensions extensions, @NotNull final DomExtensionsRegistrar registrar) {
- final XmlElement xmlElement = extensions.getXmlElement();
- if (xmlElement == null) return;
-
- IdeaPlugin ideaPlugin = extensions.getParentOfType(IdeaPlugin.class, true);
-
- if (ideaPlugin == null) return;
-
- String epPrefix = extensions.getEpPrefix();
- for (IdeaPlugin plugin : getVisiblePlugins(ideaPlugin)) {
- final String pluginId = StringUtil.notNullize(plugin.getPluginId(), "com.intellij");
- for (ExtensionPoints points : plugin.getExtensionPoints()) {
- for (ExtensionPoint point : points.getExtensionPoints()) {
- registerExtensionPoint(registrar, point, epPrefix, pluginId);
- }
- }
- }
- }
-
- @Override
- public boolean supportsStubs() {
- return false;
- }
-
private static Set<IdeaPlugin> getVisiblePlugins(IdeaPlugin ideaPlugin) {
Set<IdeaPlugin> result = ContainerUtil.newHashSet();
MultiMap<String, IdeaPlugin> byId = getPluginMap(ideaPlugin.getManager().getProject());
@@ -385,11 +309,10 @@ public class ExtensionDomExtender extends DomExtender<Extensions> {
return PsiTypesUtil.getPsiClass(elementType);
}
-
public static Collection<String> getDependencies(IdeaPlugin ideaPlugin) {
Set<String> result = new HashSet<String>();
- result.add(PluginManager.CORE_PLUGIN_ID);
+ result.add(PluginManagerCore.CORE_PLUGIN_ID);
for (Dependency dependency : ideaPlugin.getDependencies()) {
ContainerUtil.addIfNotNull(dependency.getStringValue(), result);
@@ -422,10 +345,84 @@ public class ExtensionDomExtender extends DomExtender<Extensions> {
return result;
}
+ public void registerExtensions(@NotNull final Extensions extensions, @NotNull final DomExtensionsRegistrar registrar) {
+ final XmlElement xmlElement = extensions.getXmlElement();
+ if (xmlElement == null) return;
+
+ IdeaPlugin ideaPlugin = extensions.getParentOfType(IdeaPlugin.class, true);
+
+ if (ideaPlugin == null) return;
+
+ String epPrefix = extensions.getEpPrefix();
+ for (IdeaPlugin plugin : getVisiblePlugins(ideaPlugin)) {
+ final String pluginId = StringUtil.notNullize(plugin.getPluginId(), "com.intellij");
+ for (ExtensionPoints points : plugin.getExtensionPoints()) {
+ for (ExtensionPoint point : points.getExtensionPoints()) {
+ registerExtensionPoint(registrar, point, epPrefix, pluginId);
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean supportsStubs() {
+ return false;
+ }
+
interface SimpleTagValue extends DomElement {
@SuppressWarnings("UnusedDeclaration")
@TagValue
String getTagValue();
}
+ private static class MyRequired implements Required {
+ @Override
+ public boolean value() {
+ return true;
+ }
+
+ @Override
+ public boolean nonEmpty() {
+ return true;
+ }
+
+ @Override
+ public boolean identifier() {
+ return false;
+ }
+
+ @Override
+ public Class<? extends Annotation> annotationType() {
+ return Required.class;
+ }
+ }
+
+ private static class MyExtendClass extends ExtendClassImpl {
+ private final String myInterfaceName;
+
+ private MyExtendClass(String interfaceName) {
+ myInterfaceName = interfaceName;
+ }
+
+ @Override
+ public boolean allowAbstract() {
+ return false;
+ }
+
+ @Override
+ public boolean allowInterface() {
+ return false;
+ }
+
+ @Override
+ public boolean allowEnum() {
+ return false;
+ }
+
+ @Override
+ public String value() {
+ return myInterfaceName;
+ }
+ }
+
}
diff --git a/plugins/devkit/src/dom/impl/PluginXmlDomFileDescription.java b/plugins/devkit/src/dom/impl/PluginXmlDomFileDescription.java
index b3d7fda2c19a..091c172d0a60 100644
--- a/plugins/devkit/src/dom/impl/PluginXmlDomFileDescription.java
+++ b/plugins/devkit/src/dom/impl/PluginXmlDomFileDescription.java
@@ -15,109 +15,18 @@
*/
package org.jetbrains.idea.devkit.dom.impl;
-import com.intellij.codeInspection.ProblemHighlightType;
import com.intellij.icons.AllIcons;
-import com.intellij.lang.annotation.Annotation;
-import com.intellij.lang.annotation.HighlightSeverity;
import com.intellij.openapi.util.Iconable;
-import com.intellij.psi.PsiClass;
-import com.intellij.psi.PsiElement;
-import com.intellij.psi.PsiField;
-import com.intellij.util.xml.DomElement;
import com.intellij.util.xml.DomFileDescription;
-import com.intellij.util.xml.DomUtil;
-import com.intellij.util.xml.GenericAttributeValue;
-import com.intellij.util.xml.highlighting.DomElementAnnotationHolder;
-import com.intellij.util.xml.highlighting.DomElementsAnnotator;
-import com.intellij.util.xml.reflect.DomAttributeChildDescription;
-import org.jetbrains.annotations.Nullable;
-import org.jetbrains.idea.devkit.dom.*;
+import org.jetbrains.idea.devkit.dom.IdeaPlugin;
import javax.swing.*;
-import java.util.List;
/**
* @author mike
*/
public class PluginXmlDomFileDescription extends DomFileDescription<IdeaPlugin> {
- private static final DomElementsAnnotator ANNOTATOR = new DomElementsAnnotator() {
- @Override
- public void annotate(DomElement element, DomElementAnnotationHolder holder) {
- if (element instanceof Extension) {
- annotateExtension((Extension)element, holder);
- }
- else if (element instanceof Vendor) {
- annotateVendor((Vendor)element, holder);
- }
- else if (element instanceof IdeaVersion) {
- annotateIdeaVersion((IdeaVersion)element, holder);
- }
- else if (element instanceof Extensions) {
- annotateExtensions((Extensions)element, holder);
- }
- }
-
- private void annotateExtensions(Extensions extensions, DomElementAnnotationHolder holder) {
- final GenericAttributeValue<IdeaPlugin> xmlnsAttribute = extensions.getXmlns();
- if (!DomUtil.hasXml(xmlnsAttribute)) return;
-
- final Annotation annotation = holder.createAnnotation(xmlnsAttribute,
- HighlightSeverity.WARNING,
- "Use defaultExtensionNs instead");
- annotation.setHighlightType(ProblemHighlightType.LIKE_DEPRECATED);
- }
-
- private void annotateIdeaVersion(IdeaVersion ideaVersion, DomElementAnnotationHolder holder) {
- highlightNotUsedAnymore(ideaVersion.getMin(), holder);
- highlightNotUsedAnymore(ideaVersion.getMax(), holder);
- }
-
- private void annotateExtension(Extension extension, DomElementAnnotationHolder holder) {
- final ExtensionPoint extensionPoint = extension.getExtensionPoint();
- if (extensionPoint == null) return;
- final GenericAttributeValue<PsiClass> interfaceAttribute = extensionPoint.getInterface();
- if (DomUtil.hasXml(interfaceAttribute)) {
- final PsiClass value = interfaceAttribute.getValue();
- if (value != null && value.isDeprecated()) {
- final Annotation annotation = holder.createAnnotation(extension, HighlightSeverity.WARNING, "Deprecated EP");
- annotation.setHighlightType(ProblemHighlightType.LIKE_DEPRECATED);
- return;
- }
- }
-
- final List<? extends DomAttributeChildDescription> descriptions = extension.getGenericInfo().getAttributeChildrenDescriptions();
- for (DomAttributeChildDescription attributeDescription : descriptions) {
- final GenericAttributeValue attributeValue = attributeDescription.getDomAttributeValue(extension);
- if (attributeValue == null || !DomUtil.hasXml(attributeValue)) continue;
-
- final PsiElement declaration = attributeDescription.getDeclaration(extension.getManager().getProject());
- if (declaration instanceof PsiField) {
- PsiField psiField = (PsiField)declaration;
- if (psiField.isDeprecated()) {
- final Annotation annotation = holder.createAnnotation(attributeValue, HighlightSeverity.WARNING,
- "Deprecated attribute '" + attributeDescription.getName() + "'");
- annotation.setHighlightType(ProblemHighlightType.LIKE_DEPRECATED);
- }
- }
- }
- }
-
- private void annotateVendor(Vendor vendor, DomElementAnnotationHolder holder) {
- highlightNotUsedAnymore(vendor.getLogo(), holder);
- }
-
- private void highlightNotUsedAnymore(GenericAttributeValue attributeValue,
- DomElementAnnotationHolder holder) {
- if (!DomUtil.hasXml(attributeValue)) return;
-
- final Annotation annotation = holder.createAnnotation(attributeValue,
- HighlightSeverity.WARNING,
- "Not used anymore");
- annotation.setHighlightType(ProblemHighlightType.LIKE_DEPRECATED);
- }
- };
-
public PluginXmlDomFileDescription() {
super(IdeaPlugin.class, "idea-plugin");
}
@@ -127,12 +36,6 @@ public class PluginXmlDomFileDescription extends DomFileDescription<IdeaPlugin>
return AllIcons.Nodes.Plugin;
}
- @Nullable
- @Override
- public DomElementsAnnotator createAnnotator() {
- return ANNOTATOR;
- }
-
@Override
public boolean hasStubs() {
return true;
diff --git a/plugins/devkit/src/inspections/PluginXmlDomInspection.java b/plugins/devkit/src/inspections/PluginXmlDomInspection.java
index b160cbf5dbd1..af691d283e0e 100644
--- a/plugins/devkit/src/inspections/PluginXmlDomInspection.java
+++ b/plugins/devkit/src/inspections/PluginXmlDomInspection.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,12 +15,28 @@
*/
package org.jetbrains.idea.devkit.inspections;
+import com.intellij.codeInspection.ProblemHighlightType;
+import com.intellij.openapi.module.Module;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiField;
+import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.xml.DomElement;
+import com.intellij.util.xml.DomUtil;
+import com.intellij.util.xml.GenericAttributeValue;
import com.intellij.util.xml.highlighting.BasicDomElementsInspection;
+import com.intellij.util.xml.highlighting.DomElementAnnotationHolder;
+import com.intellij.util.xml.highlighting.DomHighlightingHelper;
+import com.intellij.util.xml.highlighting.RemoveDomElementQuickFix;
+import com.intellij.util.xml.reflect.DomAttributeChildDescription;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.devkit.DevKitBundle;
-import org.jetbrains.idea.devkit.dom.IdeaPlugin;
+import org.jetbrains.idea.devkit.dom.*;
+import org.jetbrains.idea.devkit.util.PsiUtil;
+
+import java.util.List;
/**
* @author mike
@@ -47,4 +63,110 @@ public class PluginXmlDomInspection extends BasicDomElementsInspection<IdeaPlugi
public String getShortName() {
return "PluginXmlValidity";
}
+
+ @Override
+ protected void checkDomElement(DomElement element, DomElementAnnotationHolder holder, DomHighlightingHelper helper) {
+ super.checkDomElement(element, holder, helper);
+
+ if (element instanceof IdeaPlugin) {
+ checkJetBrainsPlugin((IdeaPlugin)element, holder);
+ }
+ else if (element instanceof Extension) {
+ annotateExtension((Extension)element, holder);
+ }
+ else if (element instanceof Vendor) {
+ annotateVendor((Vendor)element, holder);
+ }
+ else if (element instanceof IdeaVersion) {
+ annotateIdeaVersion((IdeaVersion)element, holder);
+ }
+ else if (element instanceof Extensions) {
+ annotateExtensions((Extensions)element, holder);
+ }
+ }
+
+ private static void checkJetBrainsPlugin(IdeaPlugin ideaPlugin, DomElementAnnotationHolder holder) {
+ final Module module = ideaPlugin.getModule();
+ if (module == null) return;
+ if (!PsiUtil.isIdeaProject(module.getProject())) return;
+
+ if (ideaPlugin.getPluginId() == null) return;
+
+ final Vendor vendor = ContainerUtil.getFirstItem(ideaPlugin.getVendors());
+ if (vendor == null) return;
+ if (!"JetBrains".equals(vendor.getValue())) return;
+
+ for (Extensions extensions : ideaPlugin.getExtensions()) {
+ final List<Extension> definedEps = DomUtil.getDefinedChildrenOfType(extensions, Extension.class, true, false);
+ for (Extension extension : definedEps) {
+ final ExtensionPoint extensionPoint = extension.getExtensionPoint();
+ if (extensionPoint == null) continue;
+ if ("com.intellij.errorHandler".equals(extensionPoint.getEffectiveQualifiedName())) {
+ return;
+ }
+ }
+ }
+
+ holder.createProblem(DomUtil.getFileElement(ideaPlugin),
+ "JetBrains plugin should provide <errorHandler>");
+ }
+
+ private static void annotateExtensions(Extensions extensions, DomElementAnnotationHolder holder) {
+ final GenericAttributeValue<IdeaPlugin> xmlnsAttribute = extensions.getXmlns();
+ if (!DomUtil.hasXml(xmlnsAttribute)) return;
+
+ holder.createProblem(xmlnsAttribute,
+ ProblemHighlightType.LIKE_DEPRECATED,
+ "Use defaultExtensionNs instead", null).highlightWholeElement();
+ }
+
+ private static void annotateIdeaVersion(IdeaVersion ideaVersion, DomElementAnnotationHolder holder) {
+ highlightNotUsedAnymore(ideaVersion.getMin(), holder);
+ highlightNotUsedAnymore(ideaVersion.getMax(), holder);
+ }
+
+ private static void annotateExtension(Extension extension, DomElementAnnotationHolder holder) {
+ final ExtensionPoint extensionPoint = extension.getExtensionPoint();
+ if (extensionPoint == null) return;
+ final GenericAttributeValue<PsiClass> interfaceAttribute = extensionPoint.getInterface();
+ if (DomUtil.hasXml(interfaceAttribute)) {
+ final PsiClass value = interfaceAttribute.getValue();
+ if (value != null && value.isDeprecated()) {
+ holder.createProblem(extension, ProblemHighlightType.LIKE_DEPRECATED, "Deprecated EP", null);
+ return;
+ }
+ }
+
+ final List<? extends DomAttributeChildDescription> descriptions = extension.getGenericInfo().getAttributeChildrenDescriptions();
+ for (DomAttributeChildDescription attributeDescription : descriptions) {
+ final GenericAttributeValue attributeValue = attributeDescription.getDomAttributeValue(extension);
+ if (attributeValue == null || !DomUtil.hasXml(attributeValue)) continue;
+
+ final PsiElement declaration = attributeDescription.getDeclaration(extension.getManager().getProject());
+ if (declaration instanceof PsiField) {
+ PsiField psiField = (PsiField)declaration;
+ if (psiField.isDeprecated()) {
+ holder.createProblem(attributeValue, ProblemHighlightType.LIKE_DEPRECATED,
+ "Deprecated attribute '" + attributeDescription.getName() + "'",
+ null)
+ .highlightWholeElement();
+ }
+ }
+ }
+ }
+
+ private static void annotateVendor(Vendor vendor, DomElementAnnotationHolder holder) {
+ highlightNotUsedAnymore(vendor.getLogo(), holder);
+ }
+
+ private static void highlightNotUsedAnymore(GenericAttributeValue attributeValue,
+ DomElementAnnotationHolder holder) {
+ if (!DomUtil.hasXml(attributeValue)) return;
+
+ holder.createProblem(attributeValue,
+ ProblemHighlightType.LIKE_DEPRECATED,
+ "Not used anymore",
+ null, new RemoveDomElementQuickFix(attributeValue))
+ .highlightWholeElement();
+ }
}
diff --git a/plugins/devkit/src/navigation/DescriptionTypeRelatedItemLineMarkerProvider.java b/plugins/devkit/src/navigation/DescriptionTypeRelatedItemLineMarkerProvider.java
index 1d759b6a8669..a5c4fba2db15 100644
--- a/plugins/devkit/src/navigation/DescriptionTypeRelatedItemLineMarkerProvider.java
+++ b/plugins/devkit/src/navigation/DescriptionTypeRelatedItemLineMarkerProvider.java
@@ -16,7 +16,6 @@
package org.jetbrains.idea.devkit.navigation;
import com.intellij.codeInsight.daemon.RelatedItemLineMarkerInfo;
-import com.intellij.codeInsight.daemon.RelatedItemLineMarkerProvider;
import com.intellij.codeInsight.navigation.NavigationGutterIconBuilder;
import com.intellij.icons.AllIcons;
import com.intellij.navigation.GotoRelatedItem;
@@ -24,8 +23,10 @@ import com.intellij.openapi.editor.markup.GutterIconRenderer;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.psi.*;
-import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiDirectory;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.util.NotNullFunction;
import com.intellij.util.containers.ContainerUtil;
@@ -41,7 +42,7 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.List;
-public class DescriptionTypeRelatedItemLineMarkerProvider extends RelatedItemLineMarkerProvider {
+public class DescriptionTypeRelatedItemLineMarkerProvider extends DevkitRelatedLineMarkerProviderBase {
private static final NotNullFunction<PsiFile, Collection<? extends PsiElement>> CONVERTER =
new NotNullFunction<PsiFile, Collection<? extends PsiElement>>() {
@@ -74,11 +75,6 @@ public class DescriptionTypeRelatedItemLineMarkerProvider extends RelatedItemLin
Module module = ModuleUtilCore.findModuleForPsiElement(psiClass);
if (module == null) return;
- final GlobalSearchScope scope = GlobalSearchScope.moduleRuntimeScope(module, false);
- final PsiClass actionClass = JavaPsiFacade.getInstance(psiClass.getProject())
- .findClass(DescriptionType.INSPECTION.getClassName(), scope);
- if (actionClass == null) return;
-
PsiElement highlightingElement = psiClass.getNameIdentifier();
if (highlightingElement == null) return;
diff --git a/plugins/devkit/src/navigation/DevkitRelatedLineMarkerProviderBase.java b/plugins/devkit/src/navigation/DevkitRelatedLineMarkerProviderBase.java
new file mode 100644
index 000000000000..e81c38ec6936
--- /dev/null
+++ b/plugins/devkit/src/navigation/DevkitRelatedLineMarkerProviderBase.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.idea.devkit.navigation;
+
+import com.intellij.codeInsight.daemon.RelatedItemLineMarkerInfo;
+import com.intellij.codeInsight.daemon.RelatedItemLineMarkerProvider;
+import com.intellij.psi.PsiElement;
+import com.intellij.util.containers.ContainerUtil;
+import org.jetbrains.idea.devkit.util.PsiUtil;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Do not process when current project is not a Plugin project.
+ */
+public abstract class DevkitRelatedLineMarkerProviderBase extends RelatedItemLineMarkerProvider {
+
+ @Override
+ public void collectNavigationMarkers(List<PsiElement> elements,
+ Collection<? super RelatedItemLineMarkerInfo> result,
+ boolean forNavigation) {
+ final PsiElement psiElement = ContainerUtil.getFirstItem(elements);
+ if (psiElement == null ||
+ !PsiUtil.isPluginProject(psiElement.getProject())) {
+ return;
+ }
+
+ super.collectNavigationMarkers(elements, result, forNavigation);
+ }
+}
diff --git a/plugins/devkit/src/navigation/ExtensionPointDeclarationRelatedItemLineMarkerProvider.java b/plugins/devkit/src/navigation/ExtensionPointDeclarationRelatedItemLineMarkerProvider.java
index 8ecdbac61291..d71b54a540f6 100644
--- a/plugins/devkit/src/navigation/ExtensionPointDeclarationRelatedItemLineMarkerProvider.java
+++ b/plugins/devkit/src/navigation/ExtensionPointDeclarationRelatedItemLineMarkerProvider.java
@@ -16,7 +16,6 @@
package org.jetbrains.idea.devkit.navigation;
import com.intellij.codeInsight.daemon.RelatedItemLineMarkerInfo;
-import com.intellij.codeInsight.daemon.RelatedItemLineMarkerProvider;
import com.intellij.codeInsight.navigation.NavigationGutterIconBuilder;
import com.intellij.icons.AllIcons;
import com.intellij.navigation.GotoRelatedItem;
@@ -37,7 +36,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
-public class ExtensionPointDeclarationRelatedItemLineMarkerProvider extends RelatedItemLineMarkerProvider {
+public class ExtensionPointDeclarationRelatedItemLineMarkerProvider extends DevkitRelatedLineMarkerProviderBase {
private static final NotNullFunction<ExtensionPointCandidate, Collection<? extends PsiElement>> CONVERTER =
new NotNullFunction<ExtensionPointCandidate, Collection<? extends PsiElement>>() {
diff --git a/plugins/devkit/src/projectRoots/IdeaJdk.java b/plugins/devkit/src/projectRoots/IdeaJdk.java
index 1539a893dbad..a5fabf928c5d 100644
--- a/plugins/devkit/src/projectRoots/IdeaJdk.java
+++ b/plugins/devkit/src/projectRoots/IdeaJdk.java
@@ -86,6 +86,15 @@ public class IdeaJdk extends JavaDependentSdkType implements JavaSdkType {
return PathManager.getHomePath().replace(File.separatorChar, '/');
}
+ @Override
+ public String adjustSelectedSdkHome(String homePath) {
+ if (SystemInfo.isMac) {
+ File home = new File(homePath, "Contents");
+ if (home.exists()) return home.getPath();
+ }
+ return super.adjustSelectedSdkHome(homePath);
+ }
+
public boolean isValidSdkHome(String path) {
if (isFromIDEAProject(path)) {
return true;
@@ -153,6 +162,9 @@ public class IdeaJdk extends JavaDependentSdkType implements JavaSdkType {
else if (new File(sdkHome, "license/AppCode_license.txt").exists()) {
productName = "AppCode ";
}
+ else if (new File(sdkHome, "license/CLion_Preview_License.txt").exists()) {
+ productName = "CLion ";
+ }
else {
productName = "IDEA ";
}
diff --git a/plugins/devkit/src/run/PluginRunConfigurationEditor.java b/plugins/devkit/src/run/PluginRunConfigurationEditor.java
index f65bd28a8fc4..9749d3adca18 100644
--- a/plugins/devkit/src/run/PluginRunConfigurationEditor.java
+++ b/plugins/devkit/src/run/PluginRunConfigurationEditor.java
@@ -15,6 +15,7 @@
*/
package org.jetbrains.idea.devkit.run;
+import com.intellij.application.options.ModulesComboBox;
import com.intellij.execution.ExecutionBundle;
import com.intellij.execution.configurations.LogFileOptions;
import com.intellij.execution.ui.AlternativeJREPanel;
@@ -24,7 +25,6 @@ import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.SettingsEditor;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.ModuleRootManager;
-import com.intellij.application.options.ModulesComboBox;
import com.intellij.openapi.ui.LabeledComponent;
import com.intellij.ui.PanelWithAnchor;
import com.intellij.ui.RawCommandLineEditor;
@@ -46,7 +46,6 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
-import java.util.ArrayList;
public class PluginRunConfigurationEditor extends SettingsEditor<PluginRunConfiguration> implements PanelWithAnchor {
private final ModulesComboBox myModules = new ModulesComboBox();
@@ -54,7 +53,7 @@ public class PluginRunConfigurationEditor extends SettingsEditor<PluginRunConfig
private final LabeledComponent<RawCommandLineEditor> myVMParameters = new LabeledComponent<RawCommandLineEditor>();
private final LabeledComponent<RawCommandLineEditor> myProgramParameters = new LabeledComponent<RawCommandLineEditor>();
private JComponent anchor;
- private AlternativeJREPanel myAlternativeJREPanel = new AlternativeJREPanel();
+ private final AlternativeJREPanel myAlternativeJREPanel = new AlternativeJREPanel();
@NonNls private final JCheckBox myShowLogs = new JCheckBox(DevKitBundle.message("show.smth", "idea.log"));
@@ -65,12 +64,14 @@ public class PluginRunConfigurationEditor extends SettingsEditor<PluginRunConfig
myPRC = prc;
myShowLogs.setSelected(isShow(prc));
myShowLogs.addChangeListener(new ChangeListener() {
- public void stateChanged(ChangeEvent e) {
+ @Override
+ public void stateChanged(@NotNull ChangeEvent e) {
setShow(prc, myShowLogs.isSelected());
}
});
myModules.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
+ @Override
+ public void actionPerformed(@NotNull ActionEvent e) {
final Module selectedModule = myModules.getSelectedModule();
if (selectedModule != null){
prc.removeAllLogFiles();
@@ -113,20 +114,19 @@ public class PluginRunConfigurationEditor extends SettingsEditor<PluginRunConfig
}
private static void setShow(PluginRunConfiguration prc, boolean show){
- final ArrayList<LogFileOptions> logFiles = prc.getLogFiles();
- for (LogFileOptions logFile: logFiles) {
+ for (LogFileOptions logFile: prc.getLogFiles()) {
logFile.setEnable(show);
}
}
private static boolean isShow(PluginRunConfiguration prc){
- final ArrayList<LogFileOptions> logFiles = prc.getLogFiles();
- for (LogFileOptions logFile : logFiles) {
+ for (LogFileOptions logFile : prc.getLogFiles()) {
if (logFile.isEnabled()) return true;
}
return false;
}
+ @Override
public void resetEditorFrom(PluginRunConfiguration prc) {
myModules.setSelectedModule(prc.getModule());
getVMParameters().setText(prc.VM_PARAMETERS);
@@ -135,6 +135,7 @@ public class PluginRunConfigurationEditor extends SettingsEditor<PluginRunConfig
}
+ @Override
public void applyEditorTo(PluginRunConfiguration prc) throws ConfigurationException {
prc.setModule(myModules.getSelectedModule());
prc.VM_PARAMETERS = getVMParameters().getText();
@@ -143,6 +144,7 @@ public class PluginRunConfigurationEditor extends SettingsEditor<PluginRunConfig
prc.setAlternativeJreEnabled(myAlternativeJREPanel.isPathEnabled());
}
+ @Override
@NotNull
public JComponent createEditor() {
myModules.fillModules(myPRC.getProject(), PluginModuleType.getInstance());
diff --git a/plugins/devkit/src/testAssistant/NavigateToTestDataAction.java b/plugins/devkit/src/testAssistant/NavigateToTestDataAction.java
index 89e10e019632..2bcebc807d4e 100644
--- a/plugins/devkit/src/testAssistant/NavigateToTestDataAction.java
+++ b/plugins/devkit/src/testAssistant/NavigateToTestDataAction.java
@@ -19,6 +19,7 @@ import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.execution.Location;
import com.intellij.execution.junit.JUnitUtil;
import com.intellij.execution.junit2.PsiMemberParameterizedLocation;
+import com.intellij.execution.testframework.TestTreeViewAction;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications;
@@ -45,7 +46,7 @@ import java.util.List;
/**
* @author yole
*/
-public class NavigateToTestDataAction extends AnAction {
+public class NavigateToTestDataAction extends AnAction implements TestTreeViewAction {
@Override
public void actionPerformed(AnActionEvent e) {
final DataContext dataContext = e.getDataContext();
diff --git a/plugins/devkit/src/testAssistant/TestDataLineMarkerProvider.java b/plugins/devkit/src/testAssistant/TestDataLineMarkerProvider.java
index 73f0ae40d4a2..60d805044f0c 100644
--- a/plugins/devkit/src/testAssistant/TestDataLineMarkerProvider.java
+++ b/plugins/devkit/src/testAssistant/TestDataLineMarkerProvider.java
@@ -34,6 +34,7 @@ import com.intellij.util.Function;
import com.intellij.util.PlatformIcons;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import org.jetbrains.idea.devkit.util.PsiUtil;
import java.awt.event.MouseEvent;
import java.io.File;
@@ -53,6 +54,16 @@ public class TestDataLineMarkerProvider implements LineMarkerProvider {
if (ApplicationManager.getApplication().isUnitTestMode()) {
return null;
}
+
+ if (!(element instanceof PsiMethod) &&
+ !(element instanceof PsiClass)) {
+ return null;
+ }
+
+ if (!PsiUtil.isPluginProject(element.getProject())) {
+ return null;
+ }
+
final VirtualFile file = PsiUtilCore.getVirtualFile(element);
if (file == null || !ProjectFileIndex.SERVICE.getInstance(element.getProject()).isInTestSourceContent(file)) {
return null;
@@ -64,7 +75,7 @@ public class TestDataLineMarkerProvider implements LineMarkerProvider {
method, method.getModifierList().getTextRange(), PlatformIcons.TEST_SOURCE_FOLDER, Pass.UPDATE_ALL, null, new TestDataNavigationHandler(),
GutterIconRenderer.Alignment.LEFT);
}
- } else if (element instanceof PsiClass) {
+ } else {
final PsiClass psiClass = (PsiClass)element;
final String basePath = getTestDataBasePath(psiClass);
if (basePath != null) {
@@ -115,7 +126,8 @@ public class TestDataLineMarkerProvider implements LineMarkerProvider {
@Nullable
public static String getTestDataBasePath(PsiClass psiClass) {
final PsiAnnotation annotation = AnnotationUtil.findAnnotationInHierarchy(psiClass,
- Collections.singleton(TEST_DATA_PATH_ANNOTATION_QUALIFIED_NAME));
+ Collections.singleton(
+ TEST_DATA_PATH_ANNOTATION_QUALIFIED_NAME));
if (annotation != null) {
final PsiAnnotationMemberValue value = annotation.findAttributeValue(PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME);
if (value instanceof PsiExpression) {
diff --git a/plugins/devkit/src/testAssistant/TestLocationDataRule.java b/plugins/devkit/src/testAssistant/TestLocationDataRule.java
index 6dccd0f808da..74c9d34c5a96 100644
--- a/plugins/devkit/src/testAssistant/TestLocationDataRule.java
+++ b/plugins/devkit/src/testAssistant/TestLocationDataRule.java
@@ -23,6 +23,7 @@ import com.intellij.execution.junit2.info.MethodLocation;
import com.intellij.ide.impl.dataRules.GetDataRule;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataProvider;
+import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.ProjectRootManager;
@@ -58,6 +59,8 @@ public class TestLocationDataRule implements GetDataRule {
@NotNull
protected static List<Location> collectRelativeLocations(Project project, VirtualFile file) {
+ if (DumbService.isDumb(project)) return Collections.emptyList();
+
final List<Location> locations = new ArrayList<Location>();
final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(project).getFileIndex();
if (fileIndex.isInContent(file) && !fileIndex.isInSource(file) && !fileIndex.isInLibraryClasses(file)) {
diff --git a/plugins/devkit/src/util/PsiUtil.java b/plugins/devkit/src/util/PsiUtil.java
index 8d093acb8017..2be3719c214a 100644
--- a/plugins/devkit/src/util/PsiUtil.java
+++ b/plugins/devkit/src/util/PsiUtil.java
@@ -125,6 +125,11 @@ public class PsiUtil {
return flag;
}
+ public static boolean isPluginProject(Project project) {
+ return JavaPsiFacade.getInstance(project).findClass(IDE_PROJECT_MARKER_CLASS,
+ GlobalSearchScope.allScope(project)) != null;
+ }
+
private static boolean isIntelliJBasedDir(VirtualFile baseDir) {
if (baseDir == null) {
return false;
diff --git a/plugins/devkit/testData/codeInsight/ExtensionsHighlighting.xml b/plugins/devkit/testData/codeInsight/ExtensionsHighlighting.xml
index 9486bf492542..d0e7a9b31296 100644
--- a/plugins/devkit/testData/codeInsight/ExtensionsHighlighting.xml
+++ b/plugins/devkit/testData/codeInsight/ExtensionsHighlighting.xml
@@ -14,7 +14,7 @@
<myPlugin.ext implementation="<error descr="'java.util.concurrent.TimeUnit' is not assignable to 'java.lang.Runnable'"><error descr="Enum is not allowed">java.util.concurrent.TimeUnit</error></error>"/>
<myPlugin.ext implementation="<error descr="'java.lang.String' is not assignable to 'java.lang.Runnable'">java.lang.String</error>"/>
- <warning descr="Deprecated EP" textAttributesKey="DEPRECATED_ATTRIBUTES"><myPlugin.deprecatedEP implementation="foo.MyDeprecatedEPImpl"/></warning>
+ <<error descr="Deprecated EP">myPlugin.deprecatedEP</error> implementation="foo.MyDeprecatedEPImpl"/>
<myPlugin.foo.bar/>
<completion.contributor/>
diff --git a/plugins/devkit/testData/codeInsight/deprecatedAttributes.xml b/plugins/devkit/testData/codeInsight/deprecatedAttributes.xml
index d77d1c0732df..e9f52b6242e4 100644
--- a/plugins/devkit/testData/codeInsight/deprecatedAttributes.xml
+++ b/plugins/devkit/testData/codeInsight/deprecatedAttributes.xml
@@ -1,13 +1,13 @@
<idea-plugin>
<id>com.intellij.myPlugin</id>
- <vendor <warning descr="Not used anymore">logo="deprecated"</warning>/>
+ <vendor <error descr="Not used anymore">logo="deprecated"</error>/>
<idea-version since-build="133"
- <warning descr="Not used anymore">min="deprecated"</warning>
- <warning descr="Not used anymore">max="deprecated"</warning>
+ <error descr="Not used anymore">min="deprecated"</error>
+ <error descr="Not used anymore">max="deprecated"</error>
/>
- <extensions <warning descr="Use defaultExtensionNs instead">xmlns="<error descr="URI is not registered (Settings | Project Settings | Schemas and DTDs)">com.intellij</error>"</warning>/>
+ <extensions <error descr="Use defaultExtensionNs instead">xmlns="<error descr="URI is not registered (Settings | Project Settings | Schemas and DTDs)">com.intellij</error>"</error>/>
</idea-plugin> \ No newline at end of file
diff --git a/plugins/devkit/testData/codeInsight/deprecatedExtensionAttribute.xml b/plugins/devkit/testData/codeInsight/deprecatedExtensionAttribute.xml
index 5466b7ee4485..0400e73a0d02 100644
--- a/plugins/devkit/testData/codeInsight/deprecatedExtensionAttribute.xml
+++ b/plugins/devkit/testData/codeInsight/deprecatedExtensionAttribute.xml
@@ -6,7 +6,7 @@
</extensionPoints>
<extensions defaultExtensionNs="com.intellij.myPlugin">
- <myExt <warning descr="Deprecated attribute 'old'">old="java.lang.Runnable"</warning> attr="value"/>
+ <myExt <error descr="Deprecated attribute 'old'">old="java.lang.Runnable"</error> attr="value"/>
</extensions>
</idea-plugin> \ No newline at end of file
diff --git a/plugins/devkit/testData/pluginXmlDomStubs/pluginWithXInclude-extensionPoints.xml b/plugins/devkit/testData/pluginXmlDomStubs/pluginWithXInclude-extensionPoints.xml
new file mode 100644
index 000000000000..813122a13176
--- /dev/null
+++ b/plugins/devkit/testData/pluginXmlDomStubs/pluginWithXInclude-extensionPoints.xml
@@ -0,0 +1,5 @@
+<idea-plugin>
+<extensionPoints>
+ <extensionPoint name="extension" beanClass="foo.Bar"/>
+</extensionPoints>
+</idea-plugin> \ No newline at end of file
diff --git a/plugins/devkit/testData/pluginXmlDomStubs/pluginWithXInclude-main.xml b/plugins/devkit/testData/pluginXmlDomStubs/pluginWithXInclude-main.xml
new file mode 100644
index 000000000000..280b9b93c555
--- /dev/null
+++ b/plugins/devkit/testData/pluginXmlDomStubs/pluginWithXInclude-main.xml
@@ -0,0 +1,10 @@
+<idea-plugin xmlns:xi="http://www.w3.org/2001/XInclude" version="2">
+
+ <id>com.intellij</id>
+
+ <extensionPoints>
+ <extensionPoint name="bar"/>
+ <xi:include href="/extensionPoints.xml" xpointer="xpointer(/extensionPoints/*)"/>
+ </extensionPoints>
+
+</idea-plugin> \ No newline at end of file
diff --git a/plugins/devkit/testData/pluginXmlDomStubs/pluginWithXInclude.xml b/plugins/devkit/testData/pluginXmlDomStubs/pluginWithXInclude.xml
new file mode 100644
index 000000000000..849086d4989f
--- /dev/null
+++ b/plugins/devkit/testData/pluginXmlDomStubs/pluginWithXInclude.xml
@@ -0,0 +1,15 @@
+<idea-plugin version="2">
+
+ <id>foo</id>
+
+ <extensionPoints>
+ <extensionPoint name="bar"/>
+ </extensionPoints>
+
+ <extensions defaultExtensionNs="foo">
+
+ <bar/>
+ <extension/>
+ </extensions>
+
+</idea-plugin> \ No newline at end of file
diff --git a/plugins/devkit/testSources/codeInsight/PluginXmlDomStubsTest.java b/plugins/devkit/testSources/codeInsight/PluginXmlDomStubsTest.java
index 685d926b1b2a..100b956bdb4c 100644
--- a/plugins/devkit/testSources/codeInsight/PluginXmlDomStubsTest.java
+++ b/plugins/devkit/testSources/codeInsight/PluginXmlDomStubsTest.java
@@ -44,6 +44,13 @@ public class PluginXmlDomStubsTest extends DomStubTest {
);
}
+ public void testXInclude() throws Exception {
+ prepareFile("pluginWithXInclude-extensionPoints.xml");
+ prepareFile("pluginWithXInclude-main.xml");
+ prepareFile("pluginWithXInclude.xml");
+ myFixture.testHighlighting("pluginWithXInclude.xml");
+ }
+
@Override
protected String getBasePath() {
return PluginPathManager.getPluginHomePathRelative("devkit") + "/testData/pluginXmlDomStubs";
diff --git a/plugins/devkit/testSources/navigation/DescriptionTypeRelatedItemLineMarkerProviderTest.java b/plugins/devkit/testSources/navigation/DescriptionTypeRelatedItemLineMarkerProviderTest.java
index f42a62993db9..c885d0a09212 100644
--- a/plugins/devkit/testSources/navigation/DescriptionTypeRelatedItemLineMarkerProviderTest.java
+++ b/plugins/devkit/testSources/navigation/DescriptionTypeRelatedItemLineMarkerProviderTest.java
@@ -22,6 +22,7 @@ import com.intellij.openapi.application.PluginPathManager;
import com.intellij.testFramework.TestDataPath;
import com.intellij.testFramework.builders.JavaModuleFixtureBuilder;
import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase;
+import com.intellij.ui.components.JBList;
import com.intellij.util.PathUtil;
import java.util.Collection;
@@ -39,6 +40,8 @@ public class DescriptionTypeRelatedItemLineMarkerProviderTest extends JavaCodeIn
protected void tuneFixture(JavaModuleFixtureBuilder moduleBuilder) throws Exception {
String pathForClass = PathUtil.getJarPathForClass(LocalInspectionEP.class);
moduleBuilder.addLibrary("lang-api", pathForClass);
+ String platformApiJar = PathUtil.getJarPathForClass(JBList.class);
+ moduleBuilder.addLibrary("platform-api", platformApiJar);
}
public void testInspectionDescription() {
diff --git a/plugins/devkit/testSources/navigation/ExtensionPointDeclarationRelatedItemLineMarkerProviderTest.java b/plugins/devkit/testSources/navigation/ExtensionPointDeclarationRelatedItemLineMarkerProviderTest.java
index 220c1959fd36..6b21d8455152 100644
--- a/plugins/devkit/testSources/navigation/ExtensionPointDeclarationRelatedItemLineMarkerProviderTest.java
+++ b/plugins/devkit/testSources/navigation/ExtensionPointDeclarationRelatedItemLineMarkerProviderTest.java
@@ -22,6 +22,7 @@ import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.testFramework.TestDataPath;
import com.intellij.testFramework.builders.JavaModuleFixtureBuilder;
import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase;
+import com.intellij.ui.components.JBList;
import com.intellij.util.PathUtil;
@TestDataPath("$CONTENT_ROOT/testData/navigation/extensionPointDeclaration")
@@ -34,8 +35,10 @@ public class ExtensionPointDeclarationRelatedItemLineMarkerProviderTest extends
@Override
protected void tuneFixture(JavaModuleFixtureBuilder moduleBuilder) throws Exception {
- String pathForClass = PathUtil.getJarPathForClass(ExtensionPointName.class);
- moduleBuilder.addLibrary("extensions", pathForClass);
+ String extensionsJar = PathUtil.getJarPathForClass(ExtensionPointName.class);
+ moduleBuilder.addLibrary("extensions", extensionsJar);
+ String platformApiJar = PathUtil.getJarPathForClass(JBList.class);
+ moduleBuilder.addLibrary("platform-api", platformApiJar);
}
public void testMyStringEP() {
diff --git a/plugins/git4idea/git4idea.iml b/plugins/git4idea/git4idea.iml
index 53ee70f60eca..c109bd529797 100644
--- a/plugins/git4idea/git4idea.iml
+++ b/plugins/git4idea/git4idea.iml
@@ -54,7 +54,7 @@
<orderEntry type="library" scope="TEST" name="cucumber-java" level="project" />
<orderEntry type="library" name="JSch" level="project" />
<orderEntry type="module" module-name="spellchecker" />
- <orderEntry type="module" module-name="cucumber-test-runner" scope="RUNTIME" />
+ <orderEntry type="module" module-name="cucumber-test-runner" scope="TEST" />
<orderEntry type="module" module-name="vcs-log-api" />
<orderEntry type="module" module-name="vcs-log-impl" />
<orderEntry type="module" module-name="vcs-log-graph" />
diff --git a/plugins/git4idea/src/git4idea/GitUtil.java b/plugins/git4idea/src/git4idea/GitUtil.java
index e96d52de8ea0..3f344482f5c6 100644
--- a/plugins/git4idea/src/git4idea/GitUtil.java
+++ b/plugins/git4idea/src/git4idea/GitUtil.java
@@ -1016,6 +1016,7 @@ public class GitUtil {
@NotNull
public static String cleanupErrorPrefixes(@NotNull String msg) {
final String[] PREFIXES = { "fatal:", "error:" };
+ msg = msg.trim();
for (String prefix : PREFIXES) {
if (msg.startsWith(prefix)) {
return msg.substring(prefix.length()).trim();
diff --git a/plugins/git4idea/src/git4idea/annotate/GitAnnotationProvider.java b/plugins/git4idea/src/git4idea/annotate/GitAnnotationProvider.java
index 5ebdefd74b3a..39241b3660f8 100644
--- a/plugins/git4idea/src/git4idea/annotate/GitAnnotationProvider.java
+++ b/plugins/git4idea/src/git4idea/annotate/GitAnnotationProvider.java
@@ -101,7 +101,6 @@ public class GitAnnotationProvider implements AnnotationProvider, VcsCacheableAn
command.run();
}
if (exception[0] != null) {
- LOG.warn(exception[0]);
throw new VcsException("Failed to annotate: " + exception[0], exception[0]);
}
return annotation[0];
diff --git a/plugins/git4idea/src/git4idea/branch/GitBranchUtil.java b/plugins/git4idea/src/git4idea/branch/GitBranchUtil.java
index 6e178b9cbc0f..2504c345b559 100644
--- a/plugins/git4idea/src/git4idea/branch/GitBranchUtil.java
+++ b/plugins/git4idea/src/git4idea/branch/GitBranchUtil.java
@@ -314,6 +314,9 @@ public class GitBranchUtil {
else if (branchName.startsWith(GitBranch.REFS_REMOTES_PREFIX)) {
return branchName.substring(GitBranch.REFS_REMOTES_PREFIX.length());
}
+ else if (branchName.startsWith(GitTag.REFS_TAGS_PREFIX)) {
+ return branchName.substring(GitTag.REFS_TAGS_PREFIX.length());
+ }
return branchName;
}
diff --git a/plugins/git4idea/src/git4idea/branch/GitBranchWorker.java b/plugins/git4idea/src/git4idea/branch/GitBranchWorker.java
index a6ae9d288dee..bcf993b21723 100644
--- a/plugins/git4idea/src/git4idea/branch/GitBranchWorker.java
+++ b/plugins/git4idea/src/git4idea/branch/GitBranchWorker.java
@@ -19,11 +19,15 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
+import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Couple;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.Change;
+import com.intellij.openapi.vfs.VfsUtil;
+import com.intellij.util.containers.ContainerUtil;
import git4idea.GitCommit;
import git4idea.GitExecutionException;
+import git4idea.GitLocalBranch;
import git4idea.GitPlatformFacade;
import git4idea.changes.GitChangeUtils;
import git4idea.commands.Git;
@@ -61,15 +65,27 @@ public final class GitBranchWorker {
myUiHandler = uiHandler;
}
- public void checkoutNewBranch(@NotNull final String name, @NotNull final List<GitRepository> repositories) {
+ public void checkoutNewBranch(@NotNull final String name, @NotNull List<GitRepository> repositories) {
updateInfo(repositories);
- new GitCheckoutNewBranchOperation(myProject, myFacade, myGit, myUiHandler, repositories, name).execute();
+ repositories = ContainerUtil.filter(repositories, new Condition<GitRepository>() {
+ @Override
+ public boolean value(GitRepository repository) {
+ GitLocalBranch currentBranch = repository.getCurrentBranch();
+ return currentBranch == null || !currentBranch.getName().equals(name);
+ }
+ });
+ if (!repositories.isEmpty()) {
+ new GitCheckoutNewBranchOperation(myProject, myFacade, myGit, myUiHandler, repositories, name).execute();
+ }
+ else {
+ LOG.error("Creating new branch the same as current in all repositories: " + name);
+ }
}
public void createNewTag(@NotNull final String name, @NotNull final String reference, @NotNull final List<GitRepository> repositories) {
- updateInfo(repositories);
for (GitRepository repository : repositories) {
myGit.createNewTag(repository, name, null, reference);
+ VfsUtil.markDirtyAndRefresh(true, true, false, repository.getGitDir());
}
}
diff --git a/plugins/git4idea/src/git4idea/checkin/GitCheckinHandlerFactory.java b/plugins/git4idea/src/git4idea/checkin/GitCheckinHandlerFactory.java
index 8bfc52ca261a..c31966176ae0 100644
--- a/plugins/git4idea/src/git4idea/checkin/GitCheckinHandlerFactory.java
+++ b/plugins/git4idea/src/git4idea/checkin/GitCheckinHandlerFactory.java
@@ -15,12 +15,14 @@
*/
package git4idea.checkin;
+import com.intellij.CommonBundle;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Couple;
@@ -281,7 +283,7 @@ public class GitCheckinHandlerFactory extends VcsCheckinHandlerFactory {
private ReturnResult warnAboutDetachedHeadIfNeeded() {
// Warning: commit on a detached HEAD
DetachedRoot detachedRoot = getDetachedRoot();
- if (detachedRoot == null) {
+ if (detachedRoot == null || !GitVcsSettings.getInstance(myProject).warnAboutDetachedHead()) {
return ReturnResult.COMMIT;
}
@@ -303,10 +305,38 @@ public class GitCheckinHandlerFactory extends VcsCheckinHandlerFactory {
readMore("http://gitolite.com/detached-head.html", "Read more about detached HEAD");
}
- final int choice = Messages.showOkCancelDialog(myPanel.getComponent(), XmlStringUtil.wrapInHtml(message), title,
- "Cancel", "Commit",
- Messages.getWarningIcon());
- if (choice != Messages.OK) {
+ DialogWrapper.DoNotAskOption dontAskAgain = new DialogWrapper.DoNotAskOption() {
+ @Override
+ public boolean isToBeShown() {
+ return true;
+ }
+
+ @Override
+ public void setToBeShown(boolean toBeShown, int exitCode) {
+ if (exitCode == Messages.OK) {
+ GitVcsSettings.getInstance(myProject).setWarnAboutDetachedHead(toBeShown);
+ }
+ }
+
+ @Override
+ public boolean canBeHidden() {
+ return true;
+ }
+
+ @Override
+ public boolean shouldSaveOptionsOnCancel() {
+ return false;
+ }
+
+ @NotNull
+ @Override
+ public String getDoNotShowMessage() {
+ return "Don't warn again";
+ }
+ };
+ int choice = Messages.showOkCancelDialog(myProject, XmlStringUtil.wrapInHtml(message), title, "Commit",
+ CommonBundle.getCancelButtonText(), Messages.getWarningIcon(), dontAskAgain);
+ if (choice == Messages.OK) {
return ReturnResult.COMMIT;
} else {
return ReturnResult.CLOSE_WINDOW;
diff --git a/plugins/git4idea/src/git4idea/config/GitVcsPanel.form b/plugins/git4idea/src/git4idea/config/GitVcsPanel.form
index 0f24aaf99d56..87d3578f7c0a 100644
--- a/plugins/git4idea/src/git4idea/config/GitVcsPanel.form
+++ b/plugins/git4idea/src/git4idea/config/GitVcsPanel.form
@@ -91,7 +91,7 @@
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
</constraints>
</vspacer>
- <grid id="4d15a" layout-manager="GridLayoutManager" row-count="4" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+ <grid id="4d15a" layout-manager="GridLayoutManager" row-count="5" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
@@ -134,6 +134,15 @@
<text value="Warn if &amp;CRLF line separators are about to be committed"/>
</properties>
</component>
+ <component id="29d5c" class="javax.swing.JCheckBox" binding="myWarnAboutDetachedHead">
+ <constraints>
+ <grid row="4" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <selected value="true"/>
+ <text value="Warn when committing in detached HEAD or during rebase"/>
+ </properties>
+ </component>
</children>
</grid>
</children>
diff --git a/plugins/git4idea/src/git4idea/config/GitVcsPanel.java b/plugins/git4idea/src/git4idea/config/GitVcsPanel.java
index a8ebfe66140f..c8c2ad46a274 100644
--- a/plugins/git4idea/src/git4idea/config/GitVcsPanel.java
+++ b/plugins/git4idea/src/git4idea/config/GitVcsPanel.java
@@ -15,18 +15,17 @@
*/
package git4idea.config;
+import com.intellij.dvcs.branch.DvcsBranchSync;
import com.intellij.openapi.application.ApplicationNamesInfo;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
-import com.intellij.openapi.util.SystemInfo;
import com.intellij.ui.components.JBCheckBox;
import git4idea.GitVcs;
import git4idea.i18n.GitBundle;
import git4idea.repo.GitRepositoryManager;
-import git4idea.ui.branch.GitBranchSyncSetting;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
@@ -52,6 +51,7 @@ public class GitVcsPanel {
private JBCheckBox mySyncBranchControl;
private JCheckBox myAutoCommitOnCherryPick;
private JBCheckBox myWarnAboutCrlf;
+ private JCheckBox myWarnAboutDetachedHead;
public GitVcsPanel(@NotNull Project project) {
myVcs = GitVcs.getInstance(project);
@@ -119,9 +119,10 @@ public class GitVcsPanel {
myGitField.setText(settings.getAppSettings().getPathToGit());
mySSHExecutableComboBox.setSelectedItem(settings.isIdeaSsh() ? IDEA_SSH : NATIVE_SSH);
myAutoUpdateIfPushRejected.setSelected(settings.autoUpdateIfPushRejected());
- mySyncBranchControl.setSelected(settings.getSyncSetting() == GitBranchSyncSetting.SYNC);
+ mySyncBranchControl.setSelected(settings.getSyncSetting() == DvcsBranchSync.SYNC);
myAutoCommitOnCherryPick.setSelected(settings.isAutoCommitOnCherryPick());
myWarnAboutCrlf.setSelected(settings.warnAboutCrlf());
+ myWarnAboutDetachedHead.setSelected(settings.warnAboutDetachedHead());
}
/**
@@ -133,9 +134,10 @@ public class GitVcsPanel {
return !settings.getAppSettings().getPathToGit().equals(getCurrentExecutablePath()) ||
(settings.isIdeaSsh() != IDEA_SSH.equals(mySSHExecutableComboBox.getSelectedItem())) ||
!settings.autoUpdateIfPushRejected() == myAutoUpdateIfPushRejected.isSelected() ||
- ((settings.getSyncSetting() == GitBranchSyncSetting.SYNC) != mySyncBranchControl.isSelected() ||
+ ((settings.getSyncSetting() == DvcsBranchSync.SYNC) != mySyncBranchControl.isSelected() ||
settings.isAutoCommitOnCherryPick() != myAutoCommitOnCherryPick.isSelected() ||
- settings.warnAboutCrlf() != myWarnAboutCrlf.isSelected());
+ settings.warnAboutCrlf() != myWarnAboutCrlf.isSelected() ||
+ settings.warnAboutDetachedHead() != myWarnAboutDetachedHead.isSelected());
}
/**
@@ -151,9 +153,10 @@ public class GitVcsPanel {
GitVcsApplicationSettings.SshExecutable.NATIVE_SSH);
settings.setAutoUpdateIfPushRejected(myAutoUpdateIfPushRejected.isSelected());
- settings.setSyncSetting(mySyncBranchControl.isSelected() ? GitBranchSyncSetting.SYNC : GitBranchSyncSetting.DONT);
+ settings.setSyncSetting(mySyncBranchControl.isSelected() ? DvcsBranchSync.SYNC : DvcsBranchSync.DONT);
settings.setAutoCommitOnCherryPick(myAutoCommitOnCherryPick.isSelected());
settings.setWarnAboutCrlf(myWarnAboutCrlf.isSelected());
+ settings.setWarnAboutDetachedHead(myWarnAboutDetachedHead.isSelected());
}
}
diff --git a/plugins/git4idea/src/git4idea/config/GitVcsSettings.java b/plugins/git4idea/src/git4idea/config/GitVcsSettings.java
index 1b5860631e59..7dd7f9b1004b 100644
--- a/plugins/git4idea/src/git4idea/config/GitVcsSettings.java
+++ b/plugins/git4idea/src/git4idea/config/GitVcsSettings.java
@@ -15,12 +15,16 @@
*/
package git4idea.config;
+import com.intellij.dvcs.branch.DvcsBranchSync;
+import com.intellij.dvcs.branch.DvcsSyncBranchSettings;
import com.intellij.lifecycle.PeriodicalTasksCloser;
-import com.intellij.openapi.components.*;
+import com.intellij.openapi.components.PersistentStateComponent;
+import com.intellij.openapi.components.State;
+import com.intellij.openapi.components.Storage;
+import com.intellij.openapi.components.StoragePathMacros;
import com.intellij.openapi.project.Project;
import com.intellij.util.ArrayUtil;
import git4idea.reset.GitResetMode;
-import git4idea.ui.branch.GitBranchSyncSetting;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -32,8 +36,8 @@ import java.util.Map;
/**
* Git VCS settings
*/
-@State(name = "Git.Settings", roamingType = RoamingType.DISABLED, storages = {@Storage(file = StoragePathMacros.WORKSPACE_FILE)})
-public class GitVcsSettings implements PersistentStateComponent<GitVcsSettings.State> {
+@State(name = "Git.Settings", storages = {@Storage(file = StoragePathMacros.WORKSPACE_FILE)})
+public class GitVcsSettings implements PersistentStateComponent<GitVcsSettings.State>, DvcsSyncBranchSettings {
private static final int PREVIOUS_COMMIT_AUTHORS_LIMIT = 16; // Limit for previous commit authors
@@ -56,12 +60,13 @@ public class GitVcsSettings implements PersistentStateComponent<GitVcsSettings.S
public UpdateChangesPolicy UPDATE_CHANGES_POLICY = UpdateChangesPolicy.STASH;
public UpdateMethod UPDATE_TYPE = UpdateMethod.BRANCH_DEFAULT;
public boolean PUSH_AUTO_UPDATE = false;
- public GitBranchSyncSetting SYNC_SETTING = GitBranchSyncSetting.NOT_DECIDED;
+ public DvcsBranchSync SYNC_SETTING = DvcsBranchSync.NOT_DECIDED;
public String RECENT_GIT_ROOT_PATH = null;
public Map<String, String> RECENT_BRANCH_BY_REPOSITORY = new HashMap<String, String>();
public String RECENT_COMMON_BRANCH = null;
public boolean AUTO_COMMIT_ON_CHERRY_PICK = false;
public boolean WARN_ABOUT_CRLF = true;
+ public boolean WARN_ABOUT_DETACHED_HEAD = true;
public GitResetMode RESET_MODE = null;
}
@@ -72,7 +77,7 @@ public class GitVcsSettings implements PersistentStateComponent<GitVcsSettings.S
public GitVcsApplicationSettings getAppSettings() {
return myAppSettings;
}
-
+
public static GitVcsSettings getInstance(Project project) {
return PeriodicalTasksCloser.getInstance().safeGetService(project, GitVcsSettings.class);
}
@@ -128,11 +133,11 @@ public class GitVcsSettings implements PersistentStateComponent<GitVcsSettings.S
}
@NotNull
- public GitBranchSyncSetting getSyncSetting() {
+ public DvcsBranchSync getSyncSetting() {
return myState.SYNC_SETTING;
}
- public void setSyncSetting(@NotNull GitBranchSyncSetting syncSetting) {
+ public void setSyncSetting(@NotNull DvcsBranchSync syncSetting) {
myState.SYNC_SETTING = syncSetting;
}
@@ -179,6 +184,14 @@ public class GitVcsSettings implements PersistentStateComponent<GitVcsSettings.S
myState.WARN_ABOUT_CRLF = warn;
}
+ public boolean warnAboutDetachedHead() {
+ return myState.WARN_ABOUT_DETACHED_HEAD;
+ }
+
+ public void setWarnAboutDetachedHead(boolean warn) {
+ myState.WARN_ABOUT_DETACHED_HEAD = warn;
+ }
+
@Nullable
public GitResetMode getResetMode() {
return myState.RESET_MODE;
diff --git a/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java b/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java
index 8273c3e1abdc..f71400be2a11 100644
--- a/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java
+++ b/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java
@@ -40,12 +40,12 @@ import com.intellij.util.concurrency.Semaphore;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.vcs.log.*;
import com.intellij.vcs.log.impl.HashImpl;
+import com.intellij.vcs.log.impl.LogDataImpl;
import com.intellij.vcs.log.util.StopWatch;
import git4idea.*;
import git4idea.branch.GitBranchUtil;
import git4idea.commands.*;
import git4idea.config.GitConfigUtil;
-import git4idea.config.GitVersionSpecialty;
import git4idea.history.browser.GitHeavyCommit;
import git4idea.history.browser.SHAHash;
import git4idea.history.browser.SymbolicRefs;
@@ -53,6 +53,7 @@ import git4idea.history.browser.SymbolicRefsI;
import git4idea.history.wholeTree.AbstractHash;
import git4idea.history.wholeTree.CommitHashPlusParents;
import git4idea.history.wholeTree.GitCommitsSequentialIndex;
+import git4idea.log.GitRefManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -515,21 +516,47 @@ public class GitHistoryUtils {
});
}
- @NotNull
- public static List<TimedVcsCommit> readCommits(@NotNull final Project project,
- @NotNull VirtualFile root,
- @NotNull final Consumer<VcsUser> userRegistry,
- @NotNull List<String> parameters) throws VcsException {
- List<TimedVcsCommit> collector = ContainerUtil.newArrayList();
- readCommits(project, root, userRegistry, parameters, new CollectConsumer<TimedVcsCommit>(collector));
- return collector;
+ @Nullable
+ public static List<VcsCommitMetadata> readLastCommits(@NotNull Project project,
+ @NotNull final VirtualFile root,
+ @NotNull String... refs)
+ throws VcsException {
+ final VcsLogObjectsFactory factory = getObjectsFactoryWithDisposeCheck(project);
+ if (factory == null) {
+ return null;
+ }
+
+ GitSimpleHandler h = new GitSimpleHandler(project, root, GitCommand.LOG);
+ GitLogParser parser = new GitLogParser(project, GitLogParser.NameStatus.NONE, HASH, PARENTS, COMMIT_TIME, SUBJECT, AUTHOR_NAME,
+ AUTHOR_EMAIL, RAW_BODY, COMMITTER_NAME, COMMITTER_EMAIL, AUTHOR_TIME);
+
+ h.setSilent(true);
+ // git show can show either -p, or --name-status, or --name-only, but we need nothing, just details => using git log --no-walk
+ h.addParameters("--no-walk");
+ h.addParameters(parser.getPretty(), "--encoding=UTF-8");
+ h.addParameters(refs);
+
+ String output = h.run();
+ List<GitLogRecord> records = parser.parse(output);
+ if (records.size() != refs.length) return null;
+
+ return ContainerUtil.map(records, new Function<GitLogRecord, VcsCommitMetadata>() {
+ @Override
+ public VcsCommitMetadata fun(GitLogRecord record) {
+ return factory.createCommitMetadata(factory.createHash(record.getHash()), getParentHashes(factory, record), record.getCommitTime(),
+ root, record.getSubject(), record.getAuthorName(), record.getAuthorEmail(),
+ record.getFullMessage(), record.getCommitterName(), record.getCommitterEmail(),
+ record.getAuthorTimeStamp());
+ }
+ });
}
public static void readCommits(@NotNull final Project project,
- @NotNull VirtualFile root,
- @NotNull final Consumer<VcsUser> userRegistry,
- @NotNull List<String> parameters,
- @NotNull final Consumer<TimedVcsCommit> commitConsumer) throws VcsException {
+ @NotNull final VirtualFile root,
+ @NotNull List<String> parameters,
+ @NotNull final Consumer<VcsUser> userConsumer,
+ @NotNull final Consumer<VcsRef> refConsumer,
+ @NotNull final Consumer<TimedVcsCommit> commitConsumer) throws VcsException {
final VcsLogObjectsFactory factory = getObjectsFactoryWithDisposeCheck(project);
if (factory == null) {
return;
@@ -538,11 +565,12 @@ public class GitHistoryUtils {
final int COMMIT_BUFFER = 1000;
GitLineHandler h = new GitLineHandler(project, root, GitCommand.LOG);
final GitLogParser parser = new GitLogParser(project, GitLogParser.NameStatus.NONE, HASH, PARENTS, COMMIT_TIME,
- AUTHOR_NAME, AUTHOR_EMAIL);
+ AUTHOR_NAME, AUTHOR_EMAIL, REF_NAMES);
h.setStdoutSuppressed(true);
h.addParameters(parser.getPretty(), "--encoding=UTF-8");
h.addParameters("--full-history");
h.addParameters("--date-order");
+ h.addParameters("--decorate=full");
h.addParameters(parameters);
h.endOptions();
@@ -568,7 +596,7 @@ public class GitHistoryUtils {
afterParseRemainder = line.substring(recordEnd + 1);
}
if (afterParseRemainder != null && records.incrementAndGet() > COMMIT_BUFFER) { // null means can't parse now
- List<TimedVcsCommit> commits = parseCommit(parser, record, userRegistry, factory);
+ List<TimedVcsCommit> commits = parseCommit(parser, record, userConsumer, refConsumer, factory, root);
for (TimedVcsCommit commit : commits) {
commitConsumer.consume(commit);
}
@@ -584,7 +612,7 @@ public class GitHistoryUtils {
@Override
public void processTerminated(int exitCode) {
try {
- List<TimedVcsCommit> commits = parseCommit(parser, record, userRegistry, factory);
+ List<TimedVcsCommit> commits = parseCommit(parser, record, userConsumer, refConsumer, factory, root);
for (TimedVcsCommit commit : commits) {
commitConsumer.consume(commit);
}
@@ -606,9 +634,12 @@ public class GitHistoryUtils {
}
@NotNull
- private static List<TimedVcsCommit> parseCommit(@NotNull GitLogParser parser, @NotNull StringBuilder record,
+ private static List<TimedVcsCommit> parseCommit(@NotNull GitLogParser parser,
+ @NotNull StringBuilder record,
@NotNull final Consumer<VcsUser> userRegistry,
- @NotNull final VcsLogObjectsFactory factory) {
+ @NotNull final Consumer<VcsRef> refConsumer,
+ @NotNull final VcsLogObjectsFactory factory,
+ @NotNull final VirtualFile root) {
List<GitLogRecord> rec = parser.parse(record.toString());
return ContainerUtil.mapNotNull(rec, new Function<GitLogRecord, TimedVcsCommit>() {
@Override
@@ -616,7 +647,11 @@ public class GitHistoryUtils {
if (record == null) {
return null;
}
- TimedVcsCommit commit = convert(record, factory);
+ Pair<TimedVcsCommit, Collection<VcsRef>> pair = convert(record, factory, root);
+ TimedVcsCommit commit = pair.first;
+ for (VcsRef ref : pair.second) {
+ refConsumer.consume(ref);
+ }
userRegistry.consume(factory.createUser(record.getAuthorName(), record.getAuthorEmail()));
return commit;
}
@@ -624,9 +659,28 @@ public class GitHistoryUtils {
}
@NotNull
- private static TimedVcsCommit convert(@NotNull GitLogRecord rec, @NotNull VcsLogObjectsFactory factory) {
+ private static Pair<TimedVcsCommit, Collection<VcsRef>> convert(@NotNull GitLogRecord rec,
+ @NotNull VcsLogObjectsFactory factory,
+ @NotNull VirtualFile root) {
+ Hash hash = HashImpl.build(rec.getHash());
List<Hash> parents = getParentHashes(factory, rec);
- return factory.createTimedCommit(HashImpl.build(rec.getHash()), parents, rec.getCommitTime());
+ TimedVcsCommit commit = factory.createTimedCommit(hash, parents, rec.getCommitTime());
+ return Pair.create(commit, parseRefs(rec.getRefs(), hash, factory, root));
+ }
+
+ @NotNull
+ private static Collection<VcsRef> parseRefs(@NotNull Collection<String> refs,
+ @NotNull final Hash hash,
+ @NotNull final VcsLogObjectsFactory factory,
+ @NotNull final VirtualFile root) {
+ return ContainerUtil.mapNotNull(refs, new Function<String, VcsRef>() {
+ @Override
+ public VcsRef fun(String refName) {
+ VcsRefType type = GitRefManager.getRefType(refName);
+ refName = GitBranchUtil.stripRefsPrefix(refName);
+ return factory.createRef(hash, refName, type, root);
+ }
+ });
}
@Nullable
@@ -749,23 +803,28 @@ public class GitHistoryUtils {
}
@NotNull
- public static List<VcsCommitMetadata> loadMetadata(@NotNull Project project, @NotNull final VirtualFile root,
- @NotNull String... parameters) throws VcsException {
-
+ public static VcsLogProvider.DetailedLogData loadMetadata(@NotNull final Project project,
+ @NotNull final VirtualFile root,
+ final boolean withRefs,
+ String... params) throws VcsException {
final VcsLogObjectsFactory factory = getObjectsFactoryWithDisposeCheck(project);
if (factory == null) {
- return Collections.emptyList();
+ return LogDataImpl.empty();
}
- return loadDetails(project, root, false, new NullableFunction<GitLogRecord, VcsCommitMetadata>() {
- @Nullable
- @Override
- public VcsCommitMetadata fun(GitLogRecord record) {
- return factory.createCommitMetadata(factory.createHash(record.getHash()), getParentHashes(factory, record), record.getCommitTime(),
- root, record.getSubject(), record.getAuthorName(), record.getAuthorEmail(),
- record.getFullMessage(), record.getCommitterName(), record.getCommitterEmail(),
- record.getAuthorTimeStamp());
- }
- }, parameters);
+ final Set<VcsRef> refs = ContainerUtil.newHashSet();
+ final List<VcsCommitMetadata> commits =
+ loadDetails(project, root, withRefs, false, new NullableFunction<GitLogRecord, VcsCommitMetadata>() {
+ @Nullable
+ @Override
+ public VcsCommitMetadata fun(GitLogRecord record) {
+ GitCommit commit = createCommit(project, root, record, factory);
+ if (withRefs) {
+ refs.addAll(parseRefs(record.getRefs(), commit.getId(), factory, root));
+ }
+ return commit;
+ }
+ }, params);
+ return new LogDataImpl(refs, commits);
}
/**
@@ -781,35 +840,39 @@ public class GitHistoryUtils {
if (factory == null) {
return Collections.emptyList();
}
- return loadDetails(project, root, true, new NullableFunction<GitLogRecord, GitCommit>() {
+ return loadDetails(project, root, false, true, new NullableFunction<GitLogRecord, GitCommit>() {
@Override
@Nullable
public GitCommit fun(GitLogRecord record) {
- try {
- return createCommit(project, root, record, factory);
- }
- catch (VcsException e) {
- LOG.error(e);
- return null;
- }
+ return createCommit(project, root, record, factory);
}
}, parameters);
}
@NotNull
- public static <T> List<T> loadDetails(@NotNull final Project project, @NotNull final VirtualFile root, boolean withChanges,
- @NotNull NullableFunction<GitLogRecord, T> converter, String... parameters)
+ public static <T> List<T> loadDetails(@NotNull final Project project,
+ @NotNull final VirtualFile root,
+ boolean withRefs,
+ boolean withChanges,
+ @NotNull NullableFunction<GitLogRecord, T> converter,
+ String... parameters)
throws VcsException {
GitSimpleHandler h = new GitSimpleHandler(project, root, GitCommand.LOG);
GitLogParser.NameStatus status = withChanges ? GitLogParser.NameStatus.STATUS : GitLogParser.NameStatus.NONE;
- GitLogParser parser = new GitLogParser(project, status, HASH, COMMIT_TIME, AUTHOR_NAME, AUTHOR_TIME,
- AUTHOR_EMAIL, COMMITTER_NAME, COMMITTER_EMAIL, PARENTS, SUBJECT, BODY, RAW_BODY);
+ GitLogParser.GitLogOption[] options = { HASH, COMMIT_TIME, AUTHOR_NAME, AUTHOR_TIME, AUTHOR_EMAIL, COMMITTER_NAME, COMMITTER_EMAIL,
+ PARENTS, SUBJECT, BODY, RAW_BODY };
+ if (withRefs) {
+ options = ArrayUtil.append(options, REF_NAMES);
+ }
+ GitLogParser parser = new GitLogParser(project, status, options);
h.setStdoutSuppressed(true);
h.addParameters(parameters);
h.addParameters(parser.getPretty(), "--encoding=UTF-8");
- h.addParameters("--full-history", "--sparse");
+ if (withRefs) {
+ h.addParameters("--decorate=full");
+ }
if (withChanges) {
- h.addParameters("-M", "--name-status");
+ h.addParameters("-M", "--name-status", "-m");
}
h.endOptions();
@@ -828,7 +891,7 @@ public class GitHistoryUtils {
}
private static GitCommit createCommit(@NotNull Project project, @NotNull VirtualFile root, @NotNull GitLogRecord record,
- @NotNull VcsLogObjectsFactory factory) throws VcsException {
+ @NotNull VcsLogObjectsFactory factory) {
List<Hash> parents = getParentHashes(factory, record);
return new GitCommit(project, HashImpl.build(record.getHash()), parents, record.getCommitTime(), root, record.getSubject(),
factory.createUser(record.getAuthorName(), record.getAuthorEmail()), record.getFullMessage(),
@@ -1091,40 +1154,6 @@ public class GitHistoryUtils {
return rc;
}
- @NotNull
- public static List<GitCommit> commitsDetails(@NotNull Project project, @NotNull VirtualFile root,
- @NotNull final Collection<String> hashes) throws VcsException {
- List<String> params = new ArrayList<String>(hashes);
- GitVcs vcs = GitVcs.getInstance(project);
- String noWalk = vcs != null && GitVersionSpecialty.NO_WALK_UNSORTED.existsIn(vcs.getVersion()) ? "--no-walk=unsorted" : "--no-walk";
- params.add(0, noWalk);
- return getAllDetails(project, root, params);
- }
-
- @NotNull
- public static List<GitCommit> getAllDetails(@NotNull Project project, @NotNull VirtualFile root,
- @NotNull List<String> parameters) throws VcsException {
- VcsLogObjectsFactory factory = getObjectsFactoryWithDisposeCheck(project);
- if (factory == null) {
- return Collections.emptyList();
- }
-
- GitSimpleHandler h = new GitSimpleHandler(project, root, GitCommand.LOG);
- GitLogParser parser = new GitLogParser(project, GitLogParser.NameStatus.STATUS,
- HASH, HASH, COMMIT_TIME, AUTHOR_NAME, AUTHOR_TIME, AUTHOR_EMAIL, COMMITTER_NAME,
- COMMITTER_EMAIL, PARENTS, REF_NAMES, SUBJECT, BODY, RAW_BODY);
- h.setSilent(true);
- h.addParameters("--name-status", "-M", parser.getPretty(), "--encoding=UTF-8");
- h.addParameters(parameters);
-
- String output = h.run();
- final List<GitCommit> rc = new ArrayList<GitCommit>();
- for (GitLogRecord record : parser.parse(output)) {
- rc.add(createCommit(project, root, record, factory));
- }
- return rc;
- }
-
public static long getAuthorTime(Project project, FilePath path, final String commitsId) throws VcsException {
// adjust path using change manager
path = getLastCommitName(project, path);
diff --git a/plugins/git4idea/src/git4idea/history/GitLogRecord.java b/plugins/git4idea/src/git4idea/history/GitLogRecord.java
index e5b8735e0d4e..a9857963124f 100644
--- a/plugins/git4idea/src/git4idea/history/GitLogRecord.java
+++ b/plugins/git4idea/src/git4idea/history/GitLogRecord.java
@@ -22,10 +22,13 @@ import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ArrayUtil;
+import com.intellij.util.Function;
+import com.intellij.util.containers.ContainerUtil;
import com.intellij.vcsUtil.VcsUtil;
import git4idea.GitUtil;
import git4idea.commands.GitHandler;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.util.*;
@@ -130,12 +133,7 @@ class GitLogRecord {
public Collection<String> getRefs() {
final String decorate = myOptions.get(REF_NAMES);
- final String[] refNames = parseRefNames(decorate);
- final List<String> result = new ArrayList<String>(refNames.length);
- for (String refName : refNames) {
- result.add(shortBuffer(refName));
- }
- return result;
+ return parseRefNames(decorate);
}
/**
* Returns the list of tags and the list of branches.
@@ -163,12 +161,23 @@ class GitLogRecord {
return Pair.create(tags, branches);
}*/
- private static String[] parseRefNames(final String decorate) {
- final int startParentheses = decorate.indexOf("(");
- final int endParentheses = decorate.indexOf(")");
- if ((startParentheses == -1) || (endParentheses == -1)) return ArrayUtil.EMPTY_STRING_ARRAY;
- final String refs = decorate.substring(startParentheses + 1, endParentheses);
- return refs.split(", ");
+ @NotNull
+ private static List<String> parseRefNames(@Nullable final String decoration) {
+ if (decoration == null) {
+ return ContainerUtil.emptyList();
+ }
+ final int startParentheses = decoration.indexOf("(");
+ final int endParentheses = decoration.indexOf(")");
+ if ((startParentheses == -1) || (endParentheses == -1)) return Collections.emptyList();
+ String refs = decoration.substring(startParentheses + 1, endParentheses);
+ String[] names = refs.split(", ");
+ return ContainerUtil.map(names, new Function<String, String>() {
+ @Override
+ public String fun(String item) {
+ int colon = item.indexOf(':');
+ return shortBuffer(colon > 0 ? item.substring(colon + 1).trim() : item);
+ }
+ });
}
private static String shortBuffer(String raw) {
diff --git a/plugins/git4idea/src/git4idea/log/GitLogProvider.java b/plugins/git4idea/src/git4idea/log/GitLogProvider.java
index b5096a94f03b..72aef054a785 100644
--- a/plugins/git4idea/src/git4idea/log/GitLogProvider.java
+++ b/plugins/git4idea/src/git4idea/log/GitLogProvider.java
@@ -15,34 +15,27 @@
*/
package git4idea.log;
-import com.intellij.openapi.diagnostic.Attachment;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.VcsKey;
import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.util.ArrayUtil;
-import com.intellij.util.Consumer;
-import com.intellij.util.ExceptionUtil;
-import com.intellij.util.Function;
+import com.intellij.util.*;
import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.containers.OpenTHashSet;
import com.intellij.vcs.log.*;
import com.intellij.vcs.log.data.VcsLogSorter;
+import com.intellij.vcs.log.impl.LogDataImpl;
import com.intellij.vcs.log.impl.HashImpl;
-import git4idea.GitLocalBranch;
-import git4idea.GitRemoteBranch;
-import git4idea.GitUserRegistry;
-import git4idea.GitVcs;
+import git4idea.*;
import git4idea.branch.GitBranchUtil;
-import git4idea.commands.GitCommand;
-import git4idea.commands.GitSimpleHandler;
+import git4idea.config.GitVersionSpecialty;
import git4idea.history.GitHistoryUtils;
-import git4idea.history.GitLogParser;
import git4idea.repo.GitRepository;
import git4idea.repo.GitRepositoryChangeListener;
import git4idea.repo.GitRepositoryManager;
+import gnu.trove.TObjectHashingStrategy;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -51,8 +44,26 @@ import java.util.*;
public class GitLogProvider implements VcsLogProvider {
private static final Logger LOG = Logger.getInstance(GitLogProvider.class);
+ public static final Function<VcsRef, String> GET_TAG_NAME = new Function<VcsRef, String>() {
+ @Override
+ public String fun(VcsRef ref) {
+ return ref.getType() == GitRefManager.TAG ? ref.getName() : null;
+ }
+ };
+ private static final TObjectHashingStrategy<VcsRef> REF_ONLY_NAME_STRATEGY = new TObjectHashingStrategy<VcsRef>() {
+ @Override
+ public int computeHashCode(@NotNull VcsRef ref) {
+ return ref.getName().hashCode();
+ }
+
+ @Override
+ public boolean equals(@NotNull VcsRef ref1, @NotNull VcsRef ref2) {
+ return ref1.getName().equals(ref2.getName());
+ }
+ };
@NotNull private final Project myProject;
+ @NotNull private final GitVcs myVcs;
@NotNull private final GitRepositoryManager myRepositoryManager;
@NotNull private final GitUserRegistry myUserRegistry;
@NotNull private final VcsLogRefManager myRefSorter;
@@ -65,112 +76,127 @@ public class GitLogProvider implements VcsLogProvider {
myUserRegistry = userRegistry;
myRefSorter = new GitRefManager(myRepositoryManager);
myVcsObjectsFactory = factory;
+ myVcs = ObjectUtils.assertNotNull(GitVcs.getInstance(project));
}
@NotNull
@Override
- public List<? extends VcsCommitMetadata> readFirstBlock(@NotNull VirtualFile root, @NotNull Requirements requirements) throws VcsException {
+ public DetailedLogData readFirstBlock(@NotNull VirtualFile root, @NotNull Requirements requirements) throws VcsException {
if (!isRepositoryReady(root)) {
- return Collections.emptyList();
+ return LogDataImpl.empty();
}
+ GitRepository repository = ObjectUtils.assertNotNull(myRepositoryManager.getRepositoryForRoot(root));
// need to query more to sort them manually; this doesn't affect performance: it is equal for -1000 and -2000
int commitCount = requirements.getCommitCount() * 2;
String[] params = new String[]{"HEAD", "--branches", "--remotes", "--max-count=" + commitCount};
// NB: not specifying --tags, because it introduces great slowdown if there are many tags,
- // but makes sense only if there are heads without branch or HEAD labels (rare case). Such cases are partially handles below.
- List<VcsCommitMetadata> firstBlock = GitHistoryUtils.loadMetadata(myProject, root, params);
+ // but makes sense only if there are heads without branch or HEAD labels (rare case). Such cases are partially handled below.
- if (requirements instanceof VcsLogProviderRequirementsEx) {
- VcsLogProviderRequirementsEx rex = (VcsLogProviderRequirementsEx)requirements;
+ boolean refresh = requirements instanceof VcsLogProviderRequirementsEx && ((VcsLogProviderRequirementsEx)requirements).isRefresh();
+
+ DetailedLogData data = GitHistoryUtils.loadMetadata(myProject, root, refresh, params);
+
+ Set<VcsRef> safeRefs = data.getRefs();
+ Set<VcsRef> allRefs = new OpenTHashSet<VcsRef>(safeRefs, REF_ONLY_NAME_STRATEGY);
+ addNewElements(allRefs, readBranches(repository));
+
+ Collection<VcsCommitMetadata> allDetails;
+ if (!refresh) {
+ allDetails = data.getCommits();
+ }
+ else {
// on refresh: get new tags, which point to commits not from the first block; then get history, walking down just from these tags
// on init: just ignore such tagged-only branches. The price for speed-up.
- if (rex.isRefresh()) {
- Collection<VcsRef> newTags = getNewTags(rex.getCurrentRefs(), rex.getPreviousRefs());
- if (!newTags.isEmpty()) {
- final Set<Hash> firstBlockHashes = ContainerUtil.map2Set(firstBlock, new Function<VcsCommitMetadata, Hash>() {
- @Override
- public Hash fun(VcsCommitMetadata metadata) {
- return metadata.getId();
- }
- });
- List<VcsRef> unmatchedHeads = getUnmatchedHeads(firstBlockHashes, newTags);
- if (!unmatchedHeads.isEmpty()) {
- List<VcsCommitMetadata> detailsFromTaggedBranches = loadSomeCommitsOnTaggedBranches(root, commitCount, unmatchedHeads);
- Collection<VcsCommitMetadata> unmatchedCommits = getUnmatchedCommits(firstBlockHashes, detailsFromTaggedBranches);
- firstBlock.addAll(unmatchedCommits);
- }
- }
+ VcsLogProviderRequirementsEx rex = (VcsLogProviderRequirementsEx)requirements;
+
+ Set<String> currentTags = readCurrentTagNames(root);
+ addOldStillExistingTags(allRefs, currentTags, rex.getPreviousRefs());
+
+ allDetails = ContainerUtil.newHashSet(data.getCommits());
+
+ Set<String> previousTags = new HashSet<String>(ContainerUtil.mapNotNull(rex.getPreviousRefs(), GET_TAG_NAME));
+ Set<String> safeTags = new HashSet<String>(ContainerUtil.mapNotNull(safeRefs, GET_TAG_NAME));
+ Set<String> newUnmatchedTags = remove(currentTags, previousTags, safeTags);
+
+ if (!newUnmatchedTags.isEmpty()) {
+ DetailedLogData commitsFromTags = loadSomeCommitsOnTaggedBranches(root, commitCount, newUnmatchedTags);
+ addNewElements(allDetails, commitsFromTags.getCommits());
+ addNewElements(allRefs, commitsFromTags.getRefs());
}
}
- firstBlock = VcsLogSorter.sortByDateTopoOrder(firstBlock);
- firstBlock = new ArrayList<VcsCommitMetadata>(firstBlock.subList(0, Math.min(firstBlock.size(), requirements.getCommitCount())));
- return firstBlock;
+ List<VcsCommitMetadata> sortedCommits = VcsLogSorter.sortByDateTopoOrder(allDetails);
+ sortedCommits = sortedCommits.subList(0, Math.min(sortedCommits.size(), requirements.getCommitCount()));
+
+ return new LogDataImpl(allRefs, sortedCommits);
}
- @NotNull
- private static Collection<VcsRef> getNewTags(@NotNull Set<VcsRef> currentRefs, @NotNull final Set<VcsRef> previousRefs) {
- return ContainerUtil.filter(currentRefs, new Condition<VcsRef>() {
- @Override
- public boolean value(VcsRef ref) {
- return !ref.getType().isBranch() && !previousRefs.contains(ref);
+ private static void addOldStillExistingTags(@NotNull Set<VcsRef> allRefs,
+ @NotNull Set<String> currentTags,
+ @NotNull Set<VcsRef> previousRefs) {
+ for (VcsRef ref : previousRefs) {
+ if (!allRefs.contains(ref) && currentTags.contains(ref.getName())) {
+ allRefs.add(ref);
}
- });
+ }
}
@NotNull
- private List<VcsCommitMetadata> loadSomeCommitsOnTaggedBranches(@NotNull VirtualFile root, int commitCount,
- @NotNull List<VcsRef> unmatchedHeads) throws VcsException {
- List<String> params = new ArrayList<String>(ContainerUtil.map(unmatchedHeads, new Function<VcsRef, String>() {
- @Override
- public String fun(VcsRef ref) {
- return ref.getCommitHash().asString();
- }
- }));
- params.add("--max-count=" + commitCount);
- return GitHistoryUtils.loadMetadata(myProject, root, ArrayUtil.toStringArray(params));
+ private Set<String> readCurrentTagNames(@NotNull VirtualFile root) throws VcsException {
+ Set<String> tags = ContainerUtil.newHashSet();
+ GitTag.listAsStrings(myProject, root, tags, null);
+ return tags;
}
@NotNull
- private static List<VcsRef> getUnmatchedHeads(@NotNull final Set<Hash> firstBlockHashes, @NotNull Collection<VcsRef> refs) {
- return ContainerUtil.filter(refs, new Condition<VcsRef>() {
- @Override
- public boolean value(VcsRef ref) {
- return !firstBlockHashes.contains(ref.getCommitHash());
+ private static <T> Set<T> remove(@NotNull Set<T> original, @NotNull Set<T>... toRemove) {
+ Set<T> result = ContainerUtil.newHashSet(original);
+ for (Set<T> set : toRemove) {
+ result.removeAll(set);
+ }
+ return result;
+ }
+
+ private static <T> void addNewElements(@NotNull Collection<T> original, @NotNull Collection<T> toAdd) {
+ for (T item : toAdd) {
+ if (!original.contains(item)) {
+ original.add(item);
}
- });
+ }
}
@NotNull
- private static Collection<VcsCommitMetadata> getUnmatchedCommits(@NotNull final Set<Hash> firstBlockHashes,
- @NotNull List<VcsCommitMetadata> detailsFromTaggedBranches) {
- return ContainerUtil.filter(detailsFromTaggedBranches, new Condition<VcsCommitMetadata>() {
- @Override
- public boolean value(VcsCommitMetadata metadata) {
- return !firstBlockHashes.contains(metadata.getId());
- }
- });
+ private DetailedLogData loadSomeCommitsOnTaggedBranches(@NotNull VirtualFile root, int commitCount,
+ @NotNull Collection<String> unmatchedTags) throws VcsException {
+ List<String> params = new ArrayList<String>();
+ params.add("--max-count=" + commitCount);
+ params.addAll(unmatchedTags);
+ return GitHistoryUtils.loadMetadata(myProject, root, true, ArrayUtil.toStringArray(params));
}
@Override
- public void readAllHashes(@NotNull VirtualFile root, @NotNull Consumer<VcsUser> userRegistry,
- @NotNull final Consumer<TimedVcsCommit> commitConsumer) throws VcsException {
+ @NotNull
+ public LogData readAllHashes(@NotNull VirtualFile root, @NotNull final Consumer<TimedVcsCommit> commitConsumer) throws VcsException {
if (!isRepositoryReady(root)) {
- return;
+ return LogDataImpl.empty();
}
List<String> parameters = new ArrayList<String>(GitHistoryUtils.LOG_ALL);
parameters.add("--sparse");
final GitBekParentFixer parentFixer = GitBekParentFixer.prepare(root, this);
- GitHistoryUtils.readCommits(myProject, root, userRegistry, parameters, new Consumer<TimedVcsCommit>() {
+ Set<VcsUser> userRegistry = ContainerUtil.newHashSet();
+ Set<VcsRef> refs = ContainerUtil.newHashSet();
+ GitHistoryUtils.readCommits(myProject, root, parameters, new CollectConsumer<VcsUser>(userRegistry),
+ new CollectConsumer<VcsRef>(refs), new Consumer<TimedVcsCommit>() {
@Override
public void consume(TimedVcsCommit commit) {
commitConsumer.consume(parentFixer.fixCommit(commit));
}
});
+ return new LogDataImpl(refs, userRegistry);
}
@NotNull
@@ -183,21 +209,19 @@ public class GitLogProvider implements VcsLogProvider {
@NotNull
@Override
public List<? extends VcsFullCommitDetails> readFullDetails(@NotNull VirtualFile root, @NotNull List<String> hashes) throws VcsException {
- return GitHistoryUtils.commitsDetails(myProject, root, hashes);
+ String noWalk = GitVersionSpecialty.NO_WALK_UNSORTED.existsIn(myVcs.getVersion()) ? "--no-walk=unsorted" : "--no-walk";
+ List<String> params = new ArrayList<String>();
+ params.add(noWalk);
+ params.addAll(hashes);
+ return GitHistoryUtils.history(myProject, root, ArrayUtil.toStringArray(params));
}
@NotNull
- @Override
- public Collection<VcsRef> readAllRefs(@NotNull VirtualFile root) throws VcsException {
- if (!isRepositoryReady(root)) {
- return Collections.emptyList();
- }
-
- GitRepository repository = getRepository(root);
- repository.update();
+ private Set<VcsRef> readBranches(@NotNull GitRepository repository) {
+ VirtualFile root = repository.getRoot();
Collection<GitLocalBranch> localBranches = repository.getBranches().getLocalBranches();
Collection<GitRemoteBranch> remoteBranches = repository.getBranches().getRemoteBranches();
- Collection<VcsRef> refs = new ArrayList<VcsRef>(localBranches.size() + remoteBranches.size());
+ Set<VcsRef> refs = new HashSet<VcsRef>(localBranches.size() + remoteBranches.size());
for (GitLocalBranch localBranch : localBranches) {
refs.add(
myVcsObjectsFactory.createRef(HashImpl.build(localBranch.getHash()), localBranch.getName(), GitRefManager.LOCAL_BRANCH, root));
@@ -210,29 +234,6 @@ public class GitLogProvider implements VcsLogProvider {
if (currentRevision != null) { // null => fresh repository
refs.add(myVcsObjectsFactory.createRef(HashImpl.build(currentRevision), "HEAD", GitRefManager.HEAD, root));
}
-
- refs.addAll(readTags(root));
- return refs;
- }
-
- // TODO this is to be removed when tags will be supported by the GitRepositoryReader
- private Collection<? extends VcsRef> readTags(@NotNull VirtualFile root) throws VcsException {
- GitSimpleHandler tagHandler = new GitSimpleHandler(myProject, root, GitCommand.LOG);
- tagHandler.setSilent(true);
- tagHandler.addParameters("--tags", "--no-walk", "--format=%H%d" + GitLogParser.RECORD_START_GIT, "--decorate=full");
- String out = tagHandler.run();
- Collection<VcsRef> refs = new ArrayList<VcsRef>();
- try {
- for (String record : out.split(GitLogParser.RECORD_START)) {
- if (!StringUtil.isEmptyOrSpaces(record)) {
- refs.addAll(new RefParser(myVcsObjectsFactory).parseCommitRefs(record.trim(), root));
- }
- }
- }
- catch (Exception e) {
- LOG.error("Error during tags parsing", new Attachment("stack_trace.txt", ExceptionUtil.getThrowableText(e)),
- new Attachment("git_output.txt", out));
- }
return refs;
}
@@ -327,7 +328,10 @@ public class GitLogProvider implements VcsLogProvider {
}
}
- return GitHistoryUtils.readCommits(myProject, root, Consumer.EMPTY_CONSUMER, filterParameters);
+ List<TimedVcsCommit> commits = ContainerUtil.newArrayList();
+ GitHistoryUtils.readCommits(myProject, root, filterParameters, Consumer.EMPTY_CONSUMER, Consumer.EMPTY_CONSUMER,
+ new CollectConsumer<TimedVcsCommit>(commits));
+ return commits;
}
@Nullable
diff --git a/plugins/git4idea/src/git4idea/log/GitRefManager.java b/plugins/git4idea/src/git4idea/log/GitRefManager.java
index eb9e79c69767..6469a1fef1bd 100644
--- a/plugins/git4idea/src/git4idea/log/GitRefManager.java
+++ b/plugins/git4idea/src/git4idea/log/GitRefManager.java
@@ -15,6 +15,7 @@ import com.intellij.vcs.log.VcsRefType;
import com.intellij.vcs.log.impl.SingletonRefGroup;
import git4idea.GitBranch;
import git4idea.GitRemoteBranch;
+import git4idea.GitTag;
import git4idea.repo.GitBranchTrackInfo;
import git4idea.repo.GitRemote;
import git4idea.repo.GitRepository;
@@ -38,9 +39,10 @@ public class GitRefManager implements VcsLogRefManager {
public static final VcsRefType LOCAL_BRANCH = new SimpleRefType(true, LOCAL_BRANCH_COLOR);
public static final VcsRefType REMOTE_BRANCH = new SimpleRefType(true, REMOTE_BRANCH_COLOR);
public static final VcsRefType TAG = new SimpleRefType(false, TAG_COLOR);
+ public static final VcsRefType OTHER = new SimpleRefType(false, TAG_COLOR);
// first has the highest priority
- private static final List<VcsRefType> REF_TYPE_PRIORITIES = Arrays.asList(HEAD, LOCAL_BRANCH, REMOTE_BRANCH, TAG);
+ private static final List<VcsRefType> REF_TYPE_PRIORITIES = Arrays.asList(HEAD, LOCAL_BRANCH, REMOTE_BRANCH, TAG, OTHER);
// -1 => higher priority
public static final Comparator<VcsRefType> REF_TYPE_COMPARATOR = new Comparator<VcsRefType>() {
@@ -173,7 +175,7 @@ public class GitRefManager implements VcsLogRefManager {
remoteRefGroups.putValue(nonTracked.get(refName), ref);
}
else {
- LOG.warn("Didn't find ref neither in local nor in remote branches: " + ref);
+ LOG.debug("Didn't find ref neither in local nor in remote branches: " + ref);
}
}
}
@@ -243,6 +245,23 @@ public class GitRefManager implements VcsLogRefManager {
return grouped;
}
+ @NotNull
+ public static VcsRefType getRefType(@NotNull String refName) {
+ if (refName.startsWith(GitBranch.REFS_HEADS_PREFIX)) {
+ return LOCAL_BRANCH;
+ }
+ if (refName.startsWith(GitBranch.REFS_REMOTES_PREFIX)) {
+ return REMOTE_BRANCH;
+ }
+ if (refName.startsWith(GitTag.REFS_TAGS_PREFIX)) {
+ return TAG;
+ }
+ if (refName.startsWith("HEAD")) {
+ return HEAD;
+ }
+ return OTHER;
+ }
+
private static class SimpleRefType implements VcsRefType {
private final boolean myIsBranch;
@NotNull private final Color myColor;
diff --git a/plugins/git4idea/src/git4idea/repo/GitRepositoryFiles.java b/plugins/git4idea/src/git4idea/repo/GitRepositoryFiles.java
index d32a0e12f28d..cb0bd9d3dd71 100644
--- a/plugins/git4idea/src/git4idea/repo/GitRepositoryFiles.java
+++ b/plugins/git4idea/src/git4idea/repo/GitRepositoryFiles.java
@@ -45,6 +45,7 @@ public class GitRepositoryFiles {
public static final String PACKED_REFS = "packed-refs";
public static final String REFS_HEADS = "refs/heads";
public static final String REFS_REMOTES = "refs/remotes";
+ public static final String REFS_TAGS = "refs/tags";
public static final String SQUASH_MSG = "SQUASH_MSG";
public static final String GIT_HEAD = DOT_GIT + slash(HEAD);
@@ -64,6 +65,7 @@ public class GitRepositoryFiles {
private final String myPackedRefsPath;
private final String myRefsHeadsDirPath;
private final String myRefsRemotesDirPath;
+ private final String myRefsTagsPath;
private final String myCommitMessagePath;
private final String myExcludePath;
@@ -85,6 +87,7 @@ public class GitRepositoryFiles {
myRebaseMergePath = gitDirPath + slash(REBASE_MERGE);
myPackedRefsPath = gitDirPath + slash(PACKED_REFS);
myRefsHeadsDirPath = gitDirPath + slash(REFS_HEADS);
+ myRefsTagsPath = gitDirPath + slash(REFS_TAGS);
myRefsRemotesDirPath = gitDirPath + slash(REFS_REMOTES);
myExcludePath = gitDirPath + slash(INFO_EXCLUDE);
}
@@ -99,19 +102,24 @@ public class GitRepositoryFiles {
*/
@NotNull
static Collection<String> getSubDirRelativePaths() {
- return Arrays.asList(slash(REFS_HEADS), slash(REFS_REMOTES), slash(INFO));
+ return Arrays.asList(slash(REFS_HEADS), slash(REFS_REMOTES), slash(REFS_TAGS), slash(INFO));
}
@NotNull
String getRefsHeadsPath() {
return myRefsHeadsDirPath;
}
-
+
@NotNull
String getRefsRemotesPath() {
return myRefsRemotesDirPath;
}
+ @NotNull
+ String getRefsTagsPath() {
+ return myRefsTagsPath;
+ }
+
/**
* {@code .git/config}
*/
@@ -148,6 +156,13 @@ public class GitRepositoryFiles {
}
/**
+ * .git/refs/tags/*
+ */
+ public boolean isTagFile(@NotNull String path) {
+ return path.startsWith(myRefsTagsPath);
+ }
+
+ /**
* .git/rebase-merge or .git/rebase-apply
*/
public boolean isRebaseFile(String path) {
diff --git a/plugins/git4idea/src/git4idea/repo/GitRepositoryImpl.java b/plugins/git4idea/src/git4idea/repo/GitRepositoryImpl.java
index 1444f44c0288..30951670e079 100644
--- a/plugins/git4idea/src/git4idea/repo/GitRepositoryImpl.java
+++ b/plugins/git4idea/src/git4idea/repo/GitRepositoryImpl.java
@@ -139,6 +139,13 @@ public class GitRepositoryImpl extends RepositoryImpl implements GitRepository {
@Nullable
@Override
+ public String getCurrentBranchName() {
+ GitLocalBranch currentBranch = getCurrentBranch();
+ return currentBranch == null ? null : currentBranch.getName();
+ }
+
+ @Nullable
+ @Override
public AbstractVcs getVcs() {
return GitVcs.getInstance(getProject());
}
@@ -235,5 +242,4 @@ public class GitRepositoryImpl extends RepositoryImpl implements GitRepository {
myBranches = branches;
}
}
-
}
diff --git a/plugins/git4idea/src/git4idea/repo/GitRepositoryUpdater.java b/plugins/git4idea/src/git4idea/repo/GitRepositoryUpdater.java
index 70a41d3d2da8..a5af8fca6352 100644
--- a/plugins/git4idea/src/git4idea/repo/GitRepositoryUpdater.java
+++ b/plugins/git4idea/src/git4idea/repo/GitRepositoryUpdater.java
@@ -34,19 +34,21 @@ import java.util.List;
/**
* Listens to .git service files changes and updates {@link GitRepository} when needed.
- * @author Kirill Likhodedov
*/
final class GitRepositoryUpdater implements Disposable, BulkFileListener {
+
+ @NotNull private final GitRepository myRepository;
@NotNull private final GitRepositoryFiles myRepositoryFiles;
@Nullable private final MessageBusConnection myMessageBusConnection;
@NotNull private final QueueProcessor<Object> myUpdateQueue;
@NotNull private final Object DUMMY_UPDATE_OBJECT = new Object();
@Nullable private final VirtualFile myRemotesDir;
@Nullable private final VirtualFile myHeadsDir;
+ @Nullable private final VirtualFile myTagsDir;
@Nullable private final LocalFileSystem.WatchRequest myWatchRequest;
-
GitRepositoryUpdater(@NotNull GitRepository repository) {
+ myRepository = repository;
VirtualFile gitDir = repository.getGitDir();
myWatchRequest = LocalFileSystem.getInstance().addRootToWatch(gitDir.getPath(), true);
@@ -54,6 +56,7 @@ final class GitRepositoryUpdater implements Disposable, BulkFileListener {
RepositoryUtil.visitVcsDirVfs(gitDir, GitRepositoryFiles.getSubDirRelativePaths());
myHeadsDir = VcsUtil.getVirtualFile(myRepositoryFiles.getRefsHeadsPath());
myRemotesDir = VcsUtil.getVirtualFile(myRepositoryFiles.getRefsRemotesPath());
+ myTagsDir = VcsUtil.getVirtualFile(myRepositoryFiles.getRefsTagsPath());
Project project = repository.getProject();
myUpdateQueue = new QueueProcessor<Object>(new RepositoryUtil.Updater(repository), project.getDisposed());
@@ -66,8 +69,6 @@ final class GitRepositoryUpdater implements Disposable, BulkFileListener {
}
}
-
-
@Override
public void dispose() {
if (myWatchRequest != null) {
@@ -92,19 +93,16 @@ final class GitRepositoryUpdater implements Disposable, BulkFileListener {
boolean packedRefsChanged = false;
boolean rebaseFileChanged = false;
boolean mergeFileChanged = false;
+ boolean tagChanged = false;
for (VFileEvent event : events) {
- String filePath = event.getPath();
- if (filePath == null) {
- continue;
- }
- filePath = GitFileUtils.stripFileProtocolPrefix(filePath);
+ String filePath = GitFileUtils.stripFileProtocolPrefix(event.getPath());
if (myRepositoryFiles.isConfigFile(filePath)) {
configChanged = true;
} else if (myRepositoryFiles.isHeadFile(filePath)) {
headChanged = true;
} else if (myRepositoryFiles.isBranchFile(filePath)) {
// it is also possible, that a local branch with complex name ("folder/branch") was created => the folder also to be watched.
- branchFileChanged = true;
+ branchFileChanged = true;
RepositoryUtil.visitAllChildrenRecursively(myHeadsDir);
} else if (myRepositoryFiles.isRemoteBranchFile(filePath)) {
// it is possible, that a branch from a new remote was fetch => we need to add new remote folder to the VFS
@@ -116,12 +114,18 @@ final class GitRepositoryUpdater implements Disposable, BulkFileListener {
rebaseFileChanged = true;
} else if (myRepositoryFiles.isMergeFile(filePath)) {
mergeFileChanged = true;
+ } else if (myRepositoryFiles.isTagFile(filePath)) {
+ RepositoryUtil.visitAllChildrenRecursively(myTagsDir);
+ tagChanged = true;
}
}
if (headChanged || configChanged || branchFileChanged || packedRefsChanged || rebaseFileChanged || mergeFileChanged) {
myUpdateQueue.add(DUMMY_UPDATE_OBJECT);
}
+ else if (tagChanged) {
+ myRepository.getProject().getMessageBus().syncPublisher(GitRepository.GIT_REPO_CHANGE).repositoryChanged(myRepository);
+ }
}
}
diff --git a/plugins/git4idea/src/git4idea/reset/GitResetAction.java b/plugins/git4idea/src/git4idea/reset/GitResetAction.java
index 749acd7e7c7c..97b5b4ffeae8 100644
--- a/plugins/git4idea/src/git4idea/reset/GitResetAction.java
+++ b/plugins/git4idea/src/git4idea/reset/GitResetAction.java
@@ -16,7 +16,6 @@
package git4idea.reset;
import com.intellij.dvcs.ui.VcsLogOneCommitPerRepoAction;
-import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
@@ -25,18 +24,19 @@ import com.intellij.util.ObjectUtils;
import com.intellij.vcs.log.VcsFullCommitDetails;
import git4idea.config.GitVcsSettings;
import git4idea.repo.GitRepository;
-import git4idea.repo.GitRepositoryManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
+import static git4idea.GitUtil.getRepositoryManager;
+
public class GitResetAction extends VcsLogOneCommitPerRepoAction<GitRepository> {
@Nullable
@Override
protected GitRepository getRepositoryForRoot(@NotNull Project project, @NotNull VirtualFile root) {
- return getRepoManager(project).getRepositoryForRoot(root);
+ return getRepositoryManager(project).getRepositoryForRoot(root);
}
@Override
@@ -57,9 +57,4 @@ public class GitResetAction extends VcsLogOneCommitPerRepoAction<GitRepository>
}
}
- @NotNull
- private static GitRepositoryManager getRepoManager(@NotNull Project project) {
- return ServiceManager.getService(project, GitRepositoryManager.class);
- }
-
}
diff --git a/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopup.java b/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopup.java
index 1cb7cf6a66c9..38188b2b7b21 100644
--- a/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopup.java
+++ b/plugins/git4idea/src/git4idea/ui/branch/GitBranchPopup.java
@@ -16,23 +16,14 @@
package git4idea.ui.branch;
import com.intellij.dvcs.DvcsUtil;
-import com.intellij.dvcs.ui.BranchActionGroupPopup;
+import com.intellij.dvcs.branch.DvcsBranchPopup;
+import com.intellij.dvcs.repo.AbstractRepositoryManager;
import com.intellij.dvcs.ui.RootAction;
-import com.intellij.notification.Notification;
-import com.intellij.notification.NotificationListener;
-import com.intellij.openapi.actionSystem.ActionGroup;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
-import com.intellij.openapi.options.ShowSettingsUtil;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.ui.popup.ListPopup;
import com.intellij.openapi.util.Condition;
-import com.intellij.openapi.vcs.VcsNotifier;
-import com.intellij.ui.popup.list.ListPopupImpl;
-import com.intellij.util.containers.ContainerUtil;
-import git4idea.GitLocalBranch;
import git4idea.GitUtil;
-import git4idea.GitVcs;
import git4idea.branch.GitBranchUtil;
import git4idea.config.GitVcsSettings;
import git4idea.repo.GitRepository;
@@ -41,51 +32,25 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
-import javax.swing.event.HyperlinkEvent;
import java.util.List;
/**
* The popup which allows to quickly switch and control Git branches.
* <p/>
*/
-class GitBranchPopup {
-
- private final Project myProject;
- private final GitRepositoryManager myRepositoryManager;
- private final GitVcsSettings myVcsSettings;
- private final GitVcs myVcs;
- private final GitMultiRootBranchConfig myMultiRootBranchConfig;
-
- private final GitRepository myCurrentRepository;
- private final ListPopupImpl myPopup;
-
- ListPopup asListPopup() {
- return myPopup;
- }
+class GitBranchPopup extends DvcsBranchPopup<GitRepository> {
/**
* @param currentRepository Current repository, which means the repository of the currently open or selected file.
* In the case of synchronized branch operations current repository matter much less, but sometimes is used,
* for example, it is preselected in the repositories combobox in the compare branches dialog.
*/
- static GitBranchPopup getInstance(@NotNull Project project, @NotNull GitRepository currentRepository) {
- return new GitBranchPopup(project, currentRepository);
- }
-
- private GitBranchPopup(@NotNull Project project, @NotNull GitRepository currentRepository) {
- myProject = project;
- myCurrentRepository = currentRepository;
- myRepositoryManager = GitUtil.getRepositoryManager(project);
- myVcs = GitVcs.getInstance(project);
- myVcsSettings = GitVcsSettings.getInstance(myProject);
-
- myMultiRootBranchConfig = new GitMultiRootBranchConfig(myRepositoryManager.getRepositories());
-
- String title = createPopupTitle(currentRepository);
-
+ static GitBranchPopup getInstance(@NotNull final Project project, @NotNull GitRepository currentRepository) {
+ final GitVcsSettings vcsSettings = GitVcsSettings.getInstance(project);
Condition<AnAction> preselectActionCondition = new Condition<AnAction>() {
@Override
public boolean value(AnAction action) {
+
if (action instanceof GitBranchPopupActions.LocalBranchActions) {
GitBranchPopupActions.LocalBranchActions branchAction = (GitBranchPopupActions.LocalBranchActions)action;
String branchName = branchAction.getBranchName();
@@ -93,10 +58,10 @@ class GitBranchPopup {
String recentBranch;
List<GitRepository> repositories = branchAction.getRepositories();
if (repositories.size() == 1) {
- recentBranch = myVcsSettings.getRecentBranchesByRepository().get(repositories.iterator().next().getRoot().getPath());
+ recentBranch = vcsSettings.getRecentBranchesByRepository().get(repositories.iterator().next().getRoot().getPath());
}
else {
- recentBranch = myVcsSettings.getRecentCommonBranch();
+ recentBranch = vcsSettings.getRecentCommonBranch();
}
if (recentBranch != null && recentBranch.equals(branchName)) {
@@ -106,37 +71,19 @@ class GitBranchPopup {
return false;
}
};
-
- myPopup = new BranchActionGroupPopup(title, project, preselectActionCondition, createActions());
-
- initBranchSyncPolicyIfNotInitialized();
- setCurrentBranchInfo();
- warnThatBranchesDivergedIfNeeded();
+ return new GitBranchPopup(currentRepository, GitUtil.getRepositoryManager(project), vcsSettings, preselectActionCondition);
}
- private void initBranchSyncPolicyIfNotInitialized() {
- if (myRepositoryManager.moreThanOneRoot() && myVcsSettings.getSyncSetting() == GitBranchSyncSetting.NOT_DECIDED) {
- if (!myMultiRootBranchConfig.diverged()) {
- notifyAboutSyncedBranches();
- myVcsSettings.setSyncSetting(GitBranchSyncSetting.SYNC);
- }
- else {
- myVcsSettings.setSyncSetting(GitBranchSyncSetting.DONT);
- }
- }
- }
-
- @NotNull
- private String createPopupTitle(@NotNull GitRepository currentRepository) {
- String title = "Git Branches";
- if (myRepositoryManager.moreThanOneRoot() &&
- (myMultiRootBranchConfig.diverged() || myVcsSettings.getSyncSetting() == GitBranchSyncSetting.DONT)) {
- title += " in " + DvcsUtil.getShortRepositoryName(currentRepository);
- }
- return title;
+ private GitBranchPopup(@NotNull GitRepository currentRepository,
+ @NotNull GitRepositoryManager repositoryManager,
+ @NotNull GitVcsSettings vcsSettings,
+ @NotNull Condition<AnAction> preselectActionCondition) {
+ super(currentRepository, repositoryManager, new GitMultiRootBranchConfig(repositoryManager.getRepositories()), vcsSettings,
+ preselectActionCondition);
}
- private void setCurrentBranchInfo() {
+ @Override
+ protected void setCurrentBranchInfo() {
String currentBranchText = "Current branch";
if (myRepositoryManager.moreThanOneRoot()) {
if (myMultiRootBranchConfig.diverged()) {
@@ -153,55 +100,16 @@ class GitBranchPopup {
myPopup.setAdText(currentBranchText, SwingConstants.CENTER);
}
- private void notifyAboutSyncedBranches() {
- String description = "You have several Git roots in the project and they all are checked out at the same branch. " +
- "We've enabled synchronous branch control for the project. <br/>" +
- "If you wish to control branches in different roots separately, " +
- "you may <a href='settings'>disable</a> the setting.";
- NotificationListener listener = new NotificationListener() {
- @Override
- public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) {
- if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
- ShowSettingsUtil.getInstance().showSettingsDialog(myProject, myVcs.getConfigurable().getDisplayName());
- if (myVcsSettings.getSyncSetting() == GitBranchSyncSetting.DONT) {
- notification.expire();
- }
- }
- }
- };
- VcsNotifier.getInstance(myProject).notifyImportantInfo("Synchronous branch control enabled", description, listener);
- }
-
- private ActionGroup createActions() {
- DefaultActionGroup popupGroup = new DefaultActionGroup(null, false);
- GitRepositoryManager repositoryManager = myRepositoryManager;
- if (repositoryManager.moreThanOneRoot()) {
- if (userWantsSyncControl()) {
- fillWithCommonRepositoryActions(popupGroup, repositoryManager);
- }
- else {
- fillPopupWithCurrentRepositoryActions(popupGroup, createRepositoriesActions());
- }
- }
- else {
- fillPopupWithCurrentRepositoryActions(popupGroup, null);
- }
- popupGroup.addSeparator();
- return popupGroup;
- }
-
- private boolean userWantsSyncControl() {
- return (myVcsSettings.getSyncSetting() != GitBranchSyncSetting.DONT);
- }
-
- private void fillWithCommonRepositoryActions(DefaultActionGroup popupGroup, GitRepositoryManager repositoryManager) {
+ @Override
+ protected void fillWithCommonRepositoryActions(@NotNull DefaultActionGroup popupGroup,
+ @NotNull AbstractRepositoryManager<GitRepository> repositoryManager) {
List<GitRepository> allRepositories = repositoryManager.getRepositories();
popupGroup.add(new GitBranchPopupActions.GitNewBranchAction(myProject, allRepositories));
popupGroup.addAll(createRepositoriesActions());
popupGroup.addSeparator("Common Local Branches");
- for (String branch : myMultiRootBranchConfig.getLocalBranches()) {
+ for (String branch : myMultiRootBranchConfig.getLocalBranchNames()) {
List<GitRepository> repositories = filterRepositoriesNotOnThisBranch(branch, allRepositories);
if (!repositories.isEmpty()) {
popupGroup.add(new GitBranchPopupActions.LocalBranchActions(myProject, repositories, branch, myCurrentRepository));
@@ -209,30 +117,14 @@ class GitBranchPopup {
}
popupGroup.addSeparator("Common Remote Branches");
- for (String branch : myMultiRootBranchConfig.getRemoteBranches()) {
+ for (String branch : ((GitMultiRootBranchConfig)myMultiRootBranchConfig).getRemoteBranches()) {
popupGroup.add(new GitBranchPopupActions.RemoteBranchActions(myProject, allRepositories, branch, myCurrentRepository));
}
}
@NotNull
- private static List<GitRepository> filterRepositoriesNotOnThisBranch(@NotNull final String branch,
- @NotNull List<GitRepository> allRepositories) {
- return ContainerUtil.filter(allRepositories, new Condition<GitRepository>() {
- @Override
- public boolean value(GitRepository repository) {
- GitLocalBranch currentBranch = repository.getCurrentBranch();
- return currentBranch == null || !branch.equals(currentBranch.getName());
- }
- });
- }
-
- private void warnThatBranchesDivergedIfNeeded() {
- if (myRepositoryManager.moreThanOneRoot() && myMultiRootBranchConfig.diverged() && userWantsSyncControl()) {
- myPopup.setWarning("Branches have diverged");
- }
- }
-
- private DefaultActionGroup createRepositoriesActions() {
+ @Override
+ protected DefaultActionGroup createRepositoriesActions() {
DefaultActionGroup popupGroup = new DefaultActionGroup(null, false);
popupGroup.addSeparator("Repositories");
for (GitRepository repository : myRepositoryManager.getRepositories()) {
@@ -243,11 +135,8 @@ class GitBranchPopup {
return popupGroup;
}
- private boolean highlightCurrentRepo() {
- return !userWantsSyncControl() || myMultiRootBranchConfig.diverged();
- }
-
- private void fillPopupWithCurrentRepositoryActions(@NotNull DefaultActionGroup popupGroup, @Nullable DefaultActionGroup actions) {
+ @Override
+ protected void fillPopupWithCurrentRepositoryActions(@NotNull DefaultActionGroup popupGroup, @Nullable DefaultActionGroup actions) {
popupGroup.addAll(new GitBranchPopupActions(myCurrentRepository.getProject(), myCurrentRepository).createActions(actions));
}
}
diff --git a/plugins/git4idea/src/git4idea/ui/branch/GitCompareBranchesDialog.java b/plugins/git4idea/src/git4idea/ui/branch/GitCompareBranchesDialog.java
index 89ff9f47268f..23588670048d 100644
--- a/plugins/git4idea/src/git4idea/ui/branch/GitCompareBranchesDialog.java
+++ b/plugins/git4idea/src/git4idea/ui/branch/GitCompareBranchesDialog.java
@@ -17,35 +17,46 @@ package git4idea.ui.branch;
import com.intellij.dvcs.DvcsUtil;
import com.intellij.icons.AllIcons;
+import com.intellij.openapi.diff.impl.dir.FrameDialogWrapper;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.ui.FrameWrapper;
import com.intellij.ui.TabbedPaneImpl;
import git4idea.GitUtil;
import git4idea.repo.GitRepository;
import git4idea.util.GitCommitCompareInfo;
import icons.Git4ideaIcons;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import javax.swing.*;
/**
* Dialog for comparing two Git branches.
*/
-public class GitCompareBranchesDialog extends FrameWrapper {
+public class GitCompareBranchesDialog extends FrameDialogWrapper {
@NotNull private final Project myProject;
- @NotNull private final String myBranchName;
- @NotNull private final String myCurrentBranchName;
- @NotNull private final GitCommitCompareInfo myCompareInfo;
+
@NotNull private final JPanel myLogPanel;
+ @NotNull private final TabbedPaneImpl myTabbedPane;
+ @NotNull private final String myTitle;
+
+ @NotNull private final Mode myMode;
- public GitCompareBranchesDialog(@NotNull Project project, @NotNull String branchName, @NotNull String currentBranchName,
- @NotNull GitCommitCompareInfo compareInfo, @NotNull GitRepository initialRepo) {
- super(project, GitCompareBranchesDialog.class.getName());
- myCurrentBranchName = currentBranchName;
- myCompareInfo = compareInfo;
+ public GitCompareBranchesDialog(@NotNull Project project,
+ @NotNull String branchName,
+ @NotNull String currentBranchName,
+ @NotNull GitCommitCompareInfo compareInfo,
+ @NotNull GitRepository initialRepo) {
+ this(project, branchName, currentBranchName, compareInfo, initialRepo, false);
+ }
+
+ public GitCompareBranchesDialog(@NotNull Project project,
+ @NotNull String branchName,
+ @NotNull String currentBranchName,
+ @NotNull GitCommitCompareInfo compareInfo,
+ @NotNull GitRepository initialRepo,
+ boolean dialog) {
myProject = project;
- myBranchName = branchName;
String rootString;
if (compareInfo.getRepositories().size() == 1 && GitUtil.getRepositoryManager(myProject).moreThanOneRoot()) {
@@ -54,23 +65,51 @@ public class GitCompareBranchesDialog extends FrameWrapper {
else {
rootString = "";
}
- setTitle(String.format("Comparing %s with %s%s", currentBranchName, branchName, rootString));
+ myTitle = String.format("Comparing %s with %s%s", currentBranchName, branchName, rootString);
+ myMode = dialog ? Mode.MODAL : Mode.FRAME;
+
+ JPanel diffPanel = new GitCompareBranchesDiffPanel(myProject, branchName, currentBranchName, compareInfo);
+ myLogPanel = new GitCompareBranchesLogPanel(myProject, branchName, currentBranchName, compareInfo, initialRepo);
- myLogPanel = new GitCompareBranchesLogPanel(myProject, myBranchName, myCurrentBranchName, myCompareInfo, initialRepo);
- setPreferredFocusedComponent(myLogPanel);
- setComponent(createCenterPanel());
- closeOnEsc();
+ myTabbedPane = new TabbedPaneImpl(SwingConstants.TOP);
+ myTabbedPane.addTab("Log", Git4ideaIcons.Branch, myLogPanel);
+ myTabbedPane.addTab("Diff", AllIcons.Actions.Diff, diffPanel);
+ myTabbedPane.setKeyboardNavigation(TabbedPaneImpl.DEFAULT_PREV_NEXT_SHORTCUTS);
}
@NotNull
- protected JComponent createCenterPanel() {
- JPanel diffPanel = new GitCompareBranchesDiffPanel(myProject, myBranchName, myCurrentBranchName, myCompareInfo);
-
- TabbedPaneImpl tabbedPane = new TabbedPaneImpl(SwingConstants.TOP);
- tabbedPane.addTab("Log", Git4ideaIcons.Branch, myLogPanel);
- tabbedPane.addTab("Diff", AllIcons.Actions.Diff, diffPanel);
- tabbedPane.setKeyboardNavigation(TabbedPaneImpl.DEFAULT_PREV_NEXT_SHORTCUTS);
- return tabbedPane;
+ @Override
+ protected JComponent getPanel() {
+ return myTabbedPane;
+ }
+
+ @Nullable
+ @Override
+ protected JComponent getPreferredFocusedComponent() {
+ return myLogPanel;
+ }
+
+ @Nullable
+ @Override
+ protected String getDimensionServiceKey() {
+ return GitCompareBranchesDialog.class.getName();
}
+ @NotNull
+ @Override
+ protected String getTitle() {
+ return myTitle;
+ }
+
+ @NotNull
+ @Override
+ protected Project getProject() {
+ return myProject;
+ }
+
+ @NotNull
+ @Override
+ protected Mode getMode() {
+ return myMode;
+ }
}
diff --git a/plugins/git4idea/src/git4idea/ui/branch/GitMultiRootBranchConfig.java b/plugins/git4idea/src/git4idea/ui/branch/GitMultiRootBranchConfig.java
index ba4dd2aab369..18076a1b9a61 100644
--- a/plugins/git4idea/src/git4idea/ui/branch/GitMultiRootBranchConfig.java
+++ b/plugins/git4idea/src/git4idea/ui/branch/GitMultiRootBranchConfig.java
@@ -15,8 +15,8 @@
*/
package git4idea.ui.branch;
+import com.intellij.dvcs.branch.DvcsMultiRootBranchConfig;
import com.intellij.util.containers.ContainerUtil;
-import git4idea.GitBranch;
import git4idea.GitLocalBranch;
import git4idea.GitRemoteBranch;
import git4idea.branch.GitBranchUtil;
@@ -32,54 +32,17 @@ import java.util.Collections;
/**
* @author Kirill Likhodedov
*/
-public class GitMultiRootBranchConfig {
-
- private final Collection<GitRepository> myRepositories;
+public class GitMultiRootBranchConfig extends DvcsMultiRootBranchConfig<GitRepository> {
public GitMultiRootBranchConfig(@NotNull Collection<GitRepository> repositories) {
- myRepositories = repositories;
+ super(repositories);
}
- boolean diverged() {
- return getCurrentBranch() == null;
- }
-
- @Nullable
- public String getCurrentBranch() {
- String commonBranch = null;
- for (GitRepository repository : myRepositories) {
- GitBranch branch = repository.getCurrentBranch();
- if (branch == null) {
- return null;
- }
- // NB: if all repositories are in the rebasing state on the same branches, this branch is returned
- if (commonBranch == null) {
- commonBranch = branch.getName();
- } else if (!commonBranch.equals(branch.getName())) {
- return null;
- }
- }
- return commonBranch;
- }
-
- @Nullable
- GitRepository.State getState() {
- GitRepository.State commonState = null;
- for (GitRepository repository : myRepositories) {
- GitRepository.State state = repository.getState();
- if (commonState == null) {
- commonState = state;
- } else if (!commonState.equals(state)) {
- return null;
- }
- }
- return commonState;
- }
-
+ @Override
@NotNull
- Collection<String> getLocalBranches() {
+ public Collection<String> getLocalBranchNames() {
return GitBranchUtil.getCommonBranches(myRepositories, true);
- }
+ }
@NotNull
Collection<String> getRemoteBranches() {
diff --git a/plugins/git4idea/src/git4idea/validators/GitNewBranchNameValidator.java b/plugins/git4idea/src/git4idea/validators/GitNewBranchNameValidator.java
index 69b06d04cc9b..40beb2686f84 100644
--- a/plugins/git4idea/src/git4idea/validators/GitNewBranchNameValidator.java
+++ b/plugins/git4idea/src/git4idea/validators/GitNewBranchNameValidator.java
@@ -51,7 +51,7 @@ public final class GitNewBranchNameValidator implements InputValidatorEx {
}
@Override
- public boolean checkInput(String inputString) {
+ public boolean checkInput(@NotNull String inputString) {
if (!GitRefNameValidator.getInstance().checkInput(inputString)){
myErrorText = "Invalid name for branch";
return false;
@@ -59,7 +59,7 @@ public final class GitNewBranchNameValidator implements InputValidatorEx {
return checkBranchConflict(inputString);
}
- private boolean checkBranchConflict(String inputString) {
+ private boolean checkBranchConflict(@NotNull String inputString) {
if (isNotPermitted(inputString) || conflictsWithLocalBranch(inputString) || conflictsWithRemoteBranch(inputString)) {
return false;
}
@@ -75,28 +75,38 @@ public final class GitNewBranchNameValidator implements InputValidatorEx {
return false;
}
- private boolean conflictsWithLocalBranch(String inputString) {
+ private boolean conflictsWithLocalBranch(@NotNull String inputString) {
return conflictsWithLocalOrRemote(inputString, true, " already exists");
}
- private boolean conflictsWithRemoteBranch(String inputString) {
+ private boolean conflictsWithRemoteBranch(@NotNull String inputString) {
return conflictsWithLocalOrRemote(inputString, false, " clashes with remote branch with the same name");
}
- private boolean conflictsWithLocalOrRemote(String inputString, boolean local, String message) {
+ private boolean conflictsWithLocalOrRemote(@NotNull String inputString, boolean local, @NotNull String message) {
+ int conflictsWithCurrentName = 0;
for (GitRepository repository : myRepositories) {
- GitBranchesCollection branchesCollection = repository.getBranches();
- Collection<? extends GitBranch> branches = local ? branchesCollection.getLocalBranches() : branchesCollection.getRemoteBranches();
- for (GitBranch branch : branches) {
- if (branch.getName().equals(inputString)) {
- myErrorText = "Branch name " + inputString + message;
- if (myRepositories.size() > 1 && !allReposHaveBranch(inputString, local)) {
- myErrorText += " in repository " + repository.getPresentableUrl();
+ if (inputString.equals(repository.getCurrentBranchName())) {
+ conflictsWithCurrentName++;
+ }
+ else {
+ GitBranchesCollection branchesCollection = repository.getBranches();
+ Collection<? extends GitBranch> branches = local ? branchesCollection.getLocalBranches() : branchesCollection.getRemoteBranches();
+ for (GitBranch branch : branches) {
+ if (branch.getName().equals(inputString)) {
+ myErrorText = "Branch name " + inputString + message;
+ if (myRepositories.size() > 1 && !allReposHaveBranch(inputString, local)) {
+ myErrorText += " in repository " + repository.getPresentableUrl();
+ }
+ return true;
}
- return true;
}
}
}
+ if (conflictsWithCurrentName == myRepositories.size()) {
+ myErrorText = "You are already on branch " + inputString;
+ return true;
+ }
return false;
}
diff --git a/plugins/git4idea/tests/git4idea/log/GitLogProviderTest.java b/plugins/git4idea/tests/git4idea/log/GitLogProviderTest.java
index 0bb67671622b..313852f118b0 100644
--- a/plugins/git4idea/tests/git4idea/log/GitLogProviderTest.java
+++ b/plugins/git4idea/tests/git4idea/log/GitLogProviderTest.java
@@ -15,13 +15,13 @@
*/
package git4idea.log;
+import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.util.ArrayUtil;
import com.intellij.util.CollectConsumer;
-import com.intellij.util.Consumer;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.vcs.log.*;
@@ -40,7 +40,8 @@ import static git4idea.test.GitExecutor.*;
public class GitLogProviderTest extends GitSingleRepoTest {
- @NotNull private GitLogProvider myLogProvider;
+ private GitLogProvider myLogProvider;
+ private VcsLogObjectsFactory myObjectsFactory;
public void setUp() throws Exception {
super.setUp();
@@ -53,6 +54,7 @@ public class GitLogProviderTest extends GitSingleRepoTest {
});
assertEquals("Incorrect number of GitLogProviders", 1, providers.size());
myLogProvider = (GitLogProvider)providers.get(0);
+ myObjectsFactory = ServiceManager.getService(myProject, VcsLogObjectsFactory.class);
}
public void tearDown() throws Exception {
@@ -64,21 +66,51 @@ public class GitLogProviderTest extends GitSingleRepoTest {
List<VcsCommitMetadata> expectedLogWithoutTaggedBranch = log();
createTaggedBranch();
- Set<VcsRef> noRefs = Collections.emptySet();
- List<? extends VcsCommitMetadata> block = myLogProvider.readFirstBlock(myProjectRoot, new RequirementsImpl(1000, false, noRefs, noRefs));
- assertOrderedEquals(block, expectedLogWithoutTaggedBranch);
+ VcsLogProvider.DetailedLogData block = myLogProvider.readFirstBlock(myProjectRoot,new RequirementsImpl(1000, false, Collections.<VcsRef>emptySet()));
+ assertOrderedEquals(block.getCommits(), expectedLogWithoutTaggedBranch);
}
public void test_refresh_with_new_tagged_branch() throws VcsException {
prepareSomeHistory();
- Set<VcsRef> prevRefs = ContainerUtil.newHashSet(myLogProvider.readAllRefs(myProjectRoot));
+ Set<VcsRef> prevRefs = readAllRefs();
createTaggedBranch();
- Set<VcsRef> newRefs = ContainerUtil.newHashSet(myLogProvider.readAllRefs(myProjectRoot));
List<VcsCommitMetadata> expectedLog = log();
- List<? extends VcsCommitMetadata> block = myLogProvider.readFirstBlock(myProjectRoot,
- new RequirementsImpl(1000, true, prevRefs, newRefs));
- assertSameElements(block, expectedLog);
+ VcsLogProvider.DetailedLogData block = myLogProvider.readFirstBlock(myProjectRoot, new RequirementsImpl(1000, true, prevRefs));
+ assertSameElements(block.getCommits(), expectedLog);
+ }
+
+ public void test_refresh_when_new_tag_moved() throws VcsException {
+ prepareSomeHistory();
+ Set<VcsRef> prevRefs = readAllRefs();
+ git("tag -f ATAG");
+
+ List<VcsCommitMetadata> expectedLog = log();
+ Set<VcsRef> refs = readAllRefs();
+ VcsLogProvider.DetailedLogData block = myLogProvider.readFirstBlock(myProjectRoot, new RequirementsImpl(1000, true, prevRefs));
+ assertSameElements(block.getCommits(), expectedLog);
+ assertSameElements(block.getRefs(), refs);
+ }
+
+ public void test_new_tag_on_old_commit() throws VcsException {
+ prepareSomeHistory();
+ Set<VcsRef> prevRefs = readAllRefs();
+ List<VcsCommitMetadata> log = log();
+ String firstCommit = log.get(log.size() - 1).getId().asString();
+ git("tag NEW_TAG " + firstCommit);
+
+ Set<VcsRef> refs = readAllRefs();
+ VcsLogProvider.DetailedLogData block = myLogProvider.readFirstBlock(myProjectRoot, new RequirementsImpl(1000, true, prevRefs));
+ assertSameElements(block.getRefs(), refs);
+ }
+
+ private Set<VcsRef> readAllRefs() {
+ String[] refs = StringUtil.splitByLines(git("log --branches --tags --no-walk --format=%H%d --decorate=full"));
+ Set<VcsRef> result = ContainerUtil.newHashSet();
+ for (String ref : refs) {
+ result.addAll(new RefParser(myObjectsFactory).parseCommitRefs(ref, myProjectRoot));
+ }
+ return result;
}
public void test_all_log_with_tagged_branch() throws VcsException {
@@ -87,7 +119,7 @@ public class GitLogProviderTest extends GitSingleRepoTest {
List<VcsCommitMetadata> expectedLog = log();
List<TimedVcsCommit> collector = ContainerUtil.newArrayList();
//noinspection unchecked
- myLogProvider.readAllHashes(myProjectRoot, Consumer.EMPTY_CONSUMER, new CollectConsumer<TimedVcsCommit>(collector));
+ myLogProvider.readAllHashes(myProjectRoot, new CollectConsumer<TimedVcsCommit>(collector));
assertOrderedEquals(expectedLog, collector);
}
diff --git a/plugins/git4idea/tests/git4idea/log/GitRefManagerTest.java b/plugins/git4idea/tests/git4idea/log/GitRefManagerTest.java
index 2ce560800066..39d5946c90ff 100644
--- a/plugins/git4idea/tests/git4idea/log/GitRefManagerTest.java
+++ b/plugins/git4idea/tests/git4idea/log/GitRefManagerTest.java
@@ -286,6 +286,12 @@ public class GitRefManagerTest extends UsefulTestCase {
@Nullable
@Override
+ public String getCurrentBranchName() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Nullable
+ @Override
public AbstractVcs getVcs() {
return null;
}
diff --git a/plugins/git4idea/src/git4idea/log/RefParser.java b/plugins/git4idea/tests/git4idea/log/RefParser.java
index 619cfcd5d4da..9a4cc962c6e7 100644
--- a/plugins/git4idea/src/git4idea/log/RefParser.java
+++ b/plugins/git4idea/tests/git4idea/log/RefParser.java
@@ -4,7 +4,9 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.vcs.log.Hash;
import com.intellij.vcs.log.VcsLogObjectsFactory;
import com.intellij.vcs.log.VcsRef;
+import com.intellij.vcs.log.VcsRefType;
import com.intellij.vcs.log.impl.HashImpl;
+import git4idea.branch.GitBranchUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -12,17 +14,11 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-
-/**
- * TODO: remove when tags are supported by the {@link git4idea.repo.GitRepositoryReader}.
- *
- * @author erokhins
- */
class RefParser {
private final VcsLogObjectsFactory myFactory;
- public RefParser(VcsLogObjectsFactory factory) {
+ public RefParser(@NotNull VcsLogObjectsFactory factory) {
myFactory = factory;
}
@@ -46,28 +42,22 @@ class RefParser {
return refs;
}
- @Nullable
- private static String getRefName(@NotNull String longRefPath, @NotNull String startPatch) {
+ @NotNull
+ private static String getRefName(@NotNull String longRefPath) {
String tagPrefix = "tag: ";
if (longRefPath.startsWith(tagPrefix)) {
longRefPath = longRefPath.substring(tagPrefix.length());
}
- if (longRefPath.startsWith(startPatch)) {
- return longRefPath.substring(startPatch.length());
- }
- else {
- return null;
- }
+ return longRefPath;
}
// example input: fb29c80 refs/tags/92.29
@Nullable
private VcsRef createRef(@NotNull Hash hash, @NotNull String longRefPath, @NotNull VirtualFile root) {
- String name = getRefName(longRefPath, "refs/tags/");
- if (name != null) {
- return myFactory.createRef(hash, name, GitRefManager.TAG, root);
- }
-
- return null;
+ String name = getRefName(longRefPath);
+ VcsRefType type = GitRefManager.getRefType(name);
+ assert type != null;
+ return myFactory.createRef(hash, GitBranchUtil.stripRefsPrefix(name), type, root);
}
+
}
diff --git a/plugins/git4idea/tests/git4idea/log/RefParserTest.java b/plugins/git4idea/tests/git4idea/log/RefParserTest.java
deleted file mode 100644
index 4cd22e0add5c..000000000000
--- a/plugins/git4idea/tests/git4idea/log/RefParserTest.java
+++ /dev/null
@@ -1,125 +0,0 @@
-package git4idea.log;
-
-import com.intellij.openapi.util.ThrowableComputable;
-import com.intellij.openapi.vcs.changes.Change;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.openapi.vfs.newvfs.impl.NullVirtualFile;
-import com.intellij.vcs.log.*;
-import com.intellij.vcs.log.impl.VcsRefImpl;
-import org.jetbrains.annotations.NotNull;
-import org.junit.Test;
-
-import java.util.Collection;
-import java.util.List;
-
-import static junit.framework.Assert.assertEquals;
-
-/**
- * @author erokhins
- */
-public class RefParserTest {
-
- public String toStr(VcsRef ref) {
- return String.format("%s TAG %s", ref.getCommitHash().asString(), ref.getName());
- }
-
- public void runTest(String inputStr, String outStr) {
- List<VcsRef> refs = new RefParser(new TestLogObjectsFactory()).parseCommitRefs(inputStr, NullVirtualFile.INSTANCE);
- StringBuilder s = new StringBuilder();
- for (VcsRef ref : refs) {
- if (s.length() > 0) {
- s.append("\n");
- }
- s.append(toStr(ref));
- }
- assertEquals(outStr, s.toString());
- }
-
- @Test
- public void tagTest() {
- runTest("22762ebf7203f6a2888425a3207d2ddc63085dd7 (tag: refs/tags/v3.6-rc1, refs/heads/br)",
- "22762ebf7203f6a2888425a3207d2ddc63085dd7 TAG v3.6-rc1");
- }
-
- @Test
- public void severalRefsTest() {
- runTest("f85125c (refs/tags/v3.6-rc1, HEAD)", "f85125c TAG v3.6-rc1");
- }
-
- @Test
- public void severalRefsTest2() {
- runTest("ed7a0d14da090ea256d68a06c6f8dd7311de192e (refs/tags/category/v3.6-rc1, HEAD, refs/remotes/origin/graph_fix)",
- "ed7a0d14da090ea256d68a06c6f8dd7311de192e TAG category/v3.6-rc1");
- }
-
- @Test
- public void severalRefsTest3() {
- runTest("ed7a0d14da090ea256d68a06c6f8dd7311de192e (tag: refs/tags/web/130.1599, tag: refs/tags/ruby/130.1597, " +
- "tag: refs/tags/py/130.1598, " +
- "tag: refs/tags/php/130.1596, tag: refs/tags/idea/130.1601, tag: refs/tags/app/130.1600)",
- "ed7a0d14da090ea256d68a06c6f8dd7311de192e TAG web/130.1599\n" +
- "ed7a0d14da090ea256d68a06c6f8dd7311de192e TAG ruby/130.1597\n" +
- "ed7a0d14da090ea256d68a06c6f8dd7311de192e TAG py/130.1598\n" +
- "ed7a0d14da090ea256d68a06c6f8dd7311de192e TAG php/130.1596\n" +
- "ed7a0d14da090ea256d68a06c6f8dd7311de192e TAG idea/130.1601\n" +
- "ed7a0d14da090ea256d68a06c6f8dd7311de192e TAG app/130.1600"
- );
- }
-
- @Test
- public void noTagName() {
- runTest("787ec72f340d740433ba068d4d58a6e58f6226bf", "");
- }
-
- private static class TestLogObjectsFactory implements VcsLogObjectsFactory {
- @NotNull
- @Override
- public Hash createHash(@NotNull String stringHash) {
- throw new UnsupportedOperationException();
- }
-
- @NotNull
- @Override
- public TimedVcsCommit createTimedCommit(@NotNull Hash hash, @NotNull List<Hash> parents, long timeStamp) {
- throw new UnsupportedOperationException();
- }
-
- @NotNull
- @Override
- public VcsShortCommitDetails createShortDetails(@NotNull Hash hash, @NotNull List<Hash> parents, long timeStamp, VirtualFile root,
- @NotNull String subject, @NotNull String authorName, String authorEmail) {
- throw new UnsupportedOperationException();
- }
-
- @NotNull
- @Override
- public VcsFullCommitDetails createCommitMetadata(@NotNull Hash hash, @NotNull List<Hash> parents, long time, VirtualFile root,
- @NotNull String subject, @NotNull String authorName, @NotNull String authorEmail,
- @NotNull String message, @NotNull String committerName, @NotNull String committerEmail,
- long authorTime) {
- throw new UnsupportedOperationException();
- }
-
- @NotNull
- @Override
- public VcsFullCommitDetails createFullDetails(@NotNull Hash hash, @NotNull List<Hash> parents, long time, VirtualFile root,
- @NotNull String subject, @NotNull String authorName, @NotNull String authorEmail,
- @NotNull String message, @NotNull String committerName, @NotNull String committerEmail,
- long authorTime,
- @NotNull ThrowableComputable<Collection<Change>, ? extends Exception> changesGetter) {
- throw new UnsupportedOperationException();
- }
-
- @NotNull
- @Override
- public VcsUser createUser(@NotNull String name, @NotNull String email) {
- throw new UnsupportedOperationException();
- }
-
- @NotNull
- @Override
- public VcsRef createRef(@NotNull Hash commitHash, @NotNull String name, @NotNull VcsRefType type, @NotNull VirtualFile root) {
- return new VcsRefImpl(commitHash, name, type, root);
- }
- }
-}
diff --git a/plugins/github/github.iml b/plugins/github/github.iml
index 7866631c1521..1b14d6b1e8a9 100644
--- a/plugins/github/github.iml
+++ b/plugins/github/github.iml
@@ -11,7 +11,7 @@
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="vcs-api" />
<orderEntry type="module" module-name="git4idea" />
- <orderEntry type="library" name="http-client-3.1" level="project" />
+ <orderEntry type="library" name="http-client" level="project" />
<orderEntry type="module" module-name="vcs-impl" />
<orderEntry type="module" module-name="tasks-core" exported="" />
<orderEntry type="module" module-name="tasks-api" exported="" />
diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubCreateGistAction.java b/plugins/github/src/org/jetbrains/plugins/github/GithubCreateGistAction.java
index 43753142a5b2..ae7b271ce3d6 100644
--- a/plugins/github/src/org/jetbrains/plugins/github/GithubCreateGistAction.java
+++ b/plugins/github/src/org/jetbrains/plugins/github/GithubCreateGistAction.java
@@ -38,6 +38,7 @@ import icons.GithubIcons;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.github.api.GithubApiUtil;
+import org.jetbrains.plugins.github.api.GithubConnection;
import org.jetbrains.plugins.github.api.GithubGist;
import org.jetbrains.plugins.github.exceptions.GithubOperationCanceledException;
import org.jetbrains.plugins.github.ui.GithubCreateGistDialog;
@@ -219,11 +220,11 @@ public class GithubCreateGistAction extends DumbAwareAction {
}
try {
final List<FileContent> finalContents = contents;
- return GithubUtil.runTask(project, auth, indicator, new ThrowableConvertor<GithubAuthData, GithubGist, IOException>() {
+ return GithubUtil.runTask(project, auth, indicator, new ThrowableConvertor<GithubConnection, GithubGist, IOException>() {
@NotNull
@Override
- public GithubGist convert(@NotNull GithubAuthData auth) throws IOException {
- return GithubApiUtil.createGist(auth, finalContents, description, isPrivate);
+ public GithubGist convert(@NotNull GithubConnection connection) throws IOException {
+ return GithubApiUtil.createGist(connection, finalContents, description, isPrivate);
}
}).getHtmlUrl();
}
diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestAction.java b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestAction.java
index 636415e5fcb6..d3fa265dc389 100644
--- a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestAction.java
+++ b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestAction.java
@@ -26,7 +26,7 @@ import icons.GithubIcons;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.github.ui.GithubCreatePullRequestDialog;
-import org.jetbrains.plugins.github.util.*;
+import org.jetbrains.plugins.github.util.GithubUtil;
import static org.jetbrains.plugins.github.util.GithubUtil.setVisibleEnabled;
@@ -73,12 +73,12 @@ public class GithubCreatePullRequestAction extends DumbAwareAction {
}
static void createPullRequest(@NotNull Project project, @Nullable VirtualFile file) {
- GithubCreatePullRequestWorker worker = GithubCreatePullRequestWorker.createPullRequestWorker(project, file);
+ GithubCreatePullRequestWorker worker = GithubCreatePullRequestWorker.create(project, file);
if (worker == null) {
return;
}
- GithubCreatePullRequestDialog dialog = new GithubCreatePullRequestDialog(worker);
+ GithubCreatePullRequestDialog dialog = new GithubCreatePullRequestDialog(project, worker);
DialogManager.show(dialog);
}
} \ No newline at end of file
diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java
index bf9803b6f46f..07ed51bfca7d 100644
--- a/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java
+++ b/plugins/github/src/org/jetbrains/plugins/github/GithubCreatePullRequestWorker.java
@@ -1,30 +1,16 @@
-/*
- * Copyright 2000-2014 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
package org.jetbrains.plugins.github;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.progress.EmptyProgressIndicator;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Couple;
import com.intellij.openapi.util.Pair;
-import com.intellij.openapi.util.Ref;
+import com.intellij.openapi.util.ThrowableComputable;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.Change;
@@ -34,11 +20,10 @@ import com.intellij.util.Function;
import com.intellij.util.ThrowableConvertor;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.Convertor;
-import com.intellij.util.containers.HashMap;
+import com.intellij.vcs.log.VcsCommitMetadata;
import git4idea.DialogManager;
import git4idea.GitCommit;
import git4idea.GitLocalBranch;
-import git4idea.GitRemoteBranch;
import git4idea.changes.GitChangeUtils;
import git4idea.commands.Git;
import git4idea.commands.GitCommandResult;
@@ -52,18 +37,19 @@ import git4idea.util.GitCommitCompareInfo;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.github.api.*;
+import org.jetbrains.plugins.github.exceptions.GithubOperationCanceledException;
import org.jetbrains.plugins.github.ui.GithubSelectForkDialog;
import org.jetbrains.plugins.github.util.*;
import java.io.IOException;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
import java.util.concurrent.Callable;
+import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
-/**
- * @author Aleksey Pivovarov
- */
public class GithubCreatePullRequestWorker {
private static final Logger LOG = GithubUtil.LOG;
private static final String CANNOT_CREATE_PULL_REQUEST = "Can't Create Pull Request";
@@ -71,40 +57,36 @@ public class GithubCreatePullRequestWorker {
@NotNull private final Project myProject;
@NotNull private final Git myGit;
@NotNull private final GitRepository myGitRepository;
+ @NotNull private final GithubAuthDataHolder myAuthHolder;
+
@NotNull private final GithubFullPath myPath;
@NotNull private final String myRemoteName;
@NotNull private final String myRemoteUrl;
@NotNull private final String myCurrentBranch;
- @NotNull private final GithubAuthDataHolder myAuthHolder;
- @NotNull private final Map<String, FutureTask<DiffInfo>> myDiffInfos;
+ @NotNull private GithubFullPath mySource;
- private volatile GithubFullPath myForkPath;
- private volatile String myTargetRemote;
+ @NotNull private final List<ForkInfo> myForks;
+ @Nullable private List<GithubFullPath> myAvailableForks;
private GithubCreatePullRequestWorker(@NotNull Project project,
@NotNull Git git,
@NotNull GitRepository gitRepository,
+ @NotNull GithubAuthDataHolder authHolder,
@NotNull GithubFullPath path,
@NotNull String remoteName,
@NotNull String remoteUrl,
- @NotNull String currentBranch,
- @NotNull GithubAuthDataHolder authHolder) {
+ @NotNull String currentBranch) {
myProject = project;
myGit = git;
myGitRepository = gitRepository;
+ myAuthHolder = authHolder;
myPath = path;
myRemoteName = remoteName;
myRemoteUrl = remoteUrl;
myCurrentBranch = currentBranch;
- myAuthHolder = authHolder;
-
- myDiffInfos = new HashMap<String, FutureTask<DiffInfo>>();
- }
- @NotNull
- public Project getProject() {
- return myProject;
+ myForks = new ArrayList<ForkInfo>();
}
@NotNull
@@ -112,231 +94,416 @@ public class GithubCreatePullRequestWorker {
return myCurrentBranch;
}
- public boolean canShowDiff() {
- return myTargetRemote != null;
+ @NotNull
+ public List<ForkInfo> getForks() {
+ return myForks;
}
@Nullable
- public static GithubCreatePullRequestWorker createPullRequestWorker(@NotNull final Project project, @Nullable final VirtualFile file) {
- Git git = ServiceManager.getService(Git.class);
+ public static GithubCreatePullRequestWorker create(@NotNull final Project project, @Nullable final VirtualFile file) {
+ return GithubUtil.computeValueInModal(project, "Loading data...", new Convertor<ProgressIndicator, GithubCreatePullRequestWorker>() {
+ @Override
+ public GithubCreatePullRequestWorker convert(ProgressIndicator indicator) {
+ Git git = ServiceManager.getService(Git.class);
- GitRepository gitRepository = GithubUtil.getGitRepository(project, file);
- if (gitRepository == null) {
- GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, "Can't find git repository");
- return null;
+ GitRepository gitRepository = GithubUtil.getGitRepository(project, file);
+ if (gitRepository == null) {
+ GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, "Can't find git repository");
+ return null;
+ }
+ gitRepository.update();
+
+ Pair<GitRemote, String> remote = GithubUtil.findGithubRemote(gitRepository);
+ if (remote == null) {
+ GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, "Can't find GitHub remote");
+ return null;
+ }
+ String remoteName = remote.getFirst().getName();
+ String remoteUrl = remote.getSecond();
+
+ GithubFullPath path = GithubUrlUtil.getUserAndRepositoryFromRemoteUrl(remoteUrl);
+ if (path == null) {
+ GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, "Can't process remote: " + remoteUrl);
+ return null;
+ }
+
+ GitLocalBranch currentBranch = gitRepository.getCurrentBranch();
+ if (currentBranch == null) {
+ GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, "No current branch");
+ return null;
+ }
+
+ GithubAuthDataHolder authHolder;
+ try {
+ authHolder = GithubUtil.getValidAuthDataHolderFromConfig(project, indicator);
+ }
+ catch (IOException e) {
+ GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, e);
+ return null;
+ }
+
+ GithubCreatePullRequestWorker worker =
+ new GithubCreatePullRequestWorker(project, git, gitRepository, authHolder, path, remoteName, remoteUrl, currentBranch.getName());
+
+ try {
+ worker.initForks(indicator);
+ }
+ catch (IOException e) {
+ GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, e);
+ return null;
+ }
+
+ return worker;
+ }
+ });
+ }
+
+ private void initForks(@NotNull ProgressIndicator indicator) throws IOException {
+ doLoadForksFromGithub(indicator);
+ doLoadForksFromGit(indicator);
+ doLoadForksFromSettings(indicator);
+ }
+
+ @Nullable
+ private ForkInfo doAddFork(@NotNull GithubFullPath path,
+ @Nullable String remoteName,
+ @NotNull ProgressIndicator indicator) {
+ for (ForkInfo fork : myForks) {
+ if (fork.getPath().equals(path)) {
+ if (fork.getRemoteName() == null && remoteName != null) {
+ fork.setRemoteName(remoteName);
+ }
+ return fork;
+ }
}
- gitRepository.update();
- Pair<GitRemote, String> remote = GithubUtil.findGithubRemote(gitRepository);
- if (remote == null) {
- GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, "Can't find GitHub remote");
- return null;
+ try {
+ List<String> branches = loadBranches(path, indicator);
+ String defaultBranch = doLoadDefaultBranch(path, indicator);
+
+ ForkInfo fork = new ForkInfo(path, branches, defaultBranch);
+ myForks.add(fork);
+ if (remoteName != null) {
+ fork.setRemoteName(remoteName);
+ }
+ return fork;
}
- String remoteName = remote.getFirst().getName();
- String remoteUrl = remote.getSecond();
- GithubFullPath path = GithubUrlUtil.getUserAndRepositoryFromRemoteUrl(remoteUrl);
- if (path == null) {
- GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, "Can't process remote: " + remoteUrl);
+ catch (IOException e) {
+ GithubNotifications.showWarning(myProject, "Can't load branches for " + path.getFullName(), e);
return null;
}
+ }
- GitLocalBranch currentBranch = gitRepository.getCurrentBranch();
- if (currentBranch == null) {
- GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, "No current branch");
- return null;
+ @Nullable
+ private ForkInfo doAddFork(@NotNull GithubRepo repo, @NotNull ProgressIndicator indicator) {
+ GithubFullPath path = repo.getFullPath();
+ for (ForkInfo fork : myForks) {
+ if (fork.getPath().equals(path)) {
+ return fork;
+ }
}
- GithubAuthDataHolder authHolder;
try {
- authHolder = GithubUtil
- .computeValueInModal(project, "Access to GitHub", new ThrowableConvertor<ProgressIndicator, GithubAuthDataHolder, IOException>() {
- @NotNull
- @Override
- public GithubAuthDataHolder convert(ProgressIndicator indicator) throws IOException {
- return GithubUtil.getValidAuthDataHolderFromConfig(project, indicator);
- }
- });
+ List<String> branches = loadBranches(path, indicator);
+ String defaultBranch = repo.getDefaultBranch();
+
+ ForkInfo fork = new ForkInfo(path, branches, defaultBranch);
+ myForks.add(fork);
+ return fork;
}
catch (IOException e) {
- GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, e);
+ GithubNotifications.showWarning(myProject, "Can't load branches for " + path.getFullName(), e);
return null;
}
+ }
- return new GithubCreatePullRequestWorker(project, git, gitRepository, path, remoteName, remoteUrl, currentBranch.getName(), authHolder);
+ private void doLoadForksFromSettings(@NotNull ProgressIndicator indicator) throws IOException {
+ GithubFullPath savedRepo = GithubProjectSettings.getInstance(myProject).getCreatePullRequestDefaultRepo();
+ if (savedRepo != null) {
+ doAddFork(savedRepo, null, indicator);
+ }
}
- @Nullable
- public GithubTargetInfo setTarget(@NotNull final GithubFullPath forkPath) {
- try {
- GithubInfo info =
- GithubUtil.computeValueInModal(myProject, "Access to GitHub", new ThrowableConvertor<ProgressIndicator, GithubInfo, IOException>() {
- @NotNull
- @Override
- public GithubInfo convert(ProgressIndicator indicator) throws IOException {
- // configure remote
- GitRemote targetRemote = GithubUtil.findGithubRemote(myGitRepository, forkPath);
- String targetRemoteName = targetRemote == null ? null : targetRemote.getName();
- if (targetRemoteName == null) {
- final Ref<Integer> responseRef = new Ref<Integer>();
- ApplicationManager.getApplication().invokeAndWait(new Runnable() {
- @Override
- public void run() {
- responseRef.set(GithubNotifications
- .showYesNoDialog(myProject, "Can't Find Remote", "Configure remote for '" + forkPath.getUser() + "'?"));
- }
- }, indicator.getModalityState());
- if (responseRef.get() == Messages.YES) {
- targetRemoteName = configureRemote(myProject, myGitRepository, forkPath);
- }
- }
+ private void doLoadForksFromGit(@NotNull ProgressIndicator indicator) {
+ for (GitRemote remote : myGitRepository.getRemotes()) {
+ for (String url : remote.getUrls()) {
+ if (GithubUrlUtil.isGithubUrl(url)) {
+ GithubFullPath path = GithubUrlUtil.getUserAndRepositoryFromRemoteUrl(url);
+ if (path != null) {
+ doAddFork(path, remote.getName(), indicator);
+ break;
+ }
+ }
+ }
+ }
+ }
- // load available branches
- List<String> branches = ContainerUtil.map(GithubUtil.runTask(myProject, myAuthHolder, indicator,
- new ThrowableConvertor<GithubAuthData, List<GithubBranch>, IOException>() {
- @Override
- public List<GithubBranch> convert(@NotNull GithubAuthData auth)
- throws IOException {
- return GithubApiUtil.getRepoBranches(auth, forkPath.getUser(),
- forkPath.getRepository());
- }
- }
- ), new Function<GithubBranch, String>() {
- @Override
- public String fun(GithubBranch githubBranch) {
- return githubBranch.getName();
- }
- });
+ private void doLoadForksFromGithub(@NotNull ProgressIndicator indicator) throws IOException {
+ GithubRepoDetailed repo =
+ GithubUtil.runTask(myProject, myAuthHolder, indicator, new ThrowableConvertor<GithubConnection, GithubRepoDetailed, IOException>() {
+ @NotNull
+ @Override
+ public GithubRepoDetailed convert(@NotNull GithubConnection connection) throws IOException {
+ return GithubApiUtil.getDetailedRepoInfo(connection, myPath.getUser(), myPath.getRepository());
+ }
+ });
- // fetch
- if (targetRemoteName != null) {
- GitFetchResult result = new GitFetcher(myProject, indicator, false).fetch(myGitRepository.getRoot(), targetRemoteName, null);
- if (!result.isSuccess()) {
- GitFetcher.displayFetchResult(myProject, result, null, result.getErrors());
- targetRemoteName = null;
- }
- }
+ doAddFork(repo, indicator);
+ if (repo.getParent() != null) {
+ doAddFork(repo.getParent(), indicator);
+ }
+ if (repo.getSource() != null) {
+ doAddFork(repo.getSource(), indicator);
+ }
- return new GithubInfo(branches, targetRemoteName);
- }
- });
+ mySource = repo.getSource() == null ? repo.getFullPath() : repo.getSource().getFullPath();
+ }
- myForkPath = forkPath;
- myTargetRemote = info.getTargetRemote();
-
- myDiffInfos.clear();
- if (canShowDiff()) {
- for (final String branch : info.getBranches()) {
- myDiffInfos.put(branch, new FutureTask<DiffInfo>(new Callable<DiffInfo>() {
- @Nullable
- @Override
- public DiffInfo call() throws Exception {
- return loadDiffInfo(myProject, myGitRepository, myCurrentBranch, myTargetRemote + "/" + branch);
- }
- }));
+ @NotNull
+ private List<String> loadBranches(@NotNull final GithubFullPath fork, @NotNull ProgressIndicator indicator) throws IOException {
+ return ContainerUtil.map(
+ GithubUtil.runTask(myProject, myAuthHolder, indicator, new ThrowableConvertor<GithubConnection, List<GithubBranch>, IOException>() {
+ @Override
+ public List<GithubBranch> convert(@NotNull GithubConnection connection) throws IOException {
+ return GithubApiUtil.getRepoBranches(connection, fork.getUser(), fork.getRepository());
+ }
+ }),
+ new Function<GithubBranch, String>() {
+ @Override
+ public String fun(@NotNull GithubBranch branch) {
+ return branch.getName();
}
}
+ );
+ }
+
+ @Nullable
+ private String doLoadDefaultBranch(@NotNull final GithubFullPath fork, @NotNull ProgressIndicator indicator) throws IOException {
+ GithubRepo repo =
+ GithubUtil.runTask(myProject, myAuthHolder, indicator, new ThrowableConvertor<GithubConnection, GithubRepo, IOException>() {
+ @Override
+ public GithubRepo convert(@NotNull GithubConnection connection) throws IOException {
+ return GithubApiUtil.getDetailedRepoInfo(connection, fork.getUser(), fork.getRepository());
+ }
+ });
+ return repo.getDefaultBranch();
+ }
+
+ public void launchFetchRemote(@NotNull final ForkInfo fork) {
+ if (fork.getRemoteName() == null) return;
+
+ if (fork.getFetchTask() != null) return;
+ synchronized (fork.LOCK) {
+ if (fork.getFetchTask() != null) return;
- return new GithubTargetInfo(info.getBranches());
+ final MasterFutureTask<Void> task = new MasterFutureTask<Void>(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ doFetchRemote(fork);
+ return null;
+ }
+ });
+ fork.setFetchTask(task);
+
+ ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
+ @Override
+ public void run() {
+ task.run();
+ }
+ });
}
- catch (IOException e) {
- GithubNotifications.showErrorDialog(myProject, CANNOT_CREATE_PULL_REQUEST, e);
+ }
+
+ public void launchLoadDiffInfo(@NotNull final BranchInfo branch) {
+ if (branch.getForkInfo().getRemoteName() == null) return;
+
+ if (branch.getDiffInfoTask() != null) return;
+ synchronized (branch.LOCK) {
+ if (branch.getDiffInfoTask() != null) return;
+
+ launchFetchRemote(branch.getForkInfo());
+ MasterFutureTask<Void> masterTask = branch.getForkInfo().getFetchTask();
+ assert masterTask != null;
+
+ final SlaveFutureTask<DiffInfo> task = new SlaveFutureTask<DiffInfo>(masterTask, new Callable<DiffInfo>() {
+ @Override
+ public DiffInfo call() throws VcsException {
+ return doLoadDiffInfo(branch);
+ }
+ });
+ branch.setDiffInfoTask(task);
+
+ ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
+ @Override
+ public void run() {
+ task.run();
+ }
+ });
+ }
+ }
+
+ @Nullable
+ public DiffInfo getDiffInfo(@NotNull final BranchInfo branch) throws IOException {
+ if (branch.getForkInfo().getRemoteName() == null) return null;
+
+ launchLoadDiffInfo(branch);
+
+ assert branch.getDiffInfoTask() != null;
+ try {
+ return branch.getDiffInfoTask().get();
+ }
+ catch (InterruptedException e) {
+ throw new GithubOperationCanceledException(e);
+ }
+ catch (ExecutionException e) {
+ Throwable ex = e.getCause();
+ if (ex instanceof VcsException) throw new IOException(ex);
+ LOG.error(ex);
return null;
}
}
- public void showDiffDialog(@NotNull String branch) {
- if (canShowDiff()) {
- DiffInfo info = getDiffInfoWithModal(branch);
- if (info == null) {
- GithubNotifications.showErrorDialog(myProject, "Can't Show Diff", "Can't get diff info");
- return;
- }
+ private boolean doFetchRemote(@NotNull ForkInfo fork) {
+ if (fork.getRemoteName() == null) return false;
- GitCompareBranchesDialog dialog =
- new GitCompareBranchesDialog(myProject, info.getTo(), info.getFrom(), info.getInfo(), myGitRepository);
- dialog.show();
+ GitFetchResult result =
+ new GitFetcher(myProject, new EmptyProgressIndicator(), false).fetch(myGitRepository.getRoot(), fork.getRemoteName(), null);
+ if (!result.isSuccess()) {
+ GitFetcher.displayFetchResult(myProject, result, null, result.getErrors());
+ return false;
}
+ return true;
}
- @Nullable
- public GithubFullPath showTargetDialog() {
- return showTargetDialog(false);
+ @NotNull
+ private DiffInfo doLoadDiffInfo(@NotNull final BranchInfo branch) throws VcsException {
+ // TODO: make cancelable and abort old speculative requests (when git4idea will allow to do so)
+ String currentBranch = myCurrentBranch;
+ String targetBranch = branch.getForkInfo().getRemoteName() + "/" + branch.getRemoteName();
+
+ List<GitCommit> commits1 = GitHistoryUtils.history(myProject, myGitRepository.getRoot(), ".." + targetBranch);
+ List<GitCommit> commits2 = GitHistoryUtils.history(myProject, myGitRepository.getRoot(), targetBranch + "..");
+ Collection<Change> diff = GitChangeUtils.getDiff(myProject, myGitRepository.getRoot(), targetBranch, myCurrentBranch, null);
+ GitCommitCompareInfo info = new GitCommitCompareInfo(GitCommitCompareInfo.InfoType.BRANCH_TO_HEAD);
+ info.put(myGitRepository, diff);
+ info.put(myGitRepository, Couple.of(commits1, commits2));
+
+ return new DiffInfo(info, currentBranch, targetBranch);
}
- @Nullable
- public GithubFullPath showTargetDialog(boolean firstTime) {
- final GithubInfo2 info = getAvailableForksInModal(myProject, myGitRepository, myAuthHolder, myPath);
- if (info == null) {
- return null;
+ private void doConfigureRemote(@NotNull ForkInfo fork) {
+ if (fork.getRemoteName() != null) return;
+
+ GithubFullPath path = fork.getPath();
+ String url = GithubUrlUtil.getCloneUrl(path);
+
+ if (GithubUtil.addGithubRemote(myProject, myGitRepository, path.getUser(), url)) {
+ fork.setRemoteName(path.getUser());
}
+ }
- if (firstTime) {
- if (info.getForks().size() == 1) {
- return info.getForks().iterator().next();
+ public void configureRemote(@NotNull final ForkInfo fork) {
+ GithubUtil.computeValueInModal(myProject, "Creating remote..", false, new Consumer<ProgressIndicator>() {
+ @Override
+ public void consume(ProgressIndicator indicator) {
+ doConfigureRemote(fork);
}
- if (info.getForks().size() == 2) {
- Iterator<GithubFullPath> it = info.getForks().iterator();
- GithubFullPath path1 = it.next();
- GithubFullPath path2 = it.next();
+ });
+ }
- if (myPath.equals(path1)) {
- return path2;
- }
- if (myPath.equals(path2)) {
- return path1;
+ @NotNull
+ public Couple<String> getDefaultDescriptionMessage(@NotNull final BranchInfo branch) {
+ Couple<String> message = branch.getDefaultMessage();
+ if (message != null) return message;
+
+ if (branch.getForkInfo().getRemoteName() == null) {
+ return getSimpleDefaultDescriptionMessage(branch);
+ }
+
+ return GithubUtil
+ .computeValueInModal(myProject, "Collecting additional data...", false, new Convertor<ProgressIndicator, Couple<String>>() {
+ @Override
+ public Couple<String> convert(ProgressIndicator o) {
+ String localBranch = myCurrentBranch;
+ String targetBranch = branch.getForkInfo().getRemoteName() + "/" + branch.getRemoteName();
+ try {
+ List<VcsCommitMetadata> commits =
+ GitHistoryUtils.readLastCommits(myProject, myGitRepository.getRoot(), localBranch, targetBranch);
+ if (commits == null) return getSimpleDefaultDescriptionMessage(branch);
+
+ VcsCommitMetadata localCommit = commits.get(0);
+ VcsCommitMetadata targetCommit = commits.get(1);
+
+ if (localCommit.getParents().contains(targetCommit.getId())) {
+ return Couple.of(localCommit.getSubject(), localCommit.getFullMessage());
+ }
+ return getSimpleDefaultDescriptionMessage(branch);
+ }
+ catch (VcsException e) {
+ GithubNotifications.showWarning(myProject, "Can't collect additional data", e);
+ return getSimpleDefaultDescriptionMessage(branch);
+ }
}
- }
+ });
+ }
+
+ @NotNull
+ public Couple<String> getSimpleDefaultDescriptionMessage(@NotNull final BranchInfo branch) {
+ Couple<String> message = Couple.of(myCurrentBranch, "");
+ branch.setDefaultMessage(message);
+ return message;
+ }
+
+ public boolean checkAction(@Nullable final BranchInfo branch) {
+ if (branch == null) {
+ GithubNotifications.showWarningDialog(myProject, CANNOT_CREATE_PULL_REQUEST, "Target branch is not selected");
+ return false;
}
- Convertor<String, GithubFullPath> getForkPath = new Convertor<String, GithubFullPath>() {
- @Nullable
- @Override
- public GithubFullPath convert(@NotNull final String user) {
- return GithubUtil.computeValueInModal(myProject, "Access to GitHub", new Convertor<ProgressIndicator, GithubFullPath>() {
- @Nullable
+ DiffInfo info;
+ try {
+ info = GithubUtil
+ .computeValueInModal(myProject, "Collecting diff data...", new ThrowableConvertor<ProgressIndicator, DiffInfo, IOException>() {
@Override
- public GithubFullPath convert(ProgressIndicator indicator) {
- return findRepositoryByUser(myProject, myAuthHolder, indicator, user, info.getForks(), info.getSource());
+ public DiffInfo convert(ProgressIndicator indicator) throws IOException {
+ return GithubUtil.runInterruptable(indicator, new ThrowableComputable<DiffInfo, IOException>() {
+ @Override
+ public DiffInfo compute() throws IOException {
+ return getDiffInfo(branch);
+ }
+ });
}
});
- }
- };
- GithubSelectForkDialog dialog = new GithubSelectForkDialog(myProject, info.getForks(), getForkPath);
- DialogManager.show(dialog);
- if (!dialog.isOK()) {
- return null;
}
- return dialog.getPath();
- }
-
- public boolean checkAction(@NotNull String targetBranch) {
- DiffInfo info = getDiffInfoWithModal(targetBranch);
+ catch (IOException e) {
+ GithubNotifications.showError(myProject, "Can't collect diff data", e);
+ return true;
+ }
if (info == null) {
return true;
}
- String localBranchName = "'" + getCurrentBranch() + "'";
- String targetBranchName = "'" + myTargetRemote + ":" + targetBranch + "'";
+ ForkInfo fork = branch.getForkInfo();
+
+ String localBranchName = "'" + myCurrentBranch + "'";
+ String targetBranchName = "'" + fork.getRemoteName() + "/" + branch.getRemoteName() + "'";
if (info.getInfo().getBranchToHeadCommits(myGitRepository).isEmpty()) {
- GithubNotifications
- .showWarningDialog(myProject, CANNOT_CREATE_PULL_REQUEST,
- "Can't create empty pull request: the branch " + localBranchName +
- " is fully merged to the branch " + targetBranchName
- );
- return false;
+ return Messages.YES == GithubNotifications
+ .showYesNoDialog(myProject, "Do you want to proceed anyway?",
+ "Empty pull request: the branch " + localBranchName + " is fully merged to the branch " + targetBranchName);
}
if (!info.getInfo().getHeadToBranchCommits(myGitRepository).isEmpty()) {
- return GithubNotifications
- .showYesNoDialog(myProject, "Do you want to proceed anyway?",
- "The branch " + targetBranchName + " is not fully merged to the branch " + localBranchName) == Messages.YES;
+ return Messages.YES == GithubNotifications
+ .showYesNoDialog(myProject, "Do you want to proceed anyway?",
+ "The branch " + targetBranchName + " is not fully merged to the branch " + localBranchName);
}
return true;
}
- public void performAction(@NotNull final String title, @NotNull final String description, @NotNull final String targetBranch) {
- @NotNull final Project project = myProject;
-
+ public void createPullRequest(@NotNull final BranchInfo branch,
+ @NotNull final String title,
+ @NotNull final String description) {
new Task.Backgroundable(myProject, "Creating pull request...") {
@Override
public void run(@NotNull ProgressIndicator indicator) {
@@ -344,298 +511,322 @@ public class GithubCreatePullRequestWorker {
indicator.setText("Pushing current branch...");
GitCommandResult result = myGit.push(myGitRepository, myRemoteName, myRemoteUrl, myCurrentBranch, true);
if (!result.success()) {
- GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, "Push failed:<br/>" + result.getErrorOutputAsHtmlString());
+ GithubNotifications.showError(myProject, CANNOT_CREATE_PULL_REQUEST, "Push failed:<br/>" + result.getErrorOutputAsHtmlString());
return;
}
- String headBranch = myPath.getUser() + ":" + myCurrentBranch;
-
LOG.info("Creating pull request");
indicator.setText("Creating pull request...");
- GithubPullRequest request =
- createPullRequest(project, myAuthHolder, indicator, myForkPath, title, description, headBranch, targetBranch);
+ GithubPullRequest request = doCreatePullRequest(indicator, branch, title, description);
if (request == null) {
return;
}
- GithubNotifications
- .showInfoURL(project, "Successfully created pull request", "Pull request #" + request.getNumber(), request.getHtmlUrl());
+ GithubNotifications.showInfoURL(myProject, "Successfully created pull request",
+ "Pull request #" + request.getNumber(), request.getHtmlUrl());
}
}.queue();
}
@Nullable
- private static String configureRemote(@NotNull Project project, @NotNull GitRepository gitRepository, @NotNull GithubFullPath forkPath) {
- String url = GithubUrlUtil.getCloneUrl(forkPath);
+ private GithubPullRequest doCreatePullRequest(@NotNull ProgressIndicator indicator,
+ @NotNull final BranchInfo branch,
+ @NotNull final String title,
+ @NotNull final String description) {
+ final ForkInfo fork = branch.getForkInfo();
- if (GithubUtil.addGithubRemote(project, gitRepository, forkPath.getUser(), url)) {
- return forkPath.getUser();
- }
- else {
- return null;
- }
- }
+ final String head = myPath.getUser() + ":" + myCurrentBranch;
+ final String base = branch.getRemoteName();
- @Nullable
- private static GithubPullRequest createPullRequest(@NotNull Project project,
- @NotNull GithubAuthDataHolder authHolder,
- @NotNull ProgressIndicator indicator,
- @NotNull final GithubFullPath targetRepo,
- @NotNull final String title,
- @NotNull final String description,
- @NotNull final String head,
- @NotNull final String base) {
try {
- return GithubUtil.runTask(project, authHolder, indicator, new ThrowableConvertor<GithubAuthData, GithubPullRequest, IOException>() {
- @NotNull
- @Override
- public GithubPullRequest convert(@NotNull GithubAuthData auth) throws IOException {
- return GithubApiUtil.createPullRequest(auth, targetRepo.getUser(), targetRepo.getRepository(), title, description, head, base);
- }
- });
+ return GithubUtil
+ .runTask(myProject, myAuthHolder, indicator, new ThrowableConvertor<GithubConnection, GithubPullRequest, IOException>() {
+ @NotNull
+ @Override
+ public GithubPullRequest convert(@NotNull GithubConnection connection) throws IOException {
+ return GithubApiUtil
+ .createPullRequest(connection, fork.getPath().getUser(), fork.getPath().getRepository(), title, description, head, base);
+ }
+ });
}
catch (IOException e) {
- GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, e);
+ GithubNotifications.showError(myProject, CANNOT_CREATE_PULL_REQUEST, e);
return null;
}
}
- @Nullable
- private DiffInfo getDiffInfo(@NotNull String branch) {
+ public void showDiffDialog(@Nullable final BranchInfo branch) {
+ if (branch == null) {
+ GithubNotifications.showWarningDialog(myProject, "Can't Show Diff", "Target branch is not selected");
+ return;
+ }
+
+ DiffInfo info;
try {
- FutureTask<DiffInfo> future = myDiffInfos.get(branch);
- if (future == null) {
- return null;
- }
- future.run();
- return future.get();
+ info = GithubUtil
+ .computeValueInModal(myProject, "Collecting diff data...", new ThrowableConvertor<ProgressIndicator, DiffInfo, IOException>() {
+ @Override
+ public DiffInfo convert(ProgressIndicator indicator) throws IOException {
+ return GithubUtil.runInterruptable(indicator, new ThrowableComputable<DiffInfo, IOException>() {
+ @Override
+ public DiffInfo compute() throws IOException {
+ return getDiffInfo(branch);
+ }
+ });
+ }
+ });
}
- catch (InterruptedException e) {
- LOG.error(e);
- return null;
+ catch (IOException e) {
+ GithubNotifications.showError(myProject, "Can't collect diff data", e);
+ return;
}
- catch (ExecutionException e) {
- LOG.error(e);
- return null;
+ if (info == null) {
+ GithubNotifications.showErrorDialog(myProject, "Can't Show Diff", "Can't collect diff data");
+ return;
}
+
+ GitCompareBranchesDialog dialog =
+ new GitCompareBranchesDialog(myProject, info.getTo(), info.getFrom(), info.getInfo(), myGitRepository, true);
+ dialog.show();
}
@Nullable
- private DiffInfo getDiffInfoWithModal(@NotNull final String branch) {
- return GithubUtil.computeValueInModal(myProject, "Collecting diff data...", new Convertor<ProgressIndicator, DiffInfo>() {
- @Override
- @Nullable
- public DiffInfo convert(ProgressIndicator indicator) {
- return getDiffInfo(branch);
- }
- });
- }
+ public ForkInfo showTargetDialog() {
+ if (myAvailableForks == null) {
+ myAvailableForks = GithubUtil
+ .computeValueInModal(myProject, myCurrentBranch, new Convertor<ProgressIndicator, List<GithubFullPath>>() {
+ @Override
+ public List<GithubFullPath> convert(ProgressIndicator indicator) {
+ return getAvailableForks(indicator);
+ }
+ });
+ }
- public void getDiffDescriptionInPooledThread(@NotNull final String branch, @NotNull final Consumer<DiffDescription> after) {
- ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
+ Convertor<String, ForkInfo> getForkPath = new Convertor<String, ForkInfo>() {
+ @Nullable
@Override
- public void run() {
- after.consume(getDefaultDescriptionMessage(branch, getDiffInfo(branch), myGitRepository));
+ public ForkInfo convert(@NotNull final String user) {
+ return GithubUtil.computeValueInModal(myProject, "Access to GitHub", new Convertor<ProgressIndicator, ForkInfo>() {
+ @Nullable
+ @Override
+ public ForkInfo convert(ProgressIndicator indicator) {
+ return findRepositoryByUser(indicator, user);
+ }
+ });
}
- });
+ };
+ GithubSelectForkDialog dialog = new GithubSelectForkDialog(myProject, myAvailableForks, getForkPath);
+ DialogManager.show(dialog);
+ if (!dialog.isOK()) {
+ return null;
+ }
+ return dialog.getPath();
}
@Nullable
- private static DiffInfo loadDiffInfo(@NotNull final Project project,
- @NotNull final GitRepository repository,
- @NotNull final String currentBranch,
- @NotNull final String targetBranch) {
+ private List<GithubFullPath> getAvailableForks(@NotNull ProgressIndicator indicator) {
try {
- List<GitCommit> commits1 = GitHistoryUtils.history(project, repository.getRoot(), ".." + targetBranch);
- List<GitCommit> commits2 = GitHistoryUtils.history(project, repository.getRoot(), targetBranch + "..");
- Collection<Change> diff = GitChangeUtils.getDiff(repository.getProject(), repository.getRoot(), targetBranch, currentBranch, null);
- GitCommitCompareInfo info = new GitCommitCompareInfo(GitCommitCompareInfo.InfoType.BRANCH_TO_HEAD);
- info.put(repository, diff);
- info.put(repository, Couple.of(commits1, commits2));
- return new DiffInfo(info, currentBranch, targetBranch);
- }
- catch (VcsException e) {
- LOG.info(e);
+ List<GithubFullPath> forks = ContainerUtil.map(
+ GithubUtil.runTask(myProject, myAuthHolder, indicator,
+ new ThrowableConvertor<GithubConnection, List<GithubRepo>, IOException>() {
+ @NotNull
+ @Override
+ public List<GithubRepo> convert(@NotNull GithubConnection connection)
+ throws IOException {
+ return GithubApiUtil.getForks(connection, mySource.getUser(), mySource.getRepository());
+ }
+ }
+ ),
+ new Function<GithubRepo, GithubFullPath>() {
+ @Override
+ public GithubFullPath fun(GithubRepo repo) {
+ return repo.getFullPath();
+ }
+ }
+ );
+ if (!forks.contains(mySource)) forks.add(mySource);
+ return forks;
+ }
+ catch (IOException e) {
+ GithubNotifications.showWarning(myProject, "Can't load available forks", e);
return null;
}
}
- @NotNull
- private static DiffDescription getDefaultDescriptionMessage(@NotNull String branch,
- @Nullable DiffInfo info,
- @NotNull GitRepository gitRepository) {
- if (info == null) {
- return new DiffDescription(branch, null, null);
- }
-
- if (info.getInfo().getBranchToHeadCommits(gitRepository).size() != 1) {
- return new DiffDescription(branch, info.getFrom(), null);
+ @Nullable
+ private ForkInfo findRepositoryByUser(@NotNull final ProgressIndicator indicator, @NotNull final String user) {
+ for (ForkInfo fork : myForks) {
+ if (StringUtil.equalsIgnoreCase(user, fork.getPath().getUser())) {
+ return fork;
+ }
}
- GitCommit commit = info.getInfo().getBranchToHeadCommits(gitRepository).get(0);
- return new DiffDescription(branch, commit.getSubject(), commit.getFullMessage());
- }
-
- @Nullable
- private static GithubInfo2 getAvailableForksInModal(@NotNull final Project project,
- @NotNull final GitRepository gitRepository,
- @NotNull final GithubAuthDataHolder authHolder,
- @NotNull final GithubFullPath path) {
try {
- return GithubUtil
- .computeValueInModal(project, "Access to GitHub", new ThrowableConvertor<ProgressIndicator, GithubInfo2, IOException>() {
- @NotNull
+ GithubRepo repo =
+ GithubUtil.runTask(myProject, myAuthHolder, indicator, new ThrowableConvertor<GithubConnection, GithubRepo, IOException>() {
+ @Nullable
@Override
- public GithubInfo2 convert(ProgressIndicator indicator) throws IOException {
- final Set<GithubFullPath> forks = new HashSet<GithubFullPath>();
-
- // GitHub
- GithubRepoDetailed repo =
- GithubUtil.runTask(project, authHolder, indicator, new ThrowableConvertor<GithubAuthData, GithubRepoDetailed, IOException>() {
- @NotNull
- @Override
- public GithubRepoDetailed convert(@NotNull GithubAuthData auth) throws IOException {
- return GithubApiUtil.getDetailedRepoInfo(auth, path.getUser(), path.getRepository());
- }
- });
-
- forks.add(path);
- if (repo.getParent() != null) {
- forks.add(repo.getParent().getFullPath());
+ public GithubRepo convert(@NotNull GithubConnection connection) throws IOException {
+ try {
+ GithubRepoDetailed target = GithubApiUtil.getDetailedRepoInfo(connection, user, mySource.getRepository());
+ if (target.getSource() != null && StringUtil.equals(target.getSource().getUserName(), mySource.getUser())) {
+ return target;
+ }
}
- if (repo.getSource() != null) {
- forks.add(repo.getSource().getFullPath());
+ catch (IOException ignore) {
+ // such repo may not exist
}
- // Git
- forks.addAll(getAvailableForksFromGit(gitRepository));
-
- GithubRepo forkTreeRoot = repo.getSource() == null ? repo : repo.getSource();
- return new GithubInfo2(forks, forkTreeRoot);
+ return GithubApiUtil.findForkByUser(connection, mySource.getUser(), mySource.getRepository(), user);
}
});
+
+ if (repo == null) return null;
+ return doAddFork(repo, indicator);
}
catch (IOException e) {
- GithubNotifications.showErrorDialog(project, CANNOT_CREATE_PULL_REQUEST, e);
+ GithubNotifications.showError(myProject, "Can't find repository", e);
return null;
}
}
- @NotNull
- private static List<GithubFullPath> getAvailableForksFromGit(@NotNull GitRepository gitRepository) {
- List<GithubFullPath> forks = new ArrayList<GithubFullPath>();
- for (GitRemoteBranch remoteBranch : gitRepository.getBranches().getRemoteBranches()) {
- for (String url : remoteBranch.getRemote().getUrls()) {
- if (GithubUrlUtil.isGithubUrl(url)) {
- GithubFullPath path = GithubUrlUtil.getUserAndRepositoryFromRemoteUrl(url);
- if (path != null) {
- forks.add(path);
- break;
- }
- }
+ public static class ForkInfo {
+ @NotNull public final Object LOCK = new Object();
+
+ // initial loading
+ @NotNull private final GithubFullPath myPath;
+
+ @NotNull private final String myDefaultBranch;
+ @NotNull private final List<BranchInfo> myBranches;
+
+ @Nullable private String myRemoteName;
+ private boolean myProposedToCreateRemote;
+
+ @Nullable private MasterFutureTask<Void> myFetchTask;
+
+ public ForkInfo(@NotNull GithubFullPath path, @NotNull List<String> branches, @Nullable String defaultBranch) {
+ myPath = path;
+ myDefaultBranch = defaultBranch == null ? "master" : defaultBranch;
+ myBranches = new ArrayList<BranchInfo>();
+ for (String branchName : branches) {
+ myBranches.add(new BranchInfo(branchName, this));
}
}
- return forks;
- }
- @Nullable
- private static GithubFullPath findRepositoryByUser(@NotNull Project project,
- @NotNull GithubAuthDataHolder authHolder,
- @NotNull ProgressIndicator indicator,
- @NotNull final String user,
- @NotNull Set<GithubFullPath> forks,
- @NotNull final GithubRepo source) {
- for (GithubFullPath path : forks) {
- if (StringUtil.equalsIgnoreCase(user, path.getUser())) {
- return path;
- }
+ @NotNull
+ public GithubFullPath getPath() {
+ return myPath;
}
- try {
- return GithubUtil.runTask(project, authHolder, indicator, new ThrowableConvertor<GithubAuthData, GithubFullPath, IOException>() {
- @Nullable
- @Override
- public GithubFullPath convert(@NotNull GithubAuthData auth) throws IOException {
- try {
- GithubRepoDetailed target = GithubApiUtil.getDetailedRepoInfo(auth, user, source.getName());
- if (target.getSource() != null && StringUtil.equals(target.getSource().getUserName(), source.getUserName())) {
- return target.getFullPath();
- }
- }
- catch (IOException ignore) {
- // such repo may not exist
- }
+ @Nullable
+ public String getRemoteName() {
+ return myRemoteName;
+ }
- GithubRepo fork = GithubApiUtil.findForkByUser(auth, source.getUserName(), source.getName(), user);
- if (fork != null) {
- return fork.getFullPath();
- }
+ @NotNull
+ public String getDefaultBranch() {
+ return myDefaultBranch;
+ }
- return null;
- }
- });
+ @NotNull
+ public List<BranchInfo> getBranches() {
+ return myBranches;
}
- catch (IOException e) {
- GithubNotifications.showError(project, CANNOT_CREATE_PULL_REQUEST, e);
+
+ public void setRemoteName(@NotNull String remoteName) {
+ myRemoteName = remoteName;
}
- return null;
- }
+ public boolean isProposedToCreateRemote() {
+ return myProposedToCreateRemote;
+ }
+
+ public void setProposedToCreateRemote(boolean proposedToCreateRemote) {
+ myProposedToCreateRemote = proposedToCreateRemote;
+ }
- private static class GithubInfo {
- @NotNull private final List<String> myBranches;
- @Nullable private final String myTargetRemote;
+ @Nullable
+ public MasterFutureTask<Void> getFetchTask() {
+ return myFetchTask;
+ }
- private GithubInfo(@NotNull List<String> repo, @Nullable String targetRemote) {
- myBranches = repo;
- myTargetRemote = targetRemote;
+ public void setFetchTask(@NotNull MasterFutureTask<Void> fetchTask) {
+ myFetchTask = fetchTask;
}
- @NotNull
- public List<String> getBranches() {
- return myBranches;
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ ForkInfo info = (ForkInfo)o;
+
+ if (!myPath.equals(info.myPath)) return false;
+
+ return true;
}
- @Nullable
- public String getTargetRemote() {
- return myTargetRemote;
+ @Override
+ public int hashCode() {
+ return myPath.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return myPath.getUser() + ":" + myPath.getRepository();
}
}
- private static class GithubInfo2 {
- @NotNull private final Set<GithubFullPath> myForks;
- @NotNull private final GithubRepo mySource;
+ public static class BranchInfo {
+ @NotNull public final Object LOCK = new Object();
- private GithubInfo2(@NotNull Set<GithubFullPath> forks, @NotNull GithubRepo source) {
- myForks = forks;
- mySource = source;
+ @NotNull private final ForkInfo myForkInfo;
+ @NotNull private final String myRemoteName;
+
+ @Nullable private SlaveFutureTask<DiffInfo> myDiffInfoTask;
+
+ @Nullable private Couple<String> myDefaultMessage;
+
+ public BranchInfo(@NotNull String remoteName, @NotNull ForkInfo fork) {
+ myRemoteName = remoteName;
+ myForkInfo = fork;
}
@NotNull
- public Set<GithubFullPath> getForks() {
- return myForks;
+ public ForkInfo getForkInfo() {
+ return myForkInfo;
}
@NotNull
- public GithubRepo getSource() {
- return mySource;
+ public String getRemoteName() {
+ return myRemoteName;
}
- }
- public static class GithubTargetInfo {
- @NotNull private final List<String> myBranches;
+ @Nullable
+ public SlaveFutureTask<DiffInfo> getDiffInfoTask() {
+ return myDiffInfoTask;
+ }
- private GithubTargetInfo(@NotNull List<String> branches) {
- myBranches = branches;
+ public void setDiffInfoTask(@NotNull SlaveFutureTask<DiffInfo> diffInfoTask) {
+ myDiffInfoTask = diffInfoTask;
}
- @NotNull
- public List<String> getBranches() {
- return myBranches;
+ @Nullable
+ public Couple<String> getDefaultMessage() {
+ return myDefaultMessage;
+ }
+
+ public void setDefaultMessage(@NotNull Couple<String> message) {
+ myDefaultMessage = message;
+ }
+
+ @Override
+ public String toString() {
+ return myRemoteName;
}
}
- private static class DiffInfo {
+ public static class DiffInfo {
@NotNull private final GitCommitCompareInfo myInfo;
@NotNull private final String myFrom;
@NotNull private final String myTo;
@@ -662,30 +853,86 @@ public class GithubCreatePullRequestWorker {
}
}
- public static class DiffDescription {
- @NotNull private final String myBranch;
- @Nullable private final String myTitle;
- @Nullable private final String myDescription;
+ public static class SlaveFutureTask<T> extends FutureTask<T> {
+ @NotNull private final MasterFutureTask myMaster;
- public DiffDescription(@NotNull String branch, @Nullable String title, @Nullable String description) {
- myBranch = branch;
- myTitle = title;
- myDescription = description;
+ public SlaveFutureTask(@NotNull MasterFutureTask master, @NotNull Callable<T> callable) {
+ super(callable);
+ myMaster = master;
}
- @NotNull
- public String getBranch() {
- return myBranch;
+ @Override
+ public void run() {
+ if (myMaster.isDone()) {
+ super.run();
+ }
+ else {
+ if (!myMaster.addSlave(this)) {
+ super.run();
+ }
+ }
}
- @Nullable
- public String getTitle() {
- return myTitle;
+ public T safeGet() {
+ try {
+ return super.get();
+ }
+ catch (InterruptedException e) {
+ return null;
+ }
+ catch (CancellationException e) {
+ return null;
+ }
+ catch (ExecutionException e) {
+ return null;
+ }
}
+ }
- @Nullable
- public String getDescription() {
- return myDescription;
+ public static class MasterFutureTask<T> extends FutureTask<T> {
+ @NotNull private final Object LOCK = new Object();
+ private boolean myDone = false;
+
+ @Nullable private List<SlaveFutureTask> mySlaves;
+
+ public MasterFutureTask(@NotNull Callable<T> callable) {
+ super(callable);
+ }
+
+ boolean addSlave(@NotNull SlaveFutureTask slave) {
+ if (isDone()) {
+ return false;
+ }
+ else {
+ synchronized (LOCK) {
+ if (myDone) return false;
+ if (mySlaves == null) mySlaves = new ArrayList<SlaveFutureTask>();
+ mySlaves.add(slave);
+ return true;
+ }
+ }
+ }
+
+ @Override
+ protected void done() {
+ synchronized (LOCK) {
+ myDone = true;
+ if (mySlaves != null) {
+ for (final SlaveFutureTask slave : mySlaves) {
+ runSlave(slave);
+ }
+ mySlaves = null;
+ }
+ }
+ }
+
+ protected void runSlave(@NotNull final SlaveFutureTask slave) {
+ ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
+ @Override
+ public void run() {
+ slave.run();
+ }
+ });
}
}
}
diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubRebaseAction.java b/plugins/github/src/org/jetbrains/plugins/github/GithubRebaseAction.java
index 719f8b956432..23d34e3178d3 100644
--- a/plugins/github/src/org/jetbrains/plugins/github/GithubRebaseAction.java
+++ b/plugins/github/src/org/jetbrains/plugins/github/GithubRebaseAction.java
@@ -41,6 +41,7 @@ import icons.GithubIcons;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.github.api.GithubApiUtil;
+import org.jetbrains.plugins.github.api.GithubConnection;
import org.jetbrains.plugins.github.api.GithubFullPath;
import org.jetbrains.plugins.github.api.GithubRepoDetailed;
import org.jetbrains.plugins.github.util.*;
@@ -197,11 +198,11 @@ public class GithubRebaseAction extends DumbAwareAction {
try {
return GithubUtil.runTask(project, GithubAuthDataHolder.createFromSettings(), indicator,
- new ThrowableConvertor<GithubAuthData, GithubRepoDetailed, IOException>() {
+ new ThrowableConvertor<GithubConnection, GithubRepoDetailed, IOException>() {
@NotNull
@Override
- public GithubRepoDetailed convert(@NotNull GithubAuthData auth) throws IOException {
- return GithubApiUtil.getDetailedRepoInfo(auth, userAndRepo.getUser(), userAndRepo.getRepository());
+ public GithubRepoDetailed convert(@NotNull GithubConnection connection) throws IOException {
+ return GithubApiUtil.getDetailedRepoInfo(connection, userAndRepo.getUser(), userAndRepo.getRepository());
}
});
}
diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java b/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java
index cca5afa0f5e5..c372b09805a1 100644
--- a/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java
+++ b/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java
@@ -52,6 +52,7 @@ import icons.GithubIcons;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.github.api.GithubApiUtil;
+import org.jetbrains.plugins.github.api.GithubConnection;
import org.jetbrains.plugins.github.api.GithubRepo;
import org.jetbrains.plugins.github.api.GithubUserDetailed;
import org.jetbrains.plugins.github.ui.GithubShareDialog;
@@ -211,15 +212,15 @@ public class GithubShareAction extends DumbAwareAction {
@Override
public GithubInfo convert(ProgressIndicator indicator) throws IOException {
// get existing github repos (network) and validate auth data
- return GithubUtil.runTask(project, authHolder, indicator, new ThrowableConvertor<GithubAuthData, GithubInfo, IOException>() {
+ return GithubUtil.runTask(project, authHolder, indicator, new ThrowableConvertor<GithubConnection, GithubInfo, IOException>() {
@NotNull
@Override
- public GithubInfo convert(@NotNull GithubAuthData auth) throws IOException {
+ public GithubInfo convert(@NotNull GithubConnection connection) throws IOException {
// check access to private repos (network)
- GithubUserDetailed userInfo = GithubApiUtil.getCurrentUserDetailed(auth);
+ GithubUserDetailed userInfo = GithubApiUtil.getCurrentUserDetailed(connection);
HashSet<String> names = new HashSet<String>();
- for (GithubRepo info : GithubApiUtil.getUserRepos(auth)) {
+ for (GithubRepo info : GithubApiUtil.getUserRepos(connection)) {
names.add(info.getName());
}
return new GithubInfo(userInfo, names);
@@ -243,11 +244,11 @@ public class GithubShareAction extends DumbAwareAction {
final boolean isPrivate) {
try {
- return GithubUtil.runTask(project, authHolder, indicator, new ThrowableConvertor<GithubAuthData, GithubRepo, IOException>() {
+ return GithubUtil.runTask(project, authHolder, indicator, new ThrowableConvertor<GithubConnection, GithubRepo, IOException>() {
@NotNull
@Override
- public GithubRepo convert(@NotNull GithubAuthData auth) throws IOException {
- return GithubApiUtil.createRepo(auth, name, description, isPrivate);
+ public GithubRepo convert(@NotNull GithubConnection connection) throws IOException {
+ return GithubApiUtil.createRepo(connection, name, description, isPrivate);
}
}).getHtmlUrl();
}
diff --git a/plugins/github/src/org/jetbrains/plugins/github/api/GithubApiUtil.java b/plugins/github/src/org/jetbrains/plugins/github/api/GithubApiUtil.java
index b8cf537f7709..063ad3bc7bb6 100644
--- a/plugins/github/src/org/jetbrains/plugins/github/api/GithubApiUtil.java
+++ b/plugins/github/src/org/jetbrains/plugins/github/api/GithubApiUtil.java
@@ -1,60 +1,32 @@
-/*
- * Copyright 2000-2014 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
package org.jetbrains.plugins.github.api;
import com.google.gson.*;
-import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.util.net.HttpConfigurable;
-import org.apache.commons.httpclient.*;
-import org.apache.commons.httpclient.auth.AuthScope;
-import org.apache.commons.httpclient.methods.*;
-import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
+import org.apache.http.Header;
+import org.apache.http.HeaderElement;
+import org.apache.http.message.BasicHeader;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import org.jetbrains.plugins.github.exceptions.*;
-import org.jetbrains.plugins.github.util.GithubAuthData;
-import org.jetbrains.plugins.github.util.GithubSettings;
-import org.jetbrains.plugins.github.util.GithubUrlUtil;
+import org.jetbrains.plugins.github.api.GithubConnection.PagedRequest;
+import org.jetbrains.plugins.github.exceptions.GithubConfusingException;
+import org.jetbrains.plugins.github.exceptions.GithubJsonException;
+import org.jetbrains.plugins.github.exceptions.GithubStatusCodeException;
import org.jetbrains.plugins.github.util.GithubUtil;
-import sun.security.validator.ValidatorException;
-import javax.net.ssl.SSLHandshakeException;
-import java.awt.*;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.Reader;
import java.net.URLEncoder;
import java.util.*;
-import java.util.List;
-/**
- * @author Kirill Likhodedov
- */
public class GithubApiUtil {
+ private static final Logger LOG = GithubUtil.LOG;
public static final String DEFAULT_GITHUB_HOST = "github.com";
private static final String PER_PAGE = "per_page=100";
- private static final Logger LOG = GithubUtil.LOG;
- private static final Header ACCEPT_V3_JSON_HTML_MARKUP = new Header("Accept", "application/vnd.github.v3.html+json");
- private static final Header ACCEPT_V3_JSON = new Header("Accept", "application/vnd.github.v3+json");
+ private static final Header ACCEPT_V3_JSON_HTML_MARKUP = new BasicHeader("Accept", "application/vnd.github.v3.html+json");
+ private static final Header ACCEPT_V3_JSON = new BasicHeader("Accept", "application/vnd.github.v3+json");
@NotNull private static final Gson gson = initGson();
@@ -65,344 +37,8 @@ public class GithubApiUtil {
return builder.create();
}
- private enum HttpVerb {
- GET, POST, DELETE, HEAD, PATCH
- }
-
- @Nullable
- private static JsonElement postRequest(@NotNull GithubAuthData auth,
- @NotNull String path,
- @Nullable String requestBody,
- @NotNull Header... headers) throws IOException {
- return request(auth, path, requestBody, Arrays.asList(headers), HttpVerb.POST).getJsonElement();
- }
-
- @Nullable
- private static JsonElement patchRequest(@NotNull GithubAuthData auth,
- @NotNull String path,
- @Nullable String requestBody,
- @NotNull Header... headers) throws IOException {
- return request(auth, path, requestBody, Arrays.asList(headers), HttpVerb.PATCH).getJsonElement();
- }
-
- @Nullable
- private static JsonElement deleteRequest(@NotNull GithubAuthData auth, @NotNull String path, @NotNull Header... headers)
- throws IOException {
- return request(auth, path, null, Arrays.asList(headers), HttpVerb.DELETE).getJsonElement();
- }
-
- @Nullable
- private static JsonElement getRequest(@NotNull GithubAuthData auth, @NotNull String path, @NotNull Header... headers) throws IOException {
- return request(auth, path, null, Arrays.asList(headers), HttpVerb.GET).getJsonElement();
- }
-
- @NotNull
- private static ResponsePage request(@NotNull GithubAuthData auth,
- @NotNull String path,
- @Nullable String requestBody,
- @NotNull Collection<Header> headers,
- @NotNull HttpVerb verb) throws IOException {
- if (EventQueue.isDispatchThread() && !ApplicationManager.getApplication().isUnitTestMode()) {
- LOG.warn("Network operation in EDT"); // TODO: fix
- }
-
- HttpMethod method = null;
- try {
- String uri = GithubUrlUtil.getApiUrl(auth.getHost()) + path;
- method = doREST(auth, uri, requestBody, headers, verb);
-
- checkStatusCode(method, requestBody);
-
- InputStream resp = method.getResponseBodyAsStream();
- if (resp == null) {
- return new ResponsePage();
- }
-
- JsonElement ret = parseResponse(resp);
- if (ret.isJsonNull()) {
- return new ResponsePage();
- }
-
- Header header = method.getResponseHeader("Link");
- if (header != null) {
- String value = header.getValue();
- int end = value.indexOf(">; rel=\"next\"");
- int begin = value.lastIndexOf('<', end);
- if (begin >= 0 && end >= 0) {
- String newPath = GithubUrlUtil.removeProtocolPrefix(value.substring(begin + 1, end));
- int index = newPath.indexOf('/');
-
- return new ResponsePage(ret, newPath.substring(index));
- }
- }
-
- return new ResponsePage(ret);
- }
- finally {
- if (method != null) {
- method.releaseConnection();
- }
- }
- }
-
- @NotNull
- private static HttpMethod doREST(@NotNull final GithubAuthData auth,
- @NotNull final String uri,
- @Nullable final String requestBody,
- @NotNull final Collection<Header> headers,
- @NotNull final HttpVerb verb) throws IOException {
- HttpClient client = getHttpClient(auth.getBasicAuth(), auth.isUseProxy());
- HttpMethod method;
- switch (verb) {
- case POST:
- method = new PostMethod(uri);
- if (requestBody != null) {
- ((PostMethod)method).setRequestEntity(new StringRequestEntity(requestBody, "application/json", "UTF-8"));
- }
- break;
- case PATCH:
- method = new PostMethod(uri) { // TODO: httpclient 4.x
- @Override
- public String getName() {
- return "PATCH";
- }
- };
- if (requestBody != null) {
- ((PostMethod)method).setRequestEntity(new StringRequestEntity(requestBody, "application/json", "UTF-8"));
- }
- break;
- case GET:
- method = new GetMethod(uri);
- break;
- case DELETE:
- method = new DeleteMethod(uri);
- break;
- case HEAD:
- method = new HeadMethod(uri);
- break;
- default:
- throw new IllegalStateException("Wrong HttpVerb: unknown method: " + verb.toString());
- }
-
- GithubAuthData.TokenAuth tokenAuth = auth.getTokenAuth();
- if (tokenAuth != null) {
- method.addRequestHeader("Authorization", "token " + tokenAuth.getToken());
- }
- GithubAuthData.BasicAuth basicAuth = auth.getBasicAuth();
- if (basicAuth != null && basicAuth.getCode() != null) {
- method.addRequestHeader("X-GitHub-OTP", basicAuth.getCode());
- }
- for (Header header : headers) {
- method.addRequestHeader(header);
- }
-
- try {
- client.executeMethod(method);
- }
- catch (SSLHandshakeException e) { // User canceled operation from CertificateManager
- if (e.getCause() instanceof ValidatorException) {
- LOG.info("Host SSL certificate is not trusted", e);
- throw new GithubOperationCanceledException("Host SSL certificate is not trusted", e);
- }
- throw e;
- }
- return method;
- }
-
- @NotNull
- private static HttpClient getHttpClient(@Nullable GithubAuthData.BasicAuth basicAuth, boolean useProxy) {
- int timeout = GithubSettings.getInstance().getConnectionTimeout();
- final HttpClient client = new HttpClient();
- HttpConnectionManagerParams params = client.getHttpConnectionManager().getParams();
- params.setConnectionTimeout(timeout); //set connection timeout (how long it takes to connect to remote host)
- params.setSoTimeout(timeout); //set socket timeout (how long it takes to retrieve data from remote host)
-
- client.getParams().setContentCharset("UTF-8");
- // Configure proxySettings if it is required
- final HttpConfigurable proxySettings = HttpConfigurable.getInstance();
- if (useProxy && proxySettings.USE_HTTP_PROXY && !StringUtil.isEmptyOrSpaces(proxySettings.PROXY_HOST)) {
- client.getHostConfiguration().setProxy(proxySettings.PROXY_HOST, proxySettings.PROXY_PORT);
- if (proxySettings.PROXY_AUTHENTICATION) {
- client.getState().setProxyCredentials(AuthScope.ANY, new UsernamePasswordCredentials(proxySettings.PROXY_LOGIN,
- proxySettings.getPlainProxyPassword()));
- }
- }
- if (basicAuth != null) {
- client.getParams().setCredentialCharset("UTF-8");
- client.getParams().setAuthenticationPreemptive(true);
- client.getState().setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(basicAuth.getLogin(), basicAuth.getPassword()));
- }
- return client;
- }
-
- private static void checkStatusCode(@NotNull HttpMethod method, @Nullable String body) throws IOException {
- int code = method.getStatusCode();
- switch (code) {
- case HttpStatus.SC_OK:
- case HttpStatus.SC_CREATED:
- case HttpStatus.SC_ACCEPTED:
- case HttpStatus.SC_NO_CONTENT:
- return;
- case HttpStatus.SC_UNAUTHORIZED:
- case HttpStatus.SC_PAYMENT_REQUIRED:
- case HttpStatus.SC_FORBIDDEN:
- String message = getErrorMessage(method);
-
- Header headerOTP = method.getResponseHeader("X-GitHub-OTP");
- if (headerOTP != null) {
- if (headerOTP.getValue().startsWith("required")) {
- throw new GithubTwoFactorAuthenticationException(message);
- }
- }
-
- if (message.contains("API rate limit exceeded")) {
- throw new GithubRateLimitExceededException(message);
- }
-
- throw new GithubAuthenticationException("Request response: " + message);
- case HttpStatus.SC_BAD_REQUEST:
- case HttpStatus.SC_UNPROCESSABLE_ENTITY:
- if (body != null) {
- LOG.info(body);
- }
- throw new GithubStatusCodeException(code + ": " + getErrorMessage(method), code);
- default:
- throw new GithubStatusCodeException(code + ": " + getErrorMessage(method), code);
- }
- }
-
- @NotNull
- private static String getErrorMessage(@NotNull HttpMethod method) {
- try {
- InputStream resp = method.getResponseBodyAsStream();
- if (resp != null) {
- GithubErrorMessageRaw error = fromJson(parseResponse(resp), GithubErrorMessageRaw.class);
- return method.getStatusText() + " - " + error.getMessage();
- }
- }
- catch (IOException e) {
- LOG.info(e);
- }
- return method.getStatusText();
- }
-
- @NotNull
- private static JsonElement parseResponse(@NotNull InputStream githubResponse) throws IOException {
- Reader reader = new InputStreamReader(githubResponse, "UTF-8");
- try {
- return new JsonParser().parse(reader);
- }
- catch (JsonParseException jse) {
- throw new GithubJsonException("Couldn't parse GitHub response", jse);
- }
- finally {
- reader.close();
- }
- }
-
- private static class ResponsePage {
- @Nullable private final JsonElement response;
- @Nullable private final String nextPage;
-
- public ResponsePage() {
- this(null, null);
- }
-
- public ResponsePage(@Nullable JsonElement response) {
- this(response, null);
- }
-
- public ResponsePage(@Nullable JsonElement response, @Nullable String next) {
- this.response = response;
- this.nextPage = next;
- }
-
- @Nullable
- public JsonElement getJsonElement() {
- return response;
- }
-
- @Nullable
- public String getNextPage() {
- return nextPage;
- }
- }
-
- /*
- * Json API
- */
-
- static <Raw extends DataConstructor, Result> Result createDataFromRaw(@NotNull Raw rawObject, @NotNull Class<Result> resultClass)
- throws GithubJsonException {
- try {
- return rawObject.create(resultClass);
- }
- catch (Exception e) {
- throw new GithubJsonException("Json parse error", e);
- }
- }
-
- public static class PagedRequest<T> {
- @Nullable private String myNextPage;
- @NotNull private final Collection<Header> myHeaders;
- @NotNull private final Class<T> myResult;
- @NotNull private final Class<? extends DataConstructor[]> myRawArray;
-
- @SuppressWarnings("NullableProblems")
- public PagedRequest(@NotNull String path,
- @NotNull Class<T> result,
- @NotNull Class<? extends DataConstructor[]> rawArray,
- @NotNull Header... headers) {
- myNextPage = path;
- myResult = result;
- myRawArray = rawArray;
- myHeaders = Arrays.asList(headers);
- }
-
- @NotNull
- public List<T> next(@NotNull GithubAuthData auth) throws IOException {
- if (myNextPage == null) {
- throw new NoSuchElementException();
- }
-
- String page = myNextPage;
- myNextPage = null;
-
- ResponsePage response = request(auth, page, null, myHeaders, HttpVerb.GET);
-
- if (response.getJsonElement() == null) {
- throw new HttpException("Empty response");
- }
-
- if (!response.getJsonElement().isJsonArray()) {
- throw new GithubJsonException("Wrong json type: expected JsonArray", new Exception(response.getJsonElement().toString()));
- }
-
- myNextPage = response.getNextPage();
-
- List<T> result = new ArrayList<T>();
- for (DataConstructor raw : fromJson(response.getJsonElement().getAsJsonArray(), myRawArray)) {
- result.add(createDataFromRaw(raw, myResult));
- }
- return result;
- }
-
- public boolean hasNext() {
- return myNextPage != null;
- }
-
- @NotNull
- public List<T> getAll(@NotNull GithubAuthData auth) throws IOException {
- List<T> result = new ArrayList<T>();
- while (hasNext()) {
- result.addAll(next(auth));
- }
- return result;
- }
- }
-
@NotNull
- private static <T> T fromJson(@Nullable JsonElement json, @NotNull Class<T> classT) throws IOException {
+ public static <T> T fromJson(@Nullable JsonElement json, @NotNull Class<T> classT) throws IOException {
if (json == null) {
throw new GithubJsonException("Unexpected empty response");
}
@@ -425,13 +61,24 @@ public class GithubApiUtil {
return res;
}
- /*
- * Github API
+ @NotNull
+ public static <Raw extends DataConstructor, Result> Result createDataFromRaw(@NotNull Raw rawObject, @NotNull Class<Result> resultClass)
+ throws GithubJsonException {
+ try {
+ return rawObject.create(resultClass);
+ }
+ catch (Exception e) {
+ throw new GithubJsonException("Json parse error", e);
+ }
+ }
+
+ /*
+ * Operations
*/
- public static void askForTwoFactorCodeSMS(@NotNull GithubAuthData auth) {
+ public static void askForTwoFactorCodeSMS(@NotNull GithubConnection connection) {
try {
- postRequest(auth, "/authorizations", null, ACCEPT_V3_JSON);
+ connection.postRequest("/authorizations", null, ACCEPT_V3_JSON);
}
catch (IOException e) {
LOG.info(e);
@@ -439,47 +86,42 @@ public class GithubApiUtil {
}
@NotNull
- public static Collection<String> getTokenScopes(@NotNull GithubAuthData auth) throws IOException {
- HttpMethod method = null;
- try {
- String uri = GithubUrlUtil.getApiUrl(auth.getHost()) + "/user";
- method = doREST(auth, uri, null, Collections.<Header>emptyList(), HttpVerb.HEAD);
-
- checkStatusCode(method, null);
+ public static Collection<String> getTokenScopes(@NotNull GithubConnection connection) throws IOException {
+ Header[] headers = connection.headRequest("/user", ACCEPT_V3_JSON);
- Header header = method.getResponseHeader("X-OAuth-Scopes");
- if (header == null) {
- throw new HttpException("No scopes header");
- }
-
- Collection<String> scopes = new ArrayList<String>();
- for (HeaderElement elem : header.getElements()) {
- scopes.add(elem.getName());
+ Header scopesHeader = null;
+ for (Header header : headers) {
+ if (header.getName().equals("X-OAuth-Scopes")) {
+ scopesHeader = header;
+ break;
}
- return scopes;
}
- finally {
- if (method != null) {
- method.releaseConnection();
- }
+ if (scopesHeader == null) {
+ throw new GithubConfusingException("No scopes header");
}
+
+ Collection<String> scopes = new ArrayList<String>();
+ for (HeaderElement elem : scopesHeader.getElements()) {
+ scopes.add(elem.getName());
+ }
+ return scopes;
}
@NotNull
- public static String getScopedToken(@NotNull GithubAuthData auth, @NotNull Collection<String> scopes, @NotNull String note)
+ public static String getScopedToken(@NotNull GithubConnection connection, @NotNull Collection<String> scopes, @NotNull String note)
throws IOException {
- GithubAuthorization token = findToken(auth, note);
+ GithubAuthorization token = findToken(connection, note);
if (token == null) {
- return getNewScopedToken(auth, scopes, note).getToken();
+ return getNewScopedToken(connection, scopes, note).getToken();
}
if (token.getScopes().containsAll(scopes)) {
return token.getToken();
}
- return updateTokenScopes(auth, token, scopes).getToken();
+ return updateTokenScopes(connection, token, scopes).getToken();
}
@NotNull
- private static GithubAuthorization updateTokenScopes(@NotNull GithubAuthData auth,
+ private static GithubAuthorization updateTokenScopes(@NotNull GithubConnection connection,
@NotNull GithubAuthorization token,
@NotNull Collection<String> scopes) throws IOException {
try {
@@ -487,7 +129,7 @@ public class GithubApiUtil {
GithubAuthorizationUpdateRequest request = new GithubAuthorizationUpdateRequest(new ArrayList<String>(scopes));
- return createDataFromRaw(fromJson(patchRequest(auth, path, gson.toJson(request), ACCEPT_V3_JSON), GithubAuthorizationRaw.class),
+ return createDataFromRaw(fromJson(connection.patchRequest(path, gson.toJson(request), ACCEPT_V3_JSON), GithubAuthorizationRaw.class),
GithubAuthorization.class);
}
catch (GithubConfusingException e) {
@@ -497,7 +139,7 @@ public class GithubApiUtil {
}
@NotNull
- private static GithubAuthorization getNewScopedToken(@NotNull GithubAuthData auth,
+ private static GithubAuthorization getNewScopedToken(@NotNull GithubConnection connection,
@NotNull Collection<String> scopes,
@NotNull String note)
throws IOException {
@@ -506,7 +148,7 @@ public class GithubApiUtil {
GithubAuthorizationCreateRequest request = new GithubAuthorizationCreateRequest(new ArrayList<String>(scopes), note, null);
- return createDataFromRaw(fromJson(postRequest(auth, path, gson.toJson(request), ACCEPT_V3_JSON), GithubAuthorizationRaw.class),
+ return createDataFromRaw(fromJson(connection.postRequest(path, gson.toJson(request), ACCEPT_V3_JSON), GithubAuthorizationRaw.class),
GithubAuthorization.class);
}
catch (GithubConfusingException e) {
@@ -516,14 +158,14 @@ public class GithubApiUtil {
}
@Nullable
- private static GithubAuthorization findToken(@NotNull GithubAuthData auth, @NotNull String note) throws IOException {
+ private static GithubAuthorization findToken(@NotNull GithubConnection connection, @NotNull String note) throws IOException {
try {
String path = "/authorizations";
PagedRequest<GithubAuthorization> request =
new PagedRequest<GithubAuthorization>(path, GithubAuthorization.class, GithubAuthorizationRaw[].class, ACCEPT_V3_JSON);
- List<GithubAuthorization> tokens = request.getAll(auth);
+ List<GithubAuthorization> tokens = request.getAll(connection);
for (GithubAuthorization token : tokens) {
if (note.equals(token.getNote())) return token;
@@ -537,29 +179,32 @@ public class GithubApiUtil {
}
@NotNull
- public static String getMasterToken(@NotNull GithubAuthData auth, @NotNull String note) throws IOException {
+ public static String getMasterToken(@NotNull GithubConnection connection, @NotNull String note) throws IOException {
// "repo" - read/write access to public/private repositories
// "gist" - create/delete gists
List<String> scopes = Arrays.asList("repo", "gist");
- return getScopedToken(auth, scopes, note);
+ return getScopedToken(connection, scopes, note);
}
@NotNull
- public static String getReadOnlyToken(@NotNull GithubAuthData auth, @NotNull String user, @NotNull String repo, @NotNull String note)
+ public static String getReadOnlyToken(@NotNull GithubConnection connection,
+ @NotNull String user,
+ @NotNull String repo,
+ @NotNull String note)
throws IOException {
- GithubRepo repository = getDetailedRepoInfo(auth, user, repo);
+ GithubRepo repository = getDetailedRepoInfo(connection, user, repo);
// TODO: use read-only token for private repos when it will be available
List<String> scopes = repository.isPrivate() ? Collections.singletonList("repo") : Collections.<String>emptyList();
- return getScopedToken(auth, scopes, note);
+ return getScopedToken(connection, scopes, note);
}
@NotNull
- public static GithubUser getCurrentUser(@NotNull GithubAuthData auth) throws IOException {
+ public static GithubUser getCurrentUser(@NotNull GithubConnection connection) throws IOException {
try {
- JsonElement result = getRequest(auth, "/user", ACCEPT_V3_JSON);
+ JsonElement result = connection.getRequest("/user", ACCEPT_V3_JSON);
return createDataFromRaw(fromJson(result, GithubUserRaw.class), GithubUser.class);
}
catch (GithubConfusingException e) {
@@ -569,9 +214,9 @@ public class GithubApiUtil {
}
@NotNull
- public static GithubUserDetailed getCurrentUserDetailed(@NotNull GithubAuthData auth) throws IOException {
+ public static GithubUserDetailed getCurrentUserDetailed(@NotNull GithubConnection connection) throws IOException {
try {
- JsonElement result = getRequest(auth, "/user", ACCEPT_V3_JSON);
+ JsonElement result = connection.getRequest("/user", ACCEPT_V3_JSON);
return createDataFromRaw(fromJson(result, GithubUserRaw.class), GithubUserDetailed.class);
}
catch (GithubConfusingException e) {
@@ -581,13 +226,13 @@ public class GithubApiUtil {
}
@NotNull
- public static List<GithubRepo> getUserRepos(@NotNull GithubAuthData auth) throws IOException {
+ public static List<GithubRepo> getUserRepos(@NotNull GithubConnection connection) throws IOException {
try {
String path = "/user/repos?" + PER_PAGE;
PagedRequest<GithubRepo> request = new PagedRequest<GithubRepo>(path, GithubRepo.class, GithubRepoRaw[].class, ACCEPT_V3_JSON);
- return request.getAll(auth);
+ return request.getAll(connection);
}
catch (GithubConfusingException e) {
e.setDetails("Can't get user repositories");
@@ -596,13 +241,13 @@ public class GithubApiUtil {
}
@NotNull
- public static List<GithubRepo> getUserRepos(@NotNull GithubAuthData auth, @NotNull String user) throws IOException {
+ public static List<GithubRepo> getUserRepos(@NotNull GithubConnection connection, @NotNull String user) throws IOException {
try {
String path = "/users/" + user + "/repos?" + PER_PAGE;
PagedRequest<GithubRepo> request = new PagedRequest<GithubRepo>(path, GithubRepo.class, GithubRepoRaw[].class, ACCEPT_V3_JSON);
- return request.getAll(auth);
+ return request.getAll(connection);
}
catch (GithubConfusingException e) {
e.setDetails("Can't get user repositories: " + user);
@@ -611,21 +256,21 @@ public class GithubApiUtil {
}
@NotNull
- public static List<GithubRepo> getAvailableRepos(@NotNull GithubAuthData auth) throws IOException {
+ public static List<GithubRepo> getAvailableRepos(@NotNull GithubConnection connection) throws IOException {
try {
List<GithubRepo> repos = new ArrayList<GithubRepo>();
- repos.addAll(getUserRepos(auth));
+ repos.addAll(getUserRepos(connection));
// We already can return something useful from getUserRepos, so let's ignore errors.
// One of this may not exist in GitHub enterprise
try {
- repos.addAll(getMembershipRepos(auth));
+ repos.addAll(getMembershipRepos(connection));
}
catch (GithubStatusCodeException ignore) {
}
try {
- repos.addAll(getWatchedRepos(auth));
+ repos.addAll(getWatchedRepos(connection));
}
catch (GithubStatusCodeException ignore) {
}
@@ -639,36 +284,36 @@ public class GithubApiUtil {
}
@NotNull
- public static List<GithubRepoOrg> getMembershipRepos(@NotNull GithubAuthData auth) throws IOException {
+ public static List<GithubRepoOrg> getMembershipRepos(@NotNull GithubConnection connection) throws IOException {
String orgsPath = "/user/orgs?" + PER_PAGE;
PagedRequest<GithubOrg> orgsRequest = new PagedRequest<GithubOrg>(orgsPath, GithubOrg.class, GithubOrgRaw[].class);
List<GithubRepoOrg> repos = new ArrayList<GithubRepoOrg>();
- for (GithubOrg org : orgsRequest.getAll(auth)) {
+ for (GithubOrg org : orgsRequest.getAll(connection)) {
String path = "/orgs/" + org.getLogin() + "/repos?type=member&" + PER_PAGE;
PagedRequest<GithubRepoOrg> request =
new PagedRequest<GithubRepoOrg>(path, GithubRepoOrg.class, GithubRepoRaw[].class, ACCEPT_V3_JSON);
- repos.addAll(request.getAll(auth));
+ repos.addAll(request.getAll(connection));
}
return repos;
}
@NotNull
- public static List<GithubRepo> getWatchedRepos(@NotNull GithubAuthData auth) throws IOException {
+ public static List<GithubRepo> getWatchedRepos(@NotNull GithubConnection connection) throws IOException {
String pathWatched = "/user/subscriptions?" + PER_PAGE;
PagedRequest<GithubRepo> requestWatched =
new PagedRequest<GithubRepo>(pathWatched, GithubRepo.class, GithubRepoRaw[].class, ACCEPT_V3_JSON);
- return requestWatched.getAll(auth);
+ return requestWatched.getAll(connection);
}
@NotNull
- public static GithubRepoDetailed getDetailedRepoInfo(@NotNull GithubAuthData auth, @NotNull String owner, @NotNull String name)
+ public static GithubRepoDetailed getDetailedRepoInfo(@NotNull GithubConnection connection, @NotNull String owner, @NotNull String name)
throws IOException {
try {
final String request = "/repos/" + owner + "/" + name;
- JsonElement jsonObject = getRequest(auth, request, ACCEPT_V3_JSON);
+ JsonElement jsonObject = connection.getRequest(request, ACCEPT_V3_JSON);
return createDataFromRaw(fromJson(jsonObject, GithubRepoRaw.class), GithubRepoDetailed.class);
}
@@ -678,11 +323,11 @@ public class GithubApiUtil {
}
}
- public static void deleteGithubRepository(@NotNull GithubAuthData auth, @NotNull String username, @NotNull String repo)
+ public static void deleteGithubRepository(@NotNull GithubConnection connection, @NotNull String username, @NotNull String repo)
throws IOException {
try {
String path = "/repos/" + username + "/" + repo;
- deleteRequest(auth, path);
+ connection.deleteRequest(path);
}
catch (GithubConfusingException e) {
e.setDetails("Can't delete repository: " + username + "/" + repo);
@@ -690,10 +335,10 @@ public class GithubApiUtil {
}
}
- public static void deleteGist(@NotNull GithubAuthData auth, @NotNull String id) throws IOException {
+ public static void deleteGist(@NotNull GithubConnection connection, @NotNull String id) throws IOException {
try {
String path = "/gists/" + id;
- deleteRequest(auth, path);
+ connection.deleteRequest(path);
}
catch (GithubConfusingException e) {
e.setDetails("Can't delete gist: id - " + id);
@@ -702,10 +347,10 @@ public class GithubApiUtil {
}
@NotNull
- public static GithubGist getGist(@NotNull GithubAuthData auth, @NotNull String id) throws IOException {
+ public static GithubGist getGist(@NotNull GithubConnection connection, @NotNull String id) throws IOException {
try {
String path = "/gists/" + id;
- JsonElement result = getRequest(auth, path, ACCEPT_V3_JSON);
+ JsonElement result = connection.getRequest(path, ACCEPT_V3_JSON);
return createDataFromRaw(fromJson(result, GithubGistRaw.class), GithubGist.class);
}
@@ -716,13 +361,13 @@ public class GithubApiUtil {
}
@NotNull
- public static GithubGist createGist(@NotNull GithubAuthData auth,
+ public static GithubGist createGist(@NotNull GithubConnection connection,
@NotNull List<GithubGist.FileContent> contents,
@NotNull String description,
boolean isPrivate) throws IOException {
try {
String request = gson.toJson(new GithubGistRequest(contents, description, !isPrivate));
- return createDataFromRaw(fromJson(postRequest(auth, "/gists", request, ACCEPT_V3_JSON), GithubGistRaw.class), GithubGist.class);
+ return createDataFromRaw(fromJson(connection.postRequest("/gists", request, ACCEPT_V3_JSON), GithubGistRaw.class), GithubGist.class);
}
catch (GithubConfusingException e) {
e.setDetails("Can't create gist");
@@ -731,7 +376,16 @@ public class GithubApiUtil {
}
@NotNull
- public static GithubPullRequest createPullRequest(@NotNull GithubAuthData auth,
+ public static List<GithubRepo> getForks(@NotNull GithubConnection connection, @NotNull String owner, @NotNull String name)
+ throws IOException {
+ String path = "/repos/" + owner + "/" + name + "/forks?" + PER_PAGE;
+ PagedRequest<GithubRepo> requestWatched =
+ new PagedRequest<GithubRepo>(path, GithubRepo.class, GithubRepoRaw[].class, ACCEPT_V3_JSON);
+ return requestWatched.getAll(connection);
+ }
+
+ @NotNull
+ public static GithubPullRequest createPullRequest(@NotNull GithubConnection connection,
@NotNull String user,
@NotNull String repo,
@NotNull String title,
@@ -741,7 +395,7 @@ public class GithubApiUtil {
try {
String request = gson.toJson(new GithubPullRequestRequest(title, description, head, base));
return createDataFromRaw(
- fromJson(postRequest(auth, "/repos/" + user + "/" + repo + "/pulls", request, ACCEPT_V3_JSON), GithubPullRequestRaw.class),
+ fromJson(connection.postRequest("/repos/" + user + "/" + repo + "/pulls", request, ACCEPT_V3_JSON), GithubPullRequestRaw.class),
GithubPullRequest.class);
}
catch (GithubConfusingException e) {
@@ -751,14 +405,17 @@ public class GithubApiUtil {
}
@NotNull
- public static GithubRepo createRepo(@NotNull GithubAuthData auth, @NotNull String name, @NotNull String description, boolean isPrivate)
+ public static GithubRepo createRepo(@NotNull GithubConnection connection,
+ @NotNull String name,
+ @NotNull String description,
+ boolean isPrivate)
throws IOException {
try {
String path = "/user/repos";
GithubRepoRequest request = new GithubRepoRequest(name, description, isPrivate);
- return createDataFromRaw(fromJson(postRequest(auth, path, gson.toJson(request), ACCEPT_V3_JSON), GithubRepoRaw.class),
+ return createDataFromRaw(fromJson(connection.postRequest(path, gson.toJson(request), ACCEPT_V3_JSON), GithubRepoRaw.class),
GithubRepo.class);
}
catch (GithubConfusingException e) {
@@ -771,7 +428,7 @@ public class GithubApiUtil {
* Open issues only
*/
@NotNull
- public static List<GithubIssue> getIssuesAssigned(@NotNull GithubAuthData auth,
+ public static List<GithubIssue> getIssuesAssigned(@NotNull GithubConnection connection,
@NotNull String user,
@NotNull String repo,
@Nullable String assigned,
@@ -791,7 +448,7 @@ public class GithubApiUtil {
List<GithubIssue> result = new ArrayList<GithubIssue>();
while (request.hasNext() && max > result.size()) {
- result.addAll(request.next(auth));
+ result.addAll(request.next(connection));
}
return result;
}
@@ -805,7 +462,7 @@ public class GithubApiUtil {
/*
* All issues - open and closed
*/
- public static List<GithubIssue> getIssuesQueried(@NotNull GithubAuthData auth,
+ public static List<GithubIssue> getIssuesQueried(@NotNull GithubConnection connection,
@NotNull String user,
@NotNull String repo,
@Nullable String query,
@@ -816,7 +473,7 @@ public class GithubApiUtil {
String path = "/search/issues?q=" + query;
//TODO: Use bodyHtml for issues - GitHub does not support this feature for SearchApi yet
- JsonElement result = getRequest(auth, path, ACCEPT_V3_JSON);
+ JsonElement result = connection.getRequest(path, ACCEPT_V3_JSON);
return createDataFromRaw(fromJson(result, GithubIssuesSearchResultRaw.class), GithubIssuesSearchResult.class).getIssues();
}
@@ -827,12 +484,12 @@ public class GithubApiUtil {
}
@NotNull
- public static GithubIssue getIssue(@NotNull GithubAuthData auth, @NotNull String user, @NotNull String repo, @NotNull String id)
+ public static GithubIssue getIssue(@NotNull GithubConnection connection, @NotNull String user, @NotNull String repo, @NotNull String id)
throws IOException {
try {
String path = "/repos/" + user + "/" + repo + "/issues/" + id;
- JsonElement result = getRequest(auth, path, ACCEPT_V3_JSON);
+ JsonElement result = connection.getRequest(path, ACCEPT_V3_JSON);
return createDataFromRaw(fromJson(result, GithubIssueRaw.class), GithubIssue.class);
}
@@ -843,7 +500,10 @@ public class GithubApiUtil {
}
@NotNull
- public static List<GithubIssueComment> getIssueComments(@NotNull GithubAuthData auth, @NotNull String user, @NotNull String repo, long id)
+ public static List<GithubIssueComment> getIssueComments(@NotNull GithubConnection connection,
+ @NotNull String user,
+ @NotNull String repo,
+ long id)
throws IOException {
try {
String path = "/repos/" + user + "/" + repo + "/issues/" + id + "/comments?" + PER_PAGE;
@@ -851,7 +511,7 @@ public class GithubApiUtil {
PagedRequest<GithubIssueComment> request =
new PagedRequest<GithubIssueComment>(path, GithubIssueComment.class, GithubIssueCommentRaw[].class, ACCEPT_V3_JSON_HTML_MARKUP);
- return request.getAll(auth);
+ return request.getAll(connection);
}
catch (GithubConfusingException e) {
e.setDetails("Can't get issue comments: " + user + "/" + repo + " - " + id);
@@ -859,15 +519,37 @@ public class GithubApiUtil {
}
}
+ public static void setIssueState(@NotNull GithubConnection connection,
+ @NotNull String user,
+ @NotNull String repo,
+ @NotNull String id,
+ boolean open)
+ throws IOException {
+ try {
+ String path = "/repos/" + user + "/" + repo + "/issues/" + id;
+
+ GithubChangeIssueStateRequest request = new GithubChangeIssueStateRequest(open ? "open" : "closed");
+
+ JsonElement result = connection.patchRequest(path, gson.toJson(request), ACCEPT_V3_JSON);
+
+ createDataFromRaw(fromJson(result, GithubIssueRaw.class), GithubIssue.class);
+ }
+ catch (GithubConfusingException e) {
+ e.setDetails("Can't set issue state: " + user + "/" + repo + " - " + id + "@" + (open ? "open" : "closed"));
+ throw e;
+ }
+ }
+
+
@NotNull
- public static GithubCommitDetailed getCommit(@NotNull GithubAuthData auth,
+ public static GithubCommitDetailed getCommit(@NotNull GithubConnection connection,
@NotNull String user,
@NotNull String repo,
@NotNull String sha) throws IOException {
try {
String path = "/repos/" + user + "/" + repo + "/commits/" + sha;
- JsonElement result = getRequest(auth, path, ACCEPT_V3_JSON);
+ JsonElement result = connection.getRequest(path, ACCEPT_V3_JSON);
return createDataFromRaw(fromJson(result, GithubCommitRaw.class), GithubCommitDetailed.class);
}
catch (GithubConfusingException e) {
@@ -877,7 +559,7 @@ public class GithubApiUtil {
}
@NotNull
- public static List<GithubCommitComment> getCommitComments(@NotNull GithubAuthData auth,
+ public static List<GithubCommitComment> getCommitComments(@NotNull GithubConnection connection,
@NotNull String user,
@NotNull String repo,
@NotNull String sha) throws IOException {
@@ -887,7 +569,7 @@ public class GithubApiUtil {
PagedRequest<GithubCommitComment> request =
new PagedRequest<GithubCommitComment>(path, GithubCommitComment.class, GithubCommitCommentRaw[].class, ACCEPT_V3_JSON_HTML_MARKUP);
- return request.getAll(auth);
+ return request.getAll(connection);
}
catch (GithubConfusingException e) {
e.setDetails("Can't get commit comments: " + user + "/" + repo + " - " + sha);
@@ -896,7 +578,7 @@ public class GithubApiUtil {
}
@NotNull
- public static List<GithubCommitComment> getPullRequestComments(@NotNull GithubAuthData auth,
+ public static List<GithubCommitComment> getPullRequestComments(@NotNull GithubConnection connection,
@NotNull String user,
@NotNull String repo,
long id) throws IOException {
@@ -906,7 +588,7 @@ public class GithubApiUtil {
PagedRequest<GithubCommitComment> request =
new PagedRequest<GithubCommitComment>(path, GithubCommitComment.class, GithubCommitCommentRaw[].class, ACCEPT_V3_JSON_HTML_MARKUP);
- return request.getAll(auth);
+ return request.getAll(connection);
}
catch (GithubConfusingException e) {
e.setDetails("Can't get pull request comments: " + user + "/" + repo + " - " + id);
@@ -915,11 +597,11 @@ public class GithubApiUtil {
}
@NotNull
- public static GithubPullRequest getPullRequest(@NotNull GithubAuthData auth, @NotNull String user, @NotNull String repo, int id)
+ public static GithubPullRequest getPullRequest(@NotNull GithubConnection connection, @NotNull String user, @NotNull String repo, int id)
throws IOException {
try {
String path = "/repos/" + user + "/" + repo + "/pulls/" + id;
- return createDataFromRaw(fromJson(getRequest(auth, path, ACCEPT_V3_JSON_HTML_MARKUP), GithubPullRequestRaw.class),
+ return createDataFromRaw(fromJson(connection.getRequest(path, ACCEPT_V3_JSON_HTML_MARKUP), GithubPullRequestRaw.class),
GithubPullRequest.class);
}
catch (GithubConfusingException e) {
@@ -929,7 +611,7 @@ public class GithubApiUtil {
}
@NotNull
- public static List<GithubPullRequest> getPullRequests(@NotNull GithubAuthData auth, @NotNull String user, @NotNull String repo)
+ public static List<GithubPullRequest> getPullRequests(@NotNull GithubConnection connection, @NotNull String user, @NotNull String repo)
throws IOException {
try {
String path = "/repos/" + user + "/" + repo + "/pulls?" + PER_PAGE;
@@ -937,7 +619,7 @@ public class GithubApiUtil {
PagedRequest<GithubPullRequest> request =
new PagedRequest<GithubPullRequest>(path, GithubPullRequest.class, GithubPullRequestRaw[].class, ACCEPT_V3_JSON_HTML_MARKUP);
- return request.getAll(auth);
+ return request.getAll(connection);
}
catch (GithubConfusingException e) {
e.setDetails("Can't get pull requests" + user + "/" + repo);
@@ -953,7 +635,10 @@ public class GithubApiUtil {
}
@NotNull
- public static List<GithubCommit> getPullRequestCommits(@NotNull GithubAuthData auth, @NotNull String user, @NotNull String repo, long id)
+ public static List<GithubCommit> getPullRequestCommits(@NotNull GithubConnection connection,
+ @NotNull String user,
+ @NotNull String repo,
+ long id)
throws IOException {
try {
String path = "/repos/" + user + "/" + repo + "/pulls/" + id + "/commits?" + PER_PAGE;
@@ -961,7 +646,7 @@ public class GithubApiUtil {
PagedRequest<GithubCommit> request =
new PagedRequest<GithubCommit>(path, GithubCommit.class, GithubCommitRaw[].class, ACCEPT_V3_JSON);
- return request.getAll(auth);
+ return request.getAll(connection);
}
catch (GithubConfusingException e) {
e.setDetails("Can't get pull request commits: " + user + "/" + repo + " - " + id);
@@ -970,14 +655,17 @@ public class GithubApiUtil {
}
@NotNull
- public static List<GithubFile> getPullRequestFiles(@NotNull GithubAuthData auth, @NotNull String user, @NotNull String repo, long id)
+ public static List<GithubFile> getPullRequestFiles(@NotNull GithubConnection connection,
+ @NotNull String user,
+ @NotNull String repo,
+ long id)
throws IOException {
try {
String path = "/repos/" + user + "/" + repo + "/pulls/" + id + "/files?" + PER_PAGE;
PagedRequest<GithubFile> request = new PagedRequest<GithubFile>(path, GithubFile.class, GithubFileRaw[].class, ACCEPT_V3_JSON);
- return request.getAll(auth);
+ return request.getAll(connection);
}
catch (GithubConfusingException e) {
e.setDetails("Can't get pull request files: " + user + "/" + repo + " - " + id);
@@ -986,7 +674,7 @@ public class GithubApiUtil {
}
@NotNull
- public static List<GithubBranch> getRepoBranches(@NotNull GithubAuthData auth, @NotNull String user, @NotNull String repo)
+ public static List<GithubBranch> getRepoBranches(@NotNull GithubConnection connection, @NotNull String user, @NotNull String repo)
throws IOException {
try {
String path = "/repos/" + user + "/" + repo + "/branches?" + PER_PAGE;
@@ -994,7 +682,7 @@ public class GithubApiUtil {
PagedRequest<GithubBranch> request =
new PagedRequest<GithubBranch>(path, GithubBranch.class, GithubBranchRaw[].class, ACCEPT_V3_JSON);
- return request.getAll(auth);
+ return request.getAll(connection);
}
catch (GithubConfusingException e) {
e.setDetails("Can't get repository branches: " + user + "/" + repo);
@@ -1003,7 +691,7 @@ public class GithubApiUtil {
}
@Nullable
- public static GithubRepo findForkByUser(@NotNull GithubAuthData auth,
+ public static GithubRepo findForkByUser(@NotNull GithubConnection connection,
@NotNull String user,
@NotNull String repo,
@NotNull String forkUser) throws IOException {
@@ -1013,7 +701,7 @@ public class GithubApiUtil {
PagedRequest<GithubRepo> request = new PagedRequest<GithubRepo>(path, GithubRepo.class, GithubRepoRaw[].class, ACCEPT_V3_JSON);
while (request.hasNext()) {
- for (GithubRepo fork : request.next(auth)) {
+ for (GithubRepo fork : request.next(connection)) {
if (StringUtil.equalsIgnoreCase(fork.getUserName(), forkUser)) {
return fork;
}
@@ -1027,4 +715,4 @@ public class GithubApiUtil {
throw e;
}
}
-} \ No newline at end of file
+}
diff --git a/plugins/github/src/org/jetbrains/plugins/github/api/GithubChangeIssueStateRequest.java b/plugins/github/src/org/jetbrains/plugins/github/api/GithubChangeIssueStateRequest.java
new file mode 100644
index 000000000000..9e21f64046e5
--- /dev/null
+++ b/plugins/github/src/org/jetbrains/plugins/github/api/GithubChangeIssueStateRequest.java
@@ -0,0 +1,12 @@
+package org.jetbrains.plugins.github.api;
+
+import org.jetbrains.annotations.NotNull;
+
+@SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
+public class GithubChangeIssueStateRequest {
+ @NotNull private final String state;
+
+ public GithubChangeIssueStateRequest(@NotNull String state) {
+ this.state = state;
+ }
+}
diff --git a/plugins/github/src/org/jetbrains/plugins/github/api/GithubConnection.java b/plugins/github/src/org/jetbrains/plugins/github/api/GithubConnection.java
new file mode 100644
index 000000000000..6358b79e38ee
--- /dev/null
+++ b/plugins/github/src/org/jetbrains/plugins/github/api/GithubConnection.java
@@ -0,0 +1,491 @@
+package org.jetbrains.plugins.github.api;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonParser;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.util.net.HttpConfigurable;
+import com.intellij.util.net.ssl.CertificateManager;
+import org.apache.http.*;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.Credentials;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.client.CredentialsProvider;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.*;
+import org.apache.http.client.protocol.HttpClientContext;
+import org.apache.http.config.ConnectionConfig;
+import org.apache.http.conn.ssl.X509HostnameVerifier;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.auth.BasicScheme;
+import org.apache.http.impl.client.BasicCredentialsProvider;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.message.BasicHeader;
+import org.apache.http.protocol.HttpContext;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.annotations.TestOnly;
+import org.jetbrains.plugins.github.exceptions.*;
+import org.jetbrains.plugins.github.util.GithubAuthData;
+import org.jetbrains.plugins.github.util.GithubSettings;
+import org.jetbrains.plugins.github.util.GithubUrlUtil;
+import org.jetbrains.plugins.github.util.GithubUtil;
+import sun.security.validator.ValidatorException;
+
+import javax.net.ssl.SSLHandshakeException;
+import java.awt.*;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.*;
+import java.util.List;
+
+import static org.jetbrains.plugins.github.api.GithubApiUtil.createDataFromRaw;
+import static org.jetbrains.plugins.github.api.GithubApiUtil.fromJson;
+
+public class GithubConnection {
+ private static final Logger LOG = GithubUtil.LOG;
+
+ private static final HttpRequestInterceptor PREEMPTIVE_BASIC_AUTH = new PreemptiveBasicAuthInterceptor();
+
+ @NotNull private final String myHost;
+ @NotNull private final CloseableHttpClient myClient;
+ private final boolean myReusable;
+
+ private volatile HttpUriRequest myRequest;
+ private volatile boolean myAborted;
+
+ @TestOnly
+ public GithubConnection(@NotNull GithubAuthData auth) {
+ this(auth, false);
+ }
+
+ public GithubConnection(@NotNull GithubAuthData auth, boolean reusable) {
+ myHost = auth.getHost();
+ myClient = createClient(auth);
+ myReusable = reusable;
+ }
+
+ private enum HttpVerb {
+ GET, POST, DELETE, HEAD, PATCH
+ }
+
+ @Nullable
+ public JsonElement getRequest(@NotNull String path,
+ @NotNull Header... headers) throws IOException {
+ return request(path, null, Arrays.asList(headers), HttpVerb.GET).getJsonElement();
+ }
+
+ @Nullable
+ public JsonElement postRequest(@NotNull String path,
+ @Nullable String requestBody,
+ @NotNull Header... headers) throws IOException {
+ return request(path, requestBody, Arrays.asList(headers), HttpVerb.POST).getJsonElement();
+ }
+
+ @Nullable
+ public JsonElement patchRequest(@NotNull String path,
+ @Nullable String requestBody,
+ @NotNull Header... headers) throws IOException {
+ return request(path, requestBody, Arrays.asList(headers), HttpVerb.PATCH).getJsonElement();
+ }
+
+ @Nullable
+ public JsonElement deleteRequest(@NotNull String path,
+ @NotNull Header... headers) throws IOException {
+ return request(path, null, Arrays.asList(headers), HttpVerb.DELETE).getJsonElement();
+ }
+
+ @NotNull
+ public Header[] headRequest(@NotNull String path,
+ @NotNull Header... headers) throws IOException {
+ return request(path, null, Arrays.asList(headers), HttpVerb.HEAD).getHeaders();
+ }
+
+ public void abort() {
+ if (myAborted) return;
+ myAborted = true;
+
+ HttpUriRequest request = myRequest;
+ if (request != null) request.abort();
+ }
+
+ public void close() throws IOException {
+ myClient.close();
+ }
+
+ @NotNull
+ private static CloseableHttpClient createClient(@NotNull GithubAuthData auth) {
+ HttpClientBuilder builder = HttpClients.custom();
+
+ return builder
+ .setDefaultRequestConfig(createRequestConfig(auth))
+ .setDefaultConnectionConfig(createConnectionConfig(auth))
+ .setDefaultCredentialsProvider(createCredentialsProvider(auth))
+ .setDefaultHeaders(createHeaders(auth))
+ .addInterceptorFirst(PREEMPTIVE_BASIC_AUTH)
+ .setSslcontext(CertificateManager.getInstance().getSslContext())
+ .setHostnameVerifier((X509HostnameVerifier)CertificateManager.HOSTNAME_VERIFIER)
+ .build();
+ }
+
+ @NotNull
+ private static RequestConfig createRequestConfig(@NotNull GithubAuthData auth) {
+ RequestConfig.Builder builder = RequestConfig.custom();
+
+ int timeout = GithubSettings.getInstance().getConnectionTimeout();
+ builder
+ .setConnectTimeout(timeout)
+ .setSocketTimeout(timeout);
+
+ final HttpConfigurable proxySettings = HttpConfigurable.getInstance();
+ if (auth.isUseProxy() && proxySettings.USE_HTTP_PROXY && !StringUtil.isEmptyOrSpaces(proxySettings.PROXY_HOST)) {
+ builder
+ .setProxy(new HttpHost(proxySettings.PROXY_HOST, proxySettings.PROXY_PORT));
+ }
+
+ return builder.build();
+ }
+
+ @NotNull
+ private static ConnectionConfig createConnectionConfig(@NotNull GithubAuthData auth) {
+ return ConnectionConfig.custom()
+ .setCharset(Consts.UTF_8)
+ .build();
+ }
+
+
+ @NotNull
+ private static CredentialsProvider createCredentialsProvider(@NotNull GithubAuthData auth) {
+ CredentialsProvider provider = new BasicCredentialsProvider();
+ // Basic authentication
+ GithubAuthData.BasicAuth basicAuth = auth.getBasicAuth();
+ if (basicAuth != null) {
+ provider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(basicAuth.getLogin(), basicAuth.getPassword()));
+ }
+
+ final HttpConfigurable proxySettings = HttpConfigurable.getInstance();
+ //proxySettings.USE_HTTP_PROXY
+ if (auth.isUseProxy() && proxySettings.USE_HTTP_PROXY && !StringUtil.isEmptyOrSpaces(proxySettings.PROXY_HOST)) {
+ if (proxySettings.PROXY_AUTHENTICATION) {
+ provider.setCredentials(new AuthScope(proxySettings.PROXY_HOST, proxySettings.PROXY_PORT),
+ new UsernamePasswordCredentials(proxySettings.PROXY_LOGIN, proxySettings.getPlainProxyPassword()));
+ }
+ }
+ return provider;
+ }
+
+ @NotNull
+ private static Collection<? extends Header> createHeaders(@NotNull GithubAuthData auth) {
+ List<Header> headers = new ArrayList<Header>();
+ GithubAuthData.TokenAuth tokenAuth = auth.getTokenAuth();
+ if (tokenAuth != null) {
+ headers.add(new BasicHeader("Authorization", "token " + tokenAuth.getToken()));
+ }
+ GithubAuthData.BasicAuth basicAuth = auth.getBasicAuth();
+ if (basicAuth != null && basicAuth.getCode() != null) {
+ headers.add(new BasicHeader("X-GitHub-OTP", basicAuth.getCode()));
+ }
+ return headers;
+ }
+
+ @NotNull
+ private ResponsePage request(@NotNull String path,
+ @Nullable String requestBody,
+ @NotNull Collection<Header> headers,
+ @NotNull HttpVerb verb) throws IOException {
+ if (myAborted) throw new GithubOperationCanceledException();
+
+ if (EventQueue.isDispatchThread() && !ApplicationManager.getApplication().isUnitTestMode()) {
+ LOG.warn("Network operation in EDT"); // TODO: fix
+ }
+
+ CloseableHttpResponse response = null;
+ try {
+ String uri = GithubUrlUtil.getApiUrl(myHost) + path;
+ response = doREST(uri, requestBody, headers, verb);
+
+ if (myAborted) throw new GithubOperationCanceledException();
+
+ checkStatusCode(response, requestBody);
+
+ HttpEntity entity = response.getEntity();
+ if (entity == null) {
+ return createResponse(response);
+ }
+
+ JsonElement ret = parseResponse(entity.getContent());
+ if (ret.isJsonNull()) {
+ return createResponse(response);
+ }
+
+ String newPath = null;
+ Header pageHeader = response.getFirstHeader("Link");
+ if (pageHeader != null) {
+ for (HeaderElement element : pageHeader.getElements()) {
+ NameValuePair rel = element.getParameterByName("rel");
+ if (rel != null && "next".equals(rel.getValue())) {
+ String urlString = element.toString();
+ int begin = urlString.indexOf('<');
+ int end = urlString.lastIndexOf('>');
+ if (begin == -1 || end == -1) {
+ LOG.error("Invalid 'Link' header", "{" + pageHeader.toString() + "}");
+ break;
+ }
+
+ String url = urlString.substring(begin + 1, end);
+ String newUrl = GithubUrlUtil.removeProtocolPrefix(url);
+ int index = newUrl.indexOf('/');
+ newPath = newUrl.substring(index);
+ break;
+ }
+ }
+ }
+
+ return createResponse(ret, newPath, response);
+ }
+ catch (SSLHandshakeException e) { // User canceled operation from CertificateManager
+ if (e.getCause() instanceof ValidatorException) {
+ LOG.info("Host SSL certificate is not trusted", e);
+ throw new GithubOperationCanceledException("Host SSL certificate is not trusted", e);
+ }
+ throw e;
+ }
+ catch (IOException e) {
+ if (myAborted) throw new GithubOperationCanceledException("Operation canceled", e);
+ throw e;
+ }
+ finally {
+ myRequest = null;
+ if (response != null) {
+ response.close();
+ }
+ if (!myReusable) {
+ myClient.close();
+ }
+ }
+ }
+
+ @NotNull
+ private CloseableHttpResponse doREST(@NotNull final String uri,
+ @Nullable final String requestBody,
+ @NotNull final Collection<Header> headers,
+ @NotNull final HttpVerb verb) throws IOException {
+ HttpRequestBase request;
+ switch (verb) {
+ case POST:
+ request = new HttpPost(uri);
+ if (requestBody != null) {
+ ((HttpPost)request).setEntity(new StringEntity(requestBody, ContentType.APPLICATION_JSON));
+ }
+ break;
+ case PATCH:
+ request = new HttpPatch(uri);
+ if (requestBody != null) {
+ ((HttpPatch)request).setEntity(new StringEntity(requestBody, ContentType.APPLICATION_JSON));
+ }
+ break;
+ case GET:
+ request = new HttpGet(uri);
+ break;
+ case DELETE:
+ request = new HttpDelete(uri);
+ break;
+ case HEAD:
+ request = new HttpHead(uri);
+ break;
+ default:
+ throw new IllegalStateException("Unknown HttpVerb: " + verb.toString());
+ }
+
+ for (Header header : headers) {
+ request.addHeader(header);
+ }
+
+ myRequest = request;
+ return myClient.execute(request);
+ }
+
+ private static void checkStatusCode(@NotNull CloseableHttpResponse response, @Nullable String body) throws IOException {
+ int code = response.getStatusLine().getStatusCode();
+ switch (code) {
+ case HttpStatus.SC_OK:
+ case HttpStatus.SC_CREATED:
+ case HttpStatus.SC_ACCEPTED:
+ case HttpStatus.SC_NO_CONTENT:
+ return;
+ case HttpStatus.SC_UNAUTHORIZED:
+ case HttpStatus.SC_PAYMENT_REQUIRED:
+ case HttpStatus.SC_FORBIDDEN:
+ String message = getErrorMessage(response);
+
+ Header headerOTP = response.getFirstHeader("X-GitHub-OTP");
+ if (headerOTP != null) {
+ for (HeaderElement element : headerOTP.getElements()) {
+ if ("required".equals(element.getName())) {
+ throw new GithubTwoFactorAuthenticationException(message);
+ }
+ }
+ }
+
+ if (message.contains("API rate limit exceeded")) {
+ throw new GithubRateLimitExceededException(message);
+ }
+
+ throw new GithubAuthenticationException("Request response: " + message);
+ case HttpStatus.SC_BAD_REQUEST:
+ case HttpStatus.SC_UNPROCESSABLE_ENTITY:
+ if (body != null) {
+ LOG.info(body);
+ }
+ throw new GithubStatusCodeException(code + ": " + getErrorMessage(response), code);
+ default:
+ throw new GithubStatusCodeException(code + ": " + getErrorMessage(response), code);
+ }
+ }
+
+ @NotNull
+ private static String getErrorMessage(@NotNull CloseableHttpResponse response) {
+ try {
+ HttpEntity entity = response.getEntity();
+ if (entity != null) {
+ GithubErrorMessageRaw error = fromJson(parseResponse(entity.getContent()), GithubErrorMessageRaw.class);
+ return response.getStatusLine().getReasonPhrase() + " - " + error.getMessage();
+ }
+ }
+ catch (IOException e) {
+ LOG.info(e);
+ }
+ return response.getStatusLine().getReasonPhrase();
+ }
+
+ @NotNull
+ private static JsonElement parseResponse(@NotNull InputStream githubResponse) throws IOException {
+ Reader reader = new InputStreamReader(githubResponse, "UTF-8");
+ try {
+ return new JsonParser().parse(reader);
+ }
+ catch (JsonParseException jse) {
+ throw new GithubJsonException("Couldn't parse GitHub response", jse);
+ }
+ finally {
+ reader.close();
+ }
+ }
+
+ public static class PagedRequest<T> {
+ @Nullable private String myNextPage;
+ @NotNull private final Collection<Header> myHeaders;
+ @NotNull private final Class<T> myResult;
+ @NotNull private final Class<? extends DataConstructor[]> myRawArray;
+
+ @SuppressWarnings("NullableProblems")
+ public PagedRequest(@NotNull String path,
+ @NotNull Class<T> result,
+ @NotNull Class<? extends DataConstructor[]> rawArray,
+ @NotNull Header... headers) {
+ myNextPage = path;
+ myResult = result;
+ myRawArray = rawArray;
+ myHeaders = Arrays.asList(headers);
+ }
+
+ @NotNull
+ public List<T> next(@NotNull GithubConnection connection) throws IOException {
+ if (myNextPage == null) {
+ throw new NoSuchElementException();
+ }
+
+ String page = myNextPage;
+ myNextPage = null;
+
+ ResponsePage response = connection.request(page, null, myHeaders, HttpVerb.GET);
+
+ if (response.getJsonElement() == null) {
+ throw new GithubConfusingException("Empty response");
+ }
+
+ if (!response.getJsonElement().isJsonArray()) {
+ throw new GithubJsonException("Wrong json type: expected JsonArray", new Exception(response.getJsonElement().toString()));
+ }
+
+ myNextPage = response.getNextPage();
+
+ List<T> result = new ArrayList<T>();
+ for (DataConstructor raw : fromJson(response.getJsonElement().getAsJsonArray(), myRawArray)) {
+ result.add(createDataFromRaw(raw, myResult));
+ }
+ return result;
+ }
+
+ public boolean hasNext() {
+ return myNextPage != null;
+ }
+
+ @NotNull
+ public List<T> getAll(@NotNull GithubConnection connection) throws IOException {
+ List<T> result = new ArrayList<T>();
+ while (hasNext()) {
+ result.addAll(next(connection));
+ }
+ return result;
+ }
+ }
+
+ private ResponsePage createResponse(@NotNull CloseableHttpResponse response) throws GithubOperationCanceledException {
+ if (myAborted) throw new GithubOperationCanceledException();
+
+ return new ResponsePage(null, null, response.getAllHeaders());
+ }
+
+ private ResponsePage createResponse(@NotNull JsonElement ret, @Nullable String path, @NotNull CloseableHttpResponse response)
+ throws GithubOperationCanceledException {
+ if (myAborted) throw new GithubOperationCanceledException();
+
+ return new ResponsePage(ret, path, response.getAllHeaders());
+ }
+
+ private static class ResponsePage {
+ @Nullable private final JsonElement myResponse;
+ @Nullable private final String myNextPage;
+ @NotNull private final Header[] myHeaders;
+
+ public ResponsePage(@Nullable JsonElement response, @Nullable String next, @NotNull Header[] headers) {
+ myResponse = response;
+ myNextPage = next;
+ myHeaders = headers;
+ }
+
+ @Nullable
+ public JsonElement getJsonElement() {
+ return myResponse;
+ }
+
+ @Nullable
+ public String getNextPage() {
+ return myNextPage;
+ }
+
+ @NotNull
+ public Header[] getHeaders() {
+ return myHeaders;
+ }
+ }
+
+ private static class PreemptiveBasicAuthInterceptor implements HttpRequestInterceptor {
+ @Override
+ public void process(HttpRequest request, HttpContext context) throws HttpException, IOException {
+ CredentialsProvider provider = (CredentialsProvider)context.getAttribute(HttpClientContext.CREDS_PROVIDER);
+ Credentials credentials = provider.getCredentials(AuthScope.ANY);
+ if (credentials != null) {
+ request.addHeader(new BasicScheme(Consts.UTF_8).authenticate(credentials, request, context));
+ }
+ }
+ }
+}
diff --git a/plugins/github/src/org/jetbrains/plugins/github/api/GithubFullPath.java b/plugins/github/src/org/jetbrains/plugins/github/api/GithubFullPath.java
index ee0134e4fbc3..1575caee25db 100644
--- a/plugins/github/src/org/jetbrains/plugins/github/api/GithubFullPath.java
+++ b/plugins/github/src/org/jetbrains/plugins/github/api/GithubFullPath.java
@@ -47,14 +47,19 @@ public class GithubFullPath {
}
@Override
+ public String toString() {
+ return "'" + getFullName() + "'";
+ }
+
+ @Override
public boolean equals(@Nullable Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
GithubFullPath that = (GithubFullPath)o;
- if (!StringUtil.endsWithIgnoreCase(myRepositoryName, that.myRepositoryName)) return false;
- if (!StringUtil.endsWithIgnoreCase(myUserName, that.myUserName)) return false;
+ if (!StringUtil.equalsIgnoreCase(myRepositoryName, that.myRepositoryName)) return false;
+ if (!StringUtil.equalsIgnoreCase(myUserName, that.myUserName)) return false;
return true;
}
diff --git a/plugins/github/src/org/jetbrains/plugins/github/api/GithubUser.java b/plugins/github/src/org/jetbrains/plugins/github/api/GithubUser.java
index 29ef1acdfd78..bf81b8d62502 100644
--- a/plugins/github/src/org/jetbrains/plugins/github/api/GithubUser.java
+++ b/plugins/github/src/org/jetbrains/plugins/github/api/GithubUser.java
@@ -26,12 +26,12 @@ public class GithubUser {
@NotNull private final String myHtmlUrl;
- @Nullable private final String myGravatarId;
+ @Nullable private final String myAvatarUrl;
- public GithubUser(@NotNull String login, @NotNull String htmlUrl, @Nullable String gravatarId) {
+ public GithubUser(@NotNull String login, @NotNull String htmlUrl, @Nullable String avatarUrl) {
myLogin = login;
myHtmlUrl = htmlUrl;
- myGravatarId = gravatarId;
+ myAvatarUrl = avatarUrl;
}
@NotNull
@@ -45,7 +45,7 @@ public class GithubUser {
}
@Nullable
- public String getGravatarId() {
- return myGravatarId;
+ public String getAvatarUrl() {
+ return myAvatarUrl;
}
}
diff --git a/plugins/github/src/org/jetbrains/plugins/github/api/GithubUserDetailed.java b/plugins/github/src/org/jetbrains/plugins/github/api/GithubUserDetailed.java
index 2c82c078e339..3940b80f360a 100644
--- a/plugins/github/src/org/jetbrains/plugins/github/api/GithubUserDetailed.java
+++ b/plugins/github/src/org/jetbrains/plugins/github/api/GithubUserDetailed.java
@@ -55,13 +55,13 @@ public class GithubUserDetailed extends GithubUser {
public GithubUserDetailed(@NotNull String login,
@NotNull String htmlUrl,
- @Nullable String gravatarId,
+ @Nullable String avatarUrl,
@Nullable String name,
@Nullable String email,
@Nullable Integer ownedPrivateRepos,
@Nullable String type,
@Nullable UserPlan plan) {
- super(login, htmlUrl, gravatarId);
+ super(login, htmlUrl, avatarUrl);
myName = name;
myEmail = email;
myOwnedPrivateRepos = ownedPrivateRepos;
diff --git a/plugins/github/src/org/jetbrains/plugins/github/api/GithubUserRaw.java b/plugins/github/src/org/jetbrains/plugins/github/api/GithubUserRaw.java
index 04d642f8eb2e..0bc673299847 100644
--- a/plugins/github/src/org/jetbrains/plugins/github/api/GithubUserRaw.java
+++ b/plugins/github/src/org/jetbrains/plugins/github/api/GithubUserRaw.java
@@ -74,14 +74,14 @@ class GithubUserRaw implements DataConstructor {
@SuppressWarnings("ConstantConditions")
@NotNull
public GithubUser createUser() {
- return new GithubUser(login, htmlUrl, gravatarId);
+ return new GithubUser(login, htmlUrl, avatarUrl);
}
@SuppressWarnings("ConstantConditions")
@NotNull
public GithubUserDetailed createUserDetailed() {
GithubUserDetailed.UserPlan plan = this.plan == null ? null : this.plan.create();
- return new GithubUserDetailed(login, htmlUrl, gravatarId, name, email, ownedPrivateRepos, type, plan);
+ return new GithubUserDetailed(login, htmlUrl, avatarUrl, name, email, ownedPrivateRepos, type, plan);
}
@SuppressWarnings("unchecked")
diff --git a/plugins/github/src/org/jetbrains/plugins/github/extensions/GithubCheckoutProvider.java b/plugins/github/src/org/jetbrains/plugins/github/extensions/GithubCheckoutProvider.java
index 6b3f73f5f8be..911314c4f72d 100644
--- a/plugins/github/src/org/jetbrains/plugins/github/extensions/GithubCheckoutProvider.java
+++ b/plugins/github/src/org/jetbrains/plugins/github/extensions/GithubCheckoutProvider.java
@@ -29,6 +29,7 @@ import git4idea.commands.Git;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.github.api.GithubApiUtil;
+import org.jetbrains.plugins.github.api.GithubConnection;
import org.jetbrains.plugins.github.api.GithubRepo;
import org.jetbrains.plugins.github.exceptions.GithubOperationCanceledException;
import org.jetbrains.plugins.github.util.GithubAuthData;
@@ -62,11 +63,11 @@ public class GithubCheckoutProvider implements CheckoutProvider {
@Override
public List<GithubRepo> convert(ProgressIndicator indicator) throws IOException {
return GithubUtil.runTask(project, GithubAuthDataHolder.createFromSettings(), indicator,
- new ThrowableConvertor<GithubAuthData, List<GithubRepo>, IOException>() {
+ new ThrowableConvertor<GithubConnection, List<GithubRepo>, IOException>() {
@NotNull
@Override
- public List<GithubRepo> convert(@NotNull GithubAuthData auth) throws IOException {
- return GithubApiUtil.getAvailableRepos(auth);
+ public List<GithubRepo> convert(@NotNull GithubConnection connection) throws IOException {
+ return GithubApiUtil.getAvailableRepos(connection);
}
}
);
diff --git a/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubComment.java b/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubComment.java
index d65a95044a9c..e3115f71975c 100644
--- a/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubComment.java
+++ b/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubComment.java
@@ -26,16 +26,16 @@ import java.util.Date;
* @author Dennis.Ushakov
*/
public class GithubComment extends SimpleComment {
- @Nullable private final String myGravatarId;
+ @Nullable private final String myAvatarUrl;
@NotNull private final String myUserHtmlUrl;
public GithubComment(@Nullable Date date,
@Nullable String author,
@NotNull String text,
- @Nullable String gravatarId,
+ @Nullable String avatarUrl,
@NotNull String userHtmlUrl) {
super(date, author, text);
- myGravatarId = gravatarId;
+ myAvatarUrl = avatarUrl;
myUserHtmlUrl = userHtmlUrl;
}
@@ -43,9 +43,9 @@ public class GithubComment extends SimpleComment {
builder.append("<hr>");
builder.append("<table>");
builder.append("<tr><td>");
- if (myGravatarId != null) {
- builder.append("<img src=\"").append("http://www.gravatar.com/avatar/").append(myGravatarId).append("?s=40\"/><br>");
- }
+ if (myAvatarUrl != null) {
+ builder.append("<img src=\"").append(myAvatarUrl).append("\" height=\"40\" width=\"40\"/><br>");
+ }
builder.append("</td><td>");
if (getAuthor() != null) {
builder.append("<b>Author:</b> <a href=\"").append(myUserHtmlUrl).append("\">").append(getAuthor()).append("</a><br>");
diff --git a/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepository.java b/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepository.java
index 7ad3238f8a12..a8445b7f76ac 100644
--- a/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepository.java
+++ b/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepository.java
@@ -5,10 +5,7 @@ import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.PasswordUtil;
import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.tasks.Comment;
-import com.intellij.tasks.Task;
-import com.intellij.tasks.TaskRepository;
-import com.intellij.tasks.TaskType;
+import com.intellij.tasks.*;
import com.intellij.tasks.impl.BaseRepository;
import com.intellij.tasks.impl.BaseRepositoryImpl;
import com.intellij.util.Function;
@@ -19,12 +16,10 @@ import icons.TasksIcons;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.github.api.GithubApiUtil;
+import org.jetbrains.plugins.github.api.GithubConnection;
import org.jetbrains.plugins.github.api.GithubIssue;
import org.jetbrains.plugins.github.api.GithubIssueComment;
-import org.jetbrains.plugins.github.exceptions.GithubAuthenticationException;
-import org.jetbrains.plugins.github.exceptions.GithubJsonException;
-import org.jetbrains.plugins.github.exceptions.GithubRateLimitExceededException;
-import org.jetbrains.plugins.github.exceptions.GithubStatusCodeException;
+import org.jetbrains.plugins.github.exceptions.*;
import org.jetbrains.plugins.github.util.GithubAuthData;
import org.jetbrains.plugins.github.util.GithubUtil;
@@ -67,14 +62,20 @@ public class GithubRepository extends BaseRepositoryImpl {
@Override
public CancellableConnection createCancellableConnection() {
return new CancellableConnection() {
+ private final GithubConnection myConnection = new GithubConnection(getAuthData(), false);
+
@Override
protected void doTest() throws Exception {
- getIssues("", 10, false);
+ try {
+ GithubApiUtil.getIssuesQueried(myConnection, getRepoAuthor(), getRepoName(), "", false);
+ }
+ catch (GithubOperationCanceledException ignore) {
+ }
}
@Override
public void cancel() {
- // TODO
+ myConnection.abort();
}
};
}
@@ -122,23 +123,30 @@ public class GithubRepository extends BaseRepositoryImpl {
@NotNull
private Task[] getIssues(@Nullable String query, int max, boolean withClosed) throws Exception {
- List<GithubIssue> issues;
- if (StringUtil.isEmptyOrSpaces(query)) {
- if (StringUtil.isEmptyOrSpaces(myUser)) {
- myUser = GithubApiUtil.getCurrentUser(getAuthData()).getLogin();
+ GithubConnection connection = getConnection();
+
+ try {
+ List<GithubIssue> issues;
+ if (StringUtil.isEmptyOrSpaces(query)) {
+ if (StringUtil.isEmptyOrSpaces(myUser)) {
+ myUser = GithubApiUtil.getCurrentUser(connection).getLogin();
+ }
+ issues = GithubApiUtil.getIssuesAssigned(connection, getRepoAuthor(), getRepoName(), myUser, max, withClosed);
+ }
+ else {
+ issues = GithubApiUtil.getIssuesQueried(connection, getRepoAuthor(), getRepoName(), query, withClosed);
}
- issues = GithubApiUtil.getIssuesAssigned(getAuthData(), getRepoAuthor(), getRepoName(), myUser, max, withClosed);
+
+ return ContainerUtil.map2Array(issues, Task.class, new Function<GithubIssue, Task>() {
+ @Override
+ public Task fun(GithubIssue issue) {
+ return createTask(issue);
+ }
+ });
}
- else {
- issues = GithubApiUtil.getIssuesQueried(getAuthData(), getRepoAuthor(), getRepoName(), query, withClosed);
+ finally {
+ connection.close();
}
-
- return ContainerUtil.map2Array(issues, Task.class, new Function<GithubIssue, Task>() {
- @Override
- public Task fun(GithubIssue issue) {
- return createTask(issue);
- }
- });
}
@NotNull
@@ -224,16 +232,22 @@ public class GithubRepository extends BaseRepositoryImpl {
}
private Comment[] fetchComments(final long id) throws Exception {
- List<GithubIssueComment> result = GithubApiUtil.getIssueComments(getAuthData(), getRepoAuthor(), getRepoName(), id);
-
- return ContainerUtil.map2Array(result, Comment.class, new Function<GithubIssueComment, Comment>() {
- @Override
- public Comment fun(GithubIssueComment comment) {
- return new GithubComment(comment.getCreatedAt(), comment.getUser().getLogin(), comment.getBodyHtml(),
- comment.getUser().getGravatarId(),
- comment.getUser().getHtmlUrl());
- }
- });
+ GithubConnection connection = getConnection();
+ try {
+ List<GithubIssueComment> result = GithubApiUtil.getIssueComments(connection, getRepoAuthor(), getRepoName(), id);
+
+ return ContainerUtil.map2Array(result, Comment.class, new Function<GithubIssueComment, Comment>() {
+ @Override
+ public Comment fun(GithubIssueComment comment) {
+ return new GithubComment(comment.getCreatedAt(), comment.getUser().getLogin(), comment.getBodyHtml(),
+ comment.getUser().getAvatarUrl(),
+ comment.getUser().getHtmlUrl());
+ }
+ });
+ }
+ finally {
+ connection.close();
+ }
}
@Nullable
@@ -245,7 +259,35 @@ public class GithubRepository extends BaseRepositoryImpl {
@Nullable
@Override
public Task findTask(@NotNull String id) throws Exception {
- return createTask(GithubApiUtil.getIssue(getAuthData(), getRepoAuthor(), getRepoName(), id));
+ GithubConnection connection = getConnection();
+ try {
+ return createTask(GithubApiUtil.getIssue(connection, getRepoAuthor(), getRepoName(), id));
+ }
+ finally {
+ connection.close();
+ }
+ }
+
+ @Override
+ public void setTaskState(@NotNull Task task, @NotNull TaskState state) throws Exception {
+ GithubConnection connection = getConnection();
+ try {
+ boolean isOpen;
+ switch (state) {
+ case OPEN:
+ isOpen = true;
+ break;
+ case RESOLVED:
+ isOpen = false;
+ break;
+ default:
+ throw new IllegalStateException("Unknown state: " + state);
+ }
+ GithubApiUtil.setIssueState(connection, getRepoAuthor(), getRepoName(), task.getNumber(), isOpen);
+ }
+ finally {
+ connection.close();
+ }
}
@NotNull
@@ -311,6 +353,10 @@ public class GithubRepository extends BaseRepositoryImpl {
return GithubAuthData.createTokenAuth(getUrl(), getToken(), isUseProxy());
}
+ private GithubConnection getConnection() {
+ return new GithubConnection(getAuthData(), true);
+ }
+
@Override
public boolean equals(Object o) {
if (!super.equals(o)) return false;
@@ -326,6 +372,6 @@ public class GithubRepository extends BaseRepositoryImpl {
@Override
protected int getFeatures() {
- return super.getFeatures() | BASIC_HTTP_AUTHORIZATION;
+ return super.getFeatures() | STATE_UPDATING;
}
}
diff --git a/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepositoryEditor.java b/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepositoryEditor.java
index 5333d82e3baf..ba863621c969 100644
--- a/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepositoryEditor.java
+++ b/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepositoryEditor.java
@@ -14,8 +14,7 @@ import com.intellij.util.ui.GridBag;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.github.api.GithubApiUtil;
-import org.jetbrains.plugins.github.exceptions.GithubOperationCanceledException;
-import org.jetbrains.plugins.github.util.GithubAuthData;
+import org.jetbrains.plugins.github.api.GithubConnection;
import org.jetbrains.plugins.github.util.GithubAuthDataHolder;
import org.jetbrains.plugins.github.util.GithubNotifications;
import org.jetbrains.plugins.github.util.GithubUtil;
@@ -126,12 +125,12 @@ public class GithubRepositoryEditor extends BaseRepositoryEditor<GithubRepositor
public String convert(ProgressIndicator indicator) throws IOException {
return GithubUtil
.runTaskWithBasicAuthForHost(myProject, GithubAuthDataHolder.createFromSettings(), indicator, getHost(),
- new ThrowableConvertor<GithubAuthData, String, IOException>() {
+ new ThrowableConvertor<GithubConnection, String, IOException>() {
@NotNull
@Override
- public String convert(@NotNull GithubAuthData auth) throws IOException {
+ public String convert(@NotNull GithubConnection connection) throws IOException {
return GithubApiUtil
- .getReadOnlyToken(auth, getRepoAuthor(), getRepoName(), "IntelliJ tasks plugin");
+ .getReadOnlyToken(connection, getRepoAuthor(), getRepoName(), "IntelliJ tasks plugin");
}
}
);
diff --git a/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepositoryType.java b/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepositoryType.java
index a677fad0d781..eefab9065add 100644
--- a/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepositoryType.java
+++ b/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepositoryType.java
@@ -2,6 +2,7 @@ package org.jetbrains.plugins.github.tasks;
import com.intellij.openapi.project.Project;
import com.intellij.tasks.TaskRepository;
+import com.intellij.tasks.TaskState;
import com.intellij.tasks.config.TaskRepositoryEditor;
import com.intellij.tasks.impl.BaseRepositoryType;
import com.intellij.util.Consumer;
@@ -9,6 +10,7 @@ import icons.TasksIcons;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
+import java.util.EnumSet;
/**
* @author Dennis.Ushakov
@@ -45,4 +47,9 @@ public class GithubRepositoryType extends BaseRepositoryType<GithubRepository> {
Consumer<GithubRepository> changeListener) {
return new GithubRepositoryEditor(project, repository, changeListener);
}
+
+ public EnumSet<TaskState> getPossibleTaskStates() {
+ return EnumSet.of(TaskState.OPEN, TaskState.RESOLVED);
+ }
+
}
diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java
index f062742d191c..482ef9492fdc 100644
--- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java
+++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestDialog.java
@@ -15,142 +15,159 @@
*/
package org.jetbrains.plugins.github.ui;
+import com.intellij.CommonBundle;
+import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.ValidationInfo;
+import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.util.Consumer;
-import com.intellij.util.ui.UIUtil;
+import com.intellij.util.ThreeState;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import org.jetbrains.plugins.github.GithubCreatePullRequestWorker;
import org.jetbrains.plugins.github.api.GithubFullPath;
+import org.jetbrains.plugins.github.util.GithubNotifications;
import org.jetbrains.plugins.github.util.GithubProjectSettings;
+import org.jetbrains.plugins.github.util.GithubSettings;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
-import java.util.Collection;
import java.util.Collections;
+import static org.jetbrains.plugins.github.GithubCreatePullRequestWorker.BranchInfo;
+import static org.jetbrains.plugins.github.GithubCreatePullRequestWorker.ForkInfo;
+
/**
* @author Aleksey Pivovarov
*/
public class GithubCreatePullRequestDialog extends DialogWrapper {
- @NotNull private final GithubCreatePullRequestPanel myGithubCreatePullRequestPanel;
+ @NotNull private final GithubCreatePullRequestPanel myPanel;
@NotNull private final GithubCreatePullRequestWorker myWorker;
@NotNull private final GithubProjectSettings myProjectSettings;
+ @NotNull private static final CreateRemoteDoNotAskOption ourDoNotAskOption = new CreateRemoteDoNotAskOption();
- public GithubCreatePullRequestDialog(@NotNull GithubCreatePullRequestWorker worker) {
- super(worker.getProject(), true);
+ public GithubCreatePullRequestDialog(@NotNull final Project project, @NotNull GithubCreatePullRequestWorker worker) {
+ super(project, true);
myWorker = worker;
- myProjectSettings = GithubProjectSettings.getInstance(myWorker.getProject());
-
- myGithubCreatePullRequestPanel = new GithubCreatePullRequestPanel();
+ myProjectSettings = GithubProjectSettings.getInstance(project);
- myGithubCreatePullRequestPanel.getShowDiffButton().addActionListener(new ActionListener() {
+ myPanel = new GithubCreatePullRequestPanel();
+ myPanel.getShowDiffButton().addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
- myWorker.showDiffDialog(myGithubCreatePullRequestPanel.getBranch());
+ myWorker.showDiffDialog(myPanel.getSelectedBranch());
}
});
- myGithubCreatePullRequestPanel.getSelectForkButton().addActionListener(new ActionListener() {
+ myPanel.getSelectForkButton().addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
- showTargetDialog();
+ ForkInfo fork = myWorker.showTargetDialog();
+ if (fork != null) {
+ myPanel.setForks(myWorker.getForks());
+ myPanel.setSelectedFork(fork.getPath());
+ }
}
});
- myGithubCreatePullRequestPanel.getBranchComboBox().addItemListener(new ItemListener() {
+
+ myPanel.getForkComboBox().addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
+ if (e.getStateChange() == ItemEvent.DESELECTED) {
+ myPanel.setBranches(Collections.<BranchInfo>emptyList());
+ }
if (e.getStateChange() == ItemEvent.SELECTED) {
- if (myWorker.canShowDiff()) {
- myGithubCreatePullRequestPanel.setBusy(true);
- myWorker.getDiffDescriptionInPooledThread(getTargetBranch(), new Consumer<GithubCreatePullRequestWorker.DiffDescription>() {
- @Override
- public void consume(final GithubCreatePullRequestWorker.DiffDescription info) {
- UIUtil.invokeLaterIfNeeded(new Runnable() {
- @Override
- public void run() {
- if (info == null) {
- myGithubCreatePullRequestPanel.setBusy(false);
- return;
- }
- if (getTargetBranch().equals(info.getBranch())) {
- myGithubCreatePullRequestPanel.setBusy(false);
- if (myGithubCreatePullRequestPanel.isTitleDescriptionEmptyOrNotModified()) {
- myGithubCreatePullRequestPanel.setTitle(info.getTitle());
- myGithubCreatePullRequestPanel.setDescription(info.getDescription());
- }
- }
- }
- });
- }
- });
+ final ForkInfo fork = (ForkInfo)e.getItem();
+ if (fork == null) return;
+
+ myPanel.setBranches(fork.getBranches());
+ myPanel.setSelectedBranch(fork.getDefaultBranch());
+
+ if (fork.getRemoteName() == null && !fork.isProposedToCreateRemote()) {
+ fork.setProposedToCreateRemote(true);
+ boolean createRemote = false;
+
+ switch (GithubSettings.getInstance().getCreatePullRequestCreateRemote()) {
+ case YES:
+ createRemote = true;
+ break;
+ case NO:
+ createRemote = false;
+ break;
+ case UNSURE:
+ createRemote = GithubNotifications.showYesNoDialog(project,
+ "Can't Find Remote",
+ "Configure remote for '" + fork.getPath().getUser() + "'?",
+ ourDoNotAskOption) == Messages.YES;
+ break;
+ }
+
+ if (createRemote) {
+ myWorker.configureRemote(fork);
+ }
+ }
+
+ if (fork.getRemoteName() == null) {
+ myPanel.setDiffEnabled(false);
+ }
+ else {
+ myPanel.setDiffEnabled(true);
+ myWorker.launchFetchRemote(fork);
}
}
}
});
- setTitle("Create Pull Request - " + myWorker.getCurrentBranch());
- init();
- }
-
- @Override
- public void show() {
- GithubFullPath defaultForkPath = myProjectSettings.getCreatePullRequestDefaultRepo();
- if (defaultForkPath != null) {
- setTarget(defaultForkPath);
- }
- else {
- if (!showTargetDialog(true)) {
- close(CANCEL_EXIT_CODE);
- return;
- }
- }
- super.show();
- }
-
- private boolean showTargetDialog() {
- return showTargetDialog(false);
- }
+ myPanel.getBranchComboBox().addItemListener(new ItemListener() {
+ @Override
+ public void itemStateChanged(ItemEvent e) {
+ if (e.getStateChange() == ItemEvent.SELECTED) {
+ BranchInfo branch = (BranchInfo)e.getItem();
+ if (branch == null) return;
- private boolean showTargetDialog(boolean firstTime) {
- GithubFullPath forkPath = myWorker.showTargetDialog(firstTime);
- if (forkPath == null) {
- return false;
- }
- return setTarget(forkPath);
- }
+ if (branch.getForkInfo().getRemoteName() != null) {
+ if (branch.getDiffInfoTask() != null && branch.getDiffInfoTask().isDone() && branch.getDiffInfoTask().safeGet() == null) {
+ myPanel.setDiffEnabled(false);
+ }
+ else {
+ myPanel.setDiffEnabled(true);
+ }
+ }
- private boolean setTarget(@NotNull GithubFullPath forkPath) {
- GithubCreatePullRequestWorker.GithubTargetInfo forkInfo = myWorker.setTarget(forkPath);
- if (forkInfo == null) {
- return false;
- }
- myProjectSettings.setCreatePullRequestDefaultRepo(forkPath);
- myGithubCreatePullRequestPanel.setDiffEnabled(myWorker.canShowDiff());
- updateBranches(forkInfo.getBranches(), forkPath);
- return true;
- }
+ if (myPanel.isTitleDescriptionEmptyOrNotModified()) {
+ Pair<String, String> description = myWorker.getDefaultDescriptionMessage(branch);
+ myPanel.setTitle(description.getFirst());
+ myPanel.setDescription(description.getSecond());
+ }
- private void updateBranches(@NotNull Collection<String> branches, @NotNull GithubFullPath forkPath) {
- myGithubCreatePullRequestPanel.setBranches(branches);
+ myWorker.launchLoadDiffInfo(branch);
+ }
+ }
+ });
- String configBranch = myProjectSettings.getCreatePullRequestDefaultBranch();
- if (configBranch != null) myGithubCreatePullRequestPanel.setSelectedBranch(configBranch);
+ myPanel.setForks(myWorker.getForks());
+ myPanel.setSelectedFork(myProjectSettings.getCreatePullRequestDefaultRepo());
+ myPanel.setSelectedBranch(myProjectSettings.getCreatePullRequestDefaultBranch());
- myGithubCreatePullRequestPanel.setForkName(forkPath.getFullName());
+ setTitle("Create Pull Request - " + myWorker.getCurrentBranch());
+ init();
}
@Override
protected void doOKAction() {
- if (myWorker.checkAction(getTargetBranch())) {
- myProjectSettings.setCreatePullRequestDefaultBranch(getTargetBranch());
- myWorker.performAction(getRequestTitle(), getDescription(), getTargetBranch());
+ BranchInfo branch = myPanel.getSelectedBranch();
+ if (myWorker.checkAction(branch)) {
+ assert branch != null;
+ myWorker.createPullRequest(branch, getRequestTitle(), getDescription());
+
+ myProjectSettings.setCreatePullRequestDefaultBranch(branch.getRemoteName());
+ myProjectSettings.setCreatePullRequestDefaultRepo(branch.getForkInfo().getPath());
+
super.doOKAction();
}
}
@@ -158,13 +175,13 @@ public class GithubCreatePullRequestDialog extends DialogWrapper {
@Nullable
@Override
protected JComponent createCenterPanel() {
- return myGithubCreatePullRequestPanel.getPanel();
+ return myPanel.getPanel();
}
@Nullable
@Override
public JComponent getPreferredFocusedComponent() {
- return myGithubCreatePullRequestPanel.getPreferredComponent();
+ return myPanel.getPreferredComponent();
}
@Override
@@ -179,50 +196,76 @@ public class GithubCreatePullRequestDialog extends DialogWrapper {
@NotNull
private String getRequestTitle() {
- return myGithubCreatePullRequestPanel.getTitle();
+ return myPanel.getTitle();
}
@NotNull
private String getDescription() {
- return myGithubCreatePullRequestPanel.getDescription();
- }
-
- @NotNull
- private String getTargetBranch() {
- return myGithubCreatePullRequestPanel.getBranch();
+ return myPanel.getDescription();
}
@Nullable
@Override
protected ValidationInfo doValidate() {
if (StringUtil.isEmptyOrSpaces(getRequestTitle())) {
- return new ValidationInfo("Title can't be empty'", myGithubCreatePullRequestPanel.getTitleTextField());
+ return new ValidationInfo("Title can't be empty'", myPanel.getTitleTextField());
}
return null;
}
@TestOnly
public void testSetRequestTitle(String title) {
- myGithubCreatePullRequestPanel.setTitle(title);
+ myPanel.setTitle(title);
}
@TestOnly
public void testSetBranch(String branch) {
- myGithubCreatePullRequestPanel.setBranches(Collections.singleton(branch));
+ myPanel.setSelectedBranch(branch);
}
@TestOnly
public void testCreatePullRequest() {
- myWorker.performAction(getRequestTitle(), getDescription(), getTargetBranch());
+ myWorker.createPullRequest(myPanel.getSelectedBranch(), getRequestTitle(), getDescription());
}
@TestOnly
- public void testSetTarget(@NotNull GithubFullPath forkPath) {
- GithubCreatePullRequestWorker.GithubTargetInfo forkInfo = myWorker.setTarget(forkPath);
- if (forkInfo == null) {
- doCancelAction();
- return;
+ public void testSetFork(@NotNull GithubFullPath forkPath) {
+ myPanel.setSelectedFork(forkPath);
+ }
+
+ private static class CreateRemoteDoNotAskOption implements DoNotAskOption {
+ @Override
+ public boolean isToBeShown() {
+ return true;
+ }
+
+ @Override
+ public void setToBeShown(boolean value, int exitCode) {
+ if (value) {
+ GithubSettings.getInstance().setCreatePullRequestCreateRemote(ThreeState.UNSURE);
+ }
+ else if (exitCode == DialogWrapper.OK_EXIT_CODE) {
+ GithubSettings.getInstance().setCreatePullRequestCreateRemote(ThreeState.YES);
+ }
+ else {
+ GithubSettings.getInstance().setCreatePullRequestCreateRemote(ThreeState.NO);
+ }
+ }
+
+ @Override
+ public boolean canBeHidden() {
+ return true;
+ }
+
+ @Override
+ public boolean shouldSaveOptionsOnCancel() {
+ return false;
+ }
+
+ @NotNull
+ @Override
+ public String getDoNotShowMessage() {
+ return CommonBundle.message("dialog.options.do.not.ask");
}
- myGithubCreatePullRequestPanel.setDiffEnabled(myWorker.canShowDiff());
}
}
diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.form b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.form
index e19b8601fa01..342fcfaecde7 100644
--- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.form
+++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.form
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.jetbrains.plugins.github.ui.GithubCreatePullRequestPanel">
- <grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="5" column-count="4" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+ <grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="5" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<xy x="20" y="20" width="500" height="400"/>
@@ -34,7 +34,7 @@
</component>
<component id="996e9" class="javax.swing.JTextField" binding="myTitleTextField">
<constraints>
- <grid row="2" column="1" row-span="1" col-span="3" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
+ <grid row="2" column="1" row-span="1" col-span="2" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
<preferred-size width="150" height="-1"/>
</grid>
</constraints>
@@ -42,7 +42,7 @@
</component>
<scrollpane id="61e54" class="com.intellij.ui.components.JBScrollPane">
<constraints>
- <grid row="4" column="0" row-span="1" col-span="4" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false">
+ <grid row="4" column="0" row-span="1" col-span="3" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false">
<minimum-size width="150" height="50"/>
</grid>
</constraints>
@@ -57,7 +57,7 @@
</scrollpane>
<component id="90c93" class="javax.swing.JButton" binding="myShowDiffButton">
<constraints>
- <grid row="1" column="3" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+ <grid row="1" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Show Diff"/>
@@ -73,26 +73,12 @@
</component>
<component id="a5106" class="javax.swing.JButton" binding="mySelectForkButton">
<constraints>
- <grid row="0" column="3" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+ <grid row="0" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
- <text value="Select Base Fork"/>
+ <text value="Select Other Fork"/>
</properties>
</component>
- <component id="e5548" class="javax.swing.JLabel" binding="myForkLabel">
- <constraints>
- <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
- </constraints>
- <properties>
- <text value="repo"/>
- </properties>
- </component>
- <component id="e5988" class="com.intellij.util.ui.AsyncProcessIcon" binding="myBusyIcon" custom-create="true">
- <constraints>
- <grid row="1" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
- </constraints>
- <properties/>
- </component>
<component id="78a64" class="com.intellij.openapi.ui.ComboBox" binding="myBranchComboBox">
<constraints>
<grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="8" fill="1" indent="0" use-parent-layout="false"/>
@@ -102,6 +88,12 @@
<toolTipText value=""/>
</properties>
</component>
+ <component id="952ec" class="com.intellij.openapi.ui.ComboBox" binding="myForkComboBox">
+ <constraints>
+ <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties/>
+ </component>
</children>
</grid>
</form>
diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.java
index 41512465eeea..f17562f12600 100644
--- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.java
+++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubCreatePullRequestPanel.java
@@ -19,9 +19,9 @@ import com.intellij.openapi.ui.ComboBox;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.DocumentAdapter;
import com.intellij.ui.SortedComboBoxModel;
-import com.intellij.util.ui.AsyncProcessIcon;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import org.jetbrains.plugins.github.api.GithubFullPath;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
@@ -29,6 +29,9 @@ import javax.swing.event.DocumentListener;
import java.util.Collection;
import java.util.Comparator;
+import static org.jetbrains.plugins.github.GithubCreatePullRequestWorker.BranchInfo;
+import static org.jetbrains.plugins.github.GithubCreatePullRequestWorker.ForkInfo;
+
/**
* @author Aleksey Pivovarov
*/
@@ -36,25 +39,35 @@ public class GithubCreatePullRequestPanel {
private JTextField myTitleTextField;
private JTextArea myDescriptionTextArea;
private ComboBox myBranchComboBox;
- private SortedComboBoxModel<String> myBranchModel;
+ private SortedComboBoxModel<ForkInfo> myForkModel;
+ private SortedComboBoxModel<BranchInfo> myBranchModel;
private JPanel myPanel;
private JButton myShowDiffButton;
private JButton mySelectForkButton;
private JLabel myForkLabel;
- private AsyncProcessIcon myBusyIcon;
+ private ComboBox myForkComboBox;
private boolean myTitleDescriptionUserModified = false;
public GithubCreatePullRequestPanel() {
myDescriptionTextArea.setBorder(BorderFactory.createEtchedBorder());
- myBranchModel = new SortedComboBoxModel<String>(new Comparator<String>() {
+
+ myBranchModel = new SortedComboBoxModel<BranchInfo>(new Comparator<BranchInfo>() {
@Override
- public int compare(String o1, String o2) {
- return StringUtil.naturalCompare(o1, o2);
+ public int compare(BranchInfo o1, BranchInfo o2) {
+ return StringUtil.naturalCompare(o1.getRemoteName(), o2.getRemoteName());
}
});
myBranchComboBox.setModel(myBranchModel);
+ myForkModel = new SortedComboBoxModel<ForkInfo>(new Comparator<ForkInfo>() {
+ @Override
+ public int compare(ForkInfo o1, ForkInfo o2) {
+ return StringUtil.naturalCompare(o1.getPath().getUser(), o2.getPath().getUser());
+ }
+ });
+ myForkComboBox.setModel(myForkModel);
+
DocumentListener userModifiedDocumentListener = new DocumentAdapter() {
@Override
protected void textChanged(DocumentEvent e) {
@@ -75,43 +88,69 @@ public class GithubCreatePullRequestPanel {
return myDescriptionTextArea.getText();
}
- @NotNull
- public String getBranch() {
- return myBranchComboBox.getSelectedItem().toString();
+ @Nullable
+ public ForkInfo getSelectedFork() {
+ return myForkModel.getSelectedItem();
}
- public void setDiffEnabled(boolean enabled) {
- myShowDiffButton.setEnabled(enabled);
+ @Nullable
+ public BranchInfo getSelectedBranch() {
+ return myBranchModel.getSelectedItem();
}
- public void setSelectedBranch(@Nullable String branch) {
- if (StringUtil.isEmptyOrSpaces(branch)) {
- return;
+ public void setSelectedFork(@Nullable GithubFullPath path) {
+ if (path != null) {
+ for (ForkInfo info : myForkModel.getItems()) {
+ if (path.equals(info.getPath())) {
+ myForkModel.setSelectedItem(info);
+ return;
+ }
+ }
}
- myBranchComboBox.setSelectedItem(branch);
+ if (myForkModel.getSize() > 0) myForkModel.setSelectedItem(myForkModel.get(0));
}
- public void setBranches(@NotNull Collection<String> branches) {
- myBranchModel.clear();
- myBranchModel.addAll(branches);
- if (branches.size() > 0) {
- myBranchComboBox.setSelectedIndex(0);
+ public void setSelectedBranch(@Nullable String branch) {
+ if (branch != null) {
+ for (BranchInfo info : myBranchModel.getItems()) {
+ if (branch.equals(info.getRemoteName())) {
+ myBranchModel.setSelectedItem(info);
+ return;
+ }
+ }
}
+
+ if (myBranchModel.getSize() > 0) myBranchModel.setSelectedItem(myBranchModel.get(0));
}
- public JPanel getPanel() {
- return myPanel;
+ public void setForks(@NotNull Collection<ForkInfo> forks) {
+ myForkModel.setSelectedItem(null);
+ myForkModel.setAll(forks);
}
- @NotNull
- public JComponent getPreferredComponent() {
- return myTitleTextField;
+ public void setBranches(@NotNull Collection<BranchInfo> branches) {
+ myBranchModel.setSelectedItem(null);
+ myBranchModel.setAll(branches);
}
- @NotNull
- public JComponent getBranchEditor() {
- return myBranchComboBox;
+ public void setTitle(@Nullable String title) {
+ myTitleTextField.setText(title);
+ myTitleDescriptionUserModified = false;
+ }
+
+ public void setDescription(@Nullable String title) {
+ myDescriptionTextArea.setText(title);
+ myTitleDescriptionUserModified = false;
+ }
+
+ public boolean isTitleDescriptionEmptyOrNotModified() {
+ return !myTitleDescriptionUserModified ||
+ (StringUtil.isEmptyOrSpaces(myTitleTextField.getText()) && StringUtil.isEmptyOrSpaces(myDescriptionTextArea.getText()));
+ }
+
+ public void setDiffEnabled(boolean enabled) {
+ myShowDiffButton.setEnabled(enabled);
}
@NotNull
@@ -120,13 +159,18 @@ public class GithubCreatePullRequestPanel {
}
@NotNull
+ public JButton getSelectForkButton() {
+ return mySelectForkButton;
+ }
+
+ @NotNull
public JButton getShowDiffButton() {
return myShowDiffButton;
}
@NotNull
- public JButton getSelectForkButton() {
- return mySelectForkButton;
+ public ComboBox getForkComboBox() {
+ return myForkComboBox;
}
@NotNull
@@ -134,36 +178,12 @@ public class GithubCreatePullRequestPanel {
return myBranchComboBox;
}
- public void setTitle(@Nullable String title) {
- myTitleTextField.setText(title);
- myTitleDescriptionUserModified = false;
- }
-
- public void setDescription(@Nullable String title) {
- myDescriptionTextArea.setText(title);
- myTitleDescriptionUserModified = false;
- }
-
- public boolean isTitleDescriptionEmptyOrNotModified() {
- return !myTitleDescriptionUserModified ||
- (StringUtil.isEmptyOrSpaces(myTitleTextField.getText()) && StringUtil.isEmptyOrSpaces(myDescriptionTextArea.getText()));
- }
-
- public void setForkName(@NotNull String forkName) {
- myForkLabel.setText(forkName);
- }
-
- public void setBusy(boolean enabled) {
- if (enabled) {
- myBusyIcon.resume();
- }
- else {
- myBusyIcon.suspend();
- }
+ public JPanel getPanel() {
+ return myPanel;
}
- private void createUIComponents() {
- myBusyIcon = new AsyncProcessIcon("Loading diff...");
- myBusyIcon.suspend();
+ @NotNull
+ public JComponent getPreferredComponent() {
+ return myTitleTextField;
}
}
diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkDialog.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkDialog.java
index d8ce684eeb38..cea8d206a845 100644
--- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkDialog.java
+++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkDialog.java
@@ -27,7 +27,9 @@ import org.jetbrains.plugins.github.api.GithubFullPath;
import org.jetbrains.plugins.github.util.GithubNotifications;
import javax.swing.*;
-import java.util.Set;
+import java.util.List;
+
+import static org.jetbrains.plugins.github.GithubCreatePullRequestWorker.ForkInfo;
/**
* @author Aleksey Pivovarov
@@ -35,25 +37,27 @@ import java.util.Set;
public class GithubSelectForkDialog extends DialogWrapper {
@NotNull private final GithubSelectForkPanel myPanel;
@NotNull private final Project myProject;
- @NotNull private final Convertor<String, GithubFullPath> myCheckFork;
- private GithubFullPath myFullPath;
+ @NotNull private final Convertor<String, ForkInfo> myCheckFork;
+ private ForkInfo mySelectedFork;
public GithubSelectForkDialog(@NotNull Project project,
- @NotNull Set<GithubFullPath> forks,
- @NotNull Convertor<String, GithubFullPath> checkFork) {
+ @Nullable List<GithubFullPath> forks,
+ @NotNull Convertor<String, ForkInfo> checkFork) {
super(project);
myProject = project;
myCheckFork = checkFork;
myPanel = new GithubSelectForkPanel();
- myPanel.setUsers(ContainerUtil.map(forks, new Function<GithubFullPath, String>() {
- @Override
- public String fun(GithubFullPath path) {
- return path.getUser();
- }
- }));
+ if (forks != null) {
+ myPanel.setUsers(ContainerUtil.map(forks, new Function<GithubFullPath, String>() {
+ @Override
+ public String fun(GithubFullPath path) {
+ return path.getUser();
+ }
+ }));
+ }
setTitle("Select Base Fork Repository");
init();
@@ -61,12 +65,12 @@ public class GithubSelectForkDialog extends DialogWrapper {
@Override
protected void doOKAction() {
- GithubFullPath path = myCheckFork.convert(myPanel.getUser());
- if (path == null) {
+ ForkInfo fork = myCheckFork.convert(myPanel.getUser());
+ if (fork == null) {
GithubNotifications.showErrorDialog(myProject, "Can't Find Repository", "Can't find fork for selected user");
}
else {
- myFullPath = path;
+ mySelectedFork = fork;
super.doOKAction();
}
}
@@ -78,12 +82,7 @@ public class GithubSelectForkDialog extends DialogWrapper {
}
@NotNull
- public GithubFullPath getPath() {
- return myFullPath;
- }
-
- @TestOnly
- public void testSetUser(@NotNull String user) {
- myPanel.setSelectedUser(user);
+ public ForkInfo getPath() {
+ return mySelectedFork;
}
}
diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkPanel.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkPanel.java
index 754afc617057..cb3e014ee7dc 100644
--- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkPanel.java
+++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSelectForkPanel.java
@@ -57,14 +57,6 @@ public class GithubSelectForkPanel {
return myComboBox.getSelectedItem().toString();
}
- public void setSelectedUser(@Nullable String user) {
- if (StringUtil.isEmptyOrSpaces(user)) {
- return;
- }
-
- myComboBox.setSelectedItem(user);
- }
-
public JPanel getPanel() {
return myPanel;
}
diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSettingsPanel.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSettingsPanel.java
index 7de0dae30d69..9bcf2aa78fc8 100644
--- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSettingsPanel.java
+++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSettingsPanel.java
@@ -30,6 +30,7 @@ import com.intellij.util.ThrowableConvertor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.github.api.GithubApiUtil;
+import org.jetbrains.plugins.github.api.GithubConnection;
import org.jetbrains.plugins.github.api.GithubUser;
import org.jetbrains.plugins.github.exceptions.GithubAuthenticationException;
import org.jetbrains.plugins.github.exceptions.GithubOperationCanceledException;
@@ -112,11 +113,10 @@ public class GithubSettingsPanel {
}
}
catch (GithubAuthenticationException ex) {
- GithubNotifications.showErrorDialog(myPane, "Login Failure", "Can't login using given credentials: " + ex.getMessage());
+ GithubNotifications.showErrorDialog(myPane, "Login Failure", "Can't login using given credentials: ", ex);
}
catch (IOException ex) {
- LOG.info(ex);
- GithubNotifications.showErrorDialog(myPane, "Login Failure", "Can't login: " + GithubUtil.getErrorTextFromException(ex));
+ GithubNotifications.showErrorDialog(myPane, "Login Failure", "Can't login: ", ex);
}
}
});
@@ -131,11 +131,12 @@ public class GithubSettingsPanel {
@Override
public String convert(ProgressIndicator indicator) throws IOException {
return GithubUtil.runTaskWithBasicAuthForHost(project, GithubAuthDataHolder.createFromSettings(), indicator, getHost(),
- new ThrowableConvertor<GithubAuthData, String, IOException>() {
+ new ThrowableConvertor<GithubConnection, String, IOException>() {
@NotNull
@Override
- public String convert(@NotNull GithubAuthData auth) throws IOException {
- return GithubApiUtil.getMasterToken(auth, "IntelliJ plugin");
+ public String convert(@NotNull GithubConnection connection)
+ throws IOException {
+ return GithubApiUtil.getMasterToken(connection, "IntelliJ plugin");
}
}
);
diff --git a/plugins/github/src/org/jetbrains/plugins/github/util/GithubNotifications.java b/plugins/github/src/org/jetbrains/plugins/github/util/GithubNotifications.java
index 767c620c93a4..d34441bf1ba3 100644
--- a/plugins/github/src/org/jetbrains/plugins/github/util/GithubNotifications.java
+++ b/plugins/github/src/org/jetbrains/plugins/github/util/GithubNotifications.java
@@ -18,6 +18,7 @@ package org.jetbrains.plugins.github.util;
import com.intellij.notification.NotificationListener;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vcs.VcsNotifier;
import org.jetbrains.annotations.NotNull;
@@ -41,6 +42,12 @@ public class GithubNotifications {
VcsNotifier.getInstance(project).notifyImportantWarning(title, message);
}
+ public static void showWarning(@NotNull Project project, @NotNull String title, @NotNull Exception e) {
+ LOG.info(title + "; ", e);
+ if (e instanceof GithubOperationCanceledException) return;
+ VcsNotifier.getInstance(project).notifyImportantWarning(title, getErrorTextFromException(e));
+ }
+
public static void showError(@NotNull Project project, @NotNull String title, @NotNull String message) {
LOG.info(title + "; " + message);
VcsNotifier.getInstance(project).notifyError(title, message);
@@ -116,19 +123,28 @@ public class GithubNotifications {
Messages.showErrorDialog(project, getErrorTextFromException(e), title);
}
- public static void showErrorDialog(@NotNull Component component, @NotNull String title, @NotNull String message) {
- LOG.info(title + "; " + message);
- Messages.showErrorDialog(component, message, title);
- }
-
public static void showErrorDialog(@NotNull Component component, @NotNull String title, @NotNull Exception e) {
LOG.info(title, e);
if (e instanceof GithubOperationCanceledException) return;
Messages.showErrorDialog(component, getErrorTextFromException(e), title);
}
+ public static void showErrorDialog(@NotNull Component component, @NotNull String title, @NotNull String prefix, @NotNull Exception e) {
+ LOG.info(title, e);
+ if (e instanceof GithubOperationCanceledException) return;
+ Messages.showErrorDialog(component, prefix + getErrorTextFromException(e), title);
+ }
+
@Messages.YesNoResult
public static int showYesNoDialog(@Nullable Project project, @NotNull String title, @NotNull String message) {
return Messages.showYesNoDialog(project, message, title, Messages.getQuestionIcon());
}
+
+ @Messages.YesNoResult
+ public static int showYesNoDialog(@Nullable Project project,
+ @NotNull String title,
+ @NotNull String message,
+ @NotNull DialogWrapper.DoNotAskOption doNotAskOption) {
+ return Messages.showYesNoDialog(project, message, title, Messages.getQuestionIcon(), doNotAskOption);
+ }
}
diff --git a/plugins/github/src/org/jetbrains/plugins/github/util/GithubSettings.java b/plugins/github/src/org/jetbrains/plugins/github/util/GithubSettings.java
index 3523e412a95e..7e98d47d8220 100644
--- a/plugins/github/src/org/jetbrains/plugins/github/util/GithubSettings.java
+++ b/plugins/github/src/org/jetbrains/plugins/github/util/GithubSettings.java
@@ -22,6 +22,7 @@ import com.intellij.ide.passwordSafe.impl.PasswordSafeImpl;
import com.intellij.openapi.components.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.util.ThreeState;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.github.api.GithubApiUtil;
@@ -60,6 +61,7 @@ public class GithubSettings implements PersistentStateComponent<GithubSettings.S
public boolean SAVE_PASSWORD = true;
public int CONNECTION_TIMEOUT = 5000;
public boolean VALID_GIT_AUTH = true;
+ public ThreeState CREATE_PULL_REQUEST_CREATE_REMOTE = ThreeState.UNSURE;
}
public static GithubSettings getInstance() {
@@ -130,6 +132,15 @@ public class GithubSettings implements PersistentStateComponent<GithubSettings.S
return passwordSafe.getSettings().getProviderType() == PasswordSafeSettings.ProviderType.MASTER_PASSWORD;
}
+ @NotNull
+ public ThreeState getCreatePullRequestCreateRemote() {
+ return myState.CREATE_PULL_REQUEST_CREATE_REMOTE;
+ }
+
+ public void setCreatePullRequestCreateRemote(@NotNull ThreeState value) {
+ myState.CREATE_PULL_REQUEST_CREATE_REMOTE = value;
+ }
+
public void setAnonymousGist(final boolean anonymousGist) {
myState.ANONYMOUS_GIST = anonymousGist;
}
diff --git a/plugins/github/src/org/jetbrains/plugins/github/util/GithubUtil.java b/plugins/github/src/org/jetbrains/plugins/github/util/GithubUtil.java
index edd12ab85ab6..34c53da7a97f 100644
--- a/plugins/github/src/org/jetbrains/plugins/github/util/GithubUtil.java
+++ b/plugins/github/src/org/jetbrains/plugins/github/util/GithubUtil.java
@@ -15,6 +15,7 @@
*/
package org.jetbrains.plugins.github.util;
+import com.intellij.concurrency.JobScheduler;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
@@ -23,12 +24,14 @@ import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
+import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.ThrowableComputable;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.util.ConcurrencyUtil;
import com.intellij.util.Consumer;
import com.intellij.util.ThrowableConsumer;
import com.intellij.util.ThrowableConvertor;
@@ -46,6 +49,7 @@ import git4idea.repo.GitRepositoryManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.github.api.GithubApiUtil;
+import org.jetbrains.plugins.github.api.GithubConnection;
import org.jetbrains.plugins.github.api.GithubFullPath;
import org.jetbrains.plugins.github.api.GithubUserDetailed;
import org.jetbrains.plugins.github.exceptions.GithubAuthenticationException;
@@ -57,6 +61,8 @@ import org.jetbrains.plugins.github.ui.GithubLoginDialog;
import java.io.IOException;
import java.net.UnknownHostException;
import java.util.List;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
/**
* Various utility methods for the GutHub plugin.
@@ -72,11 +78,21 @@ public class GithubUtil {
// TODO: Consider sharing of GithubAuthData between actions (as member of GithubSettings)
public static <T> T runTask(@NotNull Project project,
@NotNull GithubAuthDataHolder authHolder,
- @NotNull ProgressIndicator indicator,
- @NotNull ThrowableConvertor<GithubAuthData, T, IOException> task) throws IOException {
+ @NotNull final ProgressIndicator indicator,
+ @NotNull ThrowableConvertor<GithubConnection, T, IOException> task) throws IOException {
GithubAuthData auth = authHolder.getAuthData();
try {
- return task.convert(auth);
+ final GithubConnection connection = new GithubConnection(auth, true);
+ ScheduledFuture<?> future = null;
+
+ try {
+ future = addCancellationListener(indicator, connection);
+ return task.convert(connection);
+ }
+ finally {
+ connection.close();
+ if (future != null) future.cancel(true);
+ }
}
catch (GithubTwoFactorAuthenticationException e) {
getTwoFactorAuthData(project, authHolder, indicator, auth);
@@ -90,11 +106,21 @@ public class GithubUtil {
public static void runTask(@NotNull Project project,
@NotNull GithubAuthDataHolder authHolder,
- @NotNull ProgressIndicator indicator,
- @NotNull ThrowableConsumer<GithubAuthData, IOException> task) throws IOException {
+ @NotNull final ProgressIndicator indicator,
+ @NotNull ThrowableConsumer<GithubConnection, IOException> task) throws IOException {
GithubAuthData auth = authHolder.getAuthData();
try {
- task.consume(auth);
+ final GithubConnection connection = new GithubConnection(auth, true);
+ ScheduledFuture<?> future = null;
+
+ try {
+ future = addCancellationListener(indicator, connection);
+ task.consume(connection);
+ }
+ finally {
+ connection.close();
+ if (future != null) future.cancel(true);
+ }
}
catch (GithubTwoFactorAuthenticationException e) {
getTwoFactorAuthData(project, authHolder, indicator, auth);
@@ -108,15 +134,26 @@ public class GithubUtil {
public static <T> T runTaskWithBasicAuthForHost(@NotNull Project project,
@NotNull GithubAuthDataHolder authHolder,
- @NotNull ProgressIndicator indicator,
+ @NotNull final ProgressIndicator indicator,
@NotNull String host,
- @NotNull ThrowableConvertor<GithubAuthData, T, IOException> task) throws IOException {
+ @NotNull ThrowableConvertor<GithubConnection, T, IOException> task) throws IOException {
GithubAuthData auth = authHolder.getAuthData();
try {
if (auth.getAuthType() != GithubAuthData.AuthType.BASIC) {
throw new GithubAuthenticationException("Expected basic authentication");
}
- return task.convert(auth);
+
+ final GithubConnection connection = new GithubConnection(auth, true);
+ ScheduledFuture<?> future = null;
+
+ try {
+ future = addCancellationListener(indicator, connection);
+ return task.convert(connection);
+ }
+ finally {
+ connection.close();
+ if (future != null) future.cancel(true);
+ }
}
catch (GithubTwoFactorAuthenticationException e) {
getTwoFactorAuthData(project, authHolder, indicator, auth);
@@ -131,10 +168,20 @@ public class GithubUtil {
@NotNull
private static GithubUserDetailed testConnection(@NotNull Project project,
@NotNull GithubAuthDataHolder authHolder,
- @NotNull ProgressIndicator indicator) throws IOException {
+ @NotNull final ProgressIndicator indicator) throws IOException {
GithubAuthData auth = authHolder.getAuthData();
try {
- return GithubApiUtil.getCurrentUserDetailed(auth);
+ final GithubConnection connection = new GithubConnection(auth, true);
+ ScheduledFuture<?> future = null;
+
+ try {
+ future = addCancellationListener(indicator, connection);
+ return GithubApiUtil.getCurrentUserDetailed(connection);
+ }
+ finally {
+ connection.close();
+ if (future != null) future.cancel(true);
+ }
}
catch (GithubTwoFactorAuthenticationException e) {
getTwoFactorAuthData(project, authHolder, indicator, auth);
@@ -142,6 +189,33 @@ public class GithubUtil {
}
}
+ @NotNull
+ private static ScheduledFuture<?> addCancellationListener(@NotNull Runnable run) {
+ return JobScheduler.getScheduler().scheduleWithFixedDelay(run, 1000, 300, TimeUnit.MILLISECONDS);
+ }
+
+ @NotNull
+ private static ScheduledFuture<?> addCancellationListener(@NotNull final ProgressIndicator indicator,
+ @NotNull final GithubConnection connection) {
+ return addCancellationListener(new Runnable() {
+ @Override
+ public void run() {
+ if (indicator.isCanceled()) connection.abort();
+ }
+ });
+ }
+
+ @NotNull
+ private static ScheduledFuture<?> addCancellationListener(@NotNull final ProgressIndicator indicator,
+ @NotNull final Thread thread) {
+ return addCancellationListener(new Runnable() {
+ @Override
+ public void run() {
+ if (indicator.isCanceled()) thread.interrupt();
+ }
+ });
+ }
+
public static void getValidAuthData(@NotNull final Project project,
@NotNull final GithubAuthDataHolder authHolder,
@NotNull final ProgressIndicator indicator,
@@ -220,7 +294,7 @@ public class GithubUtil {
throw new GithubOperationCanceledException("Two factor authentication can be used only with Login/Password");
}
- GithubApiUtil.askForTwoFactorCodeSMS(oldAuth);
+ GithubApiUtil.askForTwoFactorCodeSMS(new GithubConnection(oldAuth, false));
final Ref<String> codeRef = new Ref<String>();
ApplicationManager.getApplication().invokeAndWait(new Runnable() {
@@ -301,13 +375,7 @@ public class GithubUtil {
try {
dataRef.set(task.convert(indicator));
}
- catch (IOException e) {
- exceptionRef.set(e);
- }
- catch (Error e) {
- exceptionRef.set(e);
- }
- catch (RuntimeException e) {
+ catch (Throwable e) {
exceptionRef.set(e);
}
}
@@ -325,17 +393,21 @@ public class GithubUtil {
public static <T> T computeValueInModal(@NotNull Project project,
@NotNull String caption,
@NotNull final Convertor<ProgressIndicator, T> task) {
+ return computeValueInModal(project, caption, true, task);
+ }
+
+ public static <T> T computeValueInModal(@NotNull Project project,
+ @NotNull String caption,
+ boolean canBeCancelled,
+ @NotNull final Convertor<ProgressIndicator, T> task) {
final Ref<T> dataRef = new Ref<T>();
final Ref<Throwable> exceptionRef = new Ref<Throwable>();
- ProgressManager.getInstance().run(new Task.Modal(project, caption, true) {
+ ProgressManager.getInstance().run(new Task.Modal(project, caption, canBeCancelled) {
public void run(@NotNull ProgressIndicator indicator) {
try {
dataRef.set(task.convert(indicator));
}
- catch (Error e) {
- exceptionRef.set(e);
- }
- catch (RuntimeException e) {
+ catch (Throwable e) {
exceptionRef.set(e);
}
}
@@ -352,16 +424,20 @@ public class GithubUtil {
public static void computeValueInModal(@NotNull Project project,
@NotNull String caption,
@NotNull final Consumer<ProgressIndicator> task) {
+ computeValueInModal(project, caption, true, task);
+ }
+
+ public static void computeValueInModal(@NotNull Project project,
+ @NotNull String caption,
+ boolean canBeCancelled,
+ @NotNull final Consumer<ProgressIndicator> task) {
final Ref<Throwable> exceptionRef = new Ref<Throwable>();
- ProgressManager.getInstance().run(new Task.Modal(project, caption, true) {
+ ProgressManager.getInstance().run(new Task.Modal(project, caption, canBeCancelled) {
public void run(@NotNull ProgressIndicator indicator) {
try {
task.consume(indicator);
}
- catch (Error e) {
- exceptionRef.set(e);
- }
- catch (RuntimeException e) {
+ catch (Throwable e) {
exceptionRef.set(e);
}
}
@@ -374,6 +450,49 @@ public class GithubUtil {
}
}
+ public static <T> T runInterruptable(@NotNull final ProgressIndicator indicator,
+ @NotNull ThrowableComputable<T, IOException> task) throws IOException {
+ ScheduledFuture<?> future = null;
+ try {
+ final Thread thread = Thread.currentThread();
+ future = addCancellationListener(indicator, thread);
+
+ return task.compute();
+ }
+ finally {
+ if (future != null) future.cancel(true);
+ Thread.interrupted();
+ }
+ }
+
+ public static <T> T runInterruptable(@NotNull final ProgressIndicator indicator, @NotNull Computable<T> task) {
+ ScheduledFuture<?> future = null;
+ try {
+ final Thread thread = Thread.currentThread();
+ future = addCancellationListener(indicator, thread);
+
+ return task.compute();
+ }
+ finally {
+ if (future != null) future.cancel(true);
+ Thread.interrupted();
+ }
+ }
+
+ public static void runInterruptable(@NotNull final ProgressIndicator indicator, @NotNull Runnable task) {
+ ScheduledFuture<?> future = null;
+ try {
+ final Thread thread = Thread.currentThread();
+ future = addCancellationListener(indicator, thread);
+
+ task.run();
+ }
+ finally {
+ if (future != null) future.cancel(true);
+ Thread.interrupted();
+ }
+ }
+
/*
* Git utils
*/
diff --git a/plugins/github/test/org/jetbrains/plugins/github/GithubCreateGistTestBase.java b/plugins/github/test/org/jetbrains/plugins/github/GithubCreateGistTestBase.java
index b54bd8c62b4e..4dabe58bebc7 100644
--- a/plugins/github/test/org/jetbrains/plugins/github/GithubCreateGistTestBase.java
+++ b/plugins/github/test/org/jetbrains/plugins/github/GithubCreateGistTestBase.java
@@ -22,6 +22,7 @@ import com.intellij.util.text.DateFormatUtil;
import git4idea.test.TestDialogHandler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.github.api.GithubApiUtil;
+import org.jetbrains.plugins.github.api.GithubConnection;
import org.jetbrains.plugins.github.api.GithubGist;
import org.jetbrains.plugins.github.test.GithubTest;
import org.jetbrains.plugins.github.ui.GithubLoginDialog;
@@ -59,7 +60,7 @@ public abstract class GithubCreateGistTestBase extends GithubTest {
protected void deleteGist() throws IOException {
if (GIST_ID != null) {
- GithubApiUtil.deleteGist(myGitHubSettings.getAuthData(), GIST_ID);
+ GithubApiUtil.deleteGist(new GithubConnection(myGitHubSettings.getAuthData()), GIST_ID);
GIST = null;
GIST_ID = null;
}
@@ -82,7 +83,7 @@ public abstract class GithubCreateGistTestBase extends GithubTest {
if (GIST == null) {
try {
- GIST = GithubApiUtil.getGist(myGitHubSettings.getAuthData(), GIST_ID);
+ GIST = GithubApiUtil.getGist(new GithubConnection(myGitHubSettings.getAuthData()), GIST_ID);
}
catch (IOException e) {
System.err.println(e.getMessage());
diff --git a/plugins/github/test/org/jetbrains/plugins/github/GithubCreatePullRequestTestBase.java b/plugins/github/test/org/jetbrains/plugins/github/GithubCreatePullRequestTestBase.java
index 643c3d2db5f0..b6a2058cd24f 100644
--- a/plugins/github/test/org/jetbrains/plugins/github/GithubCreatePullRequestTestBase.java
+++ b/plugins/github/test/org/jetbrains/plugins/github/GithubCreatePullRequestTestBase.java
@@ -76,8 +76,8 @@ public abstract class GithubCreatePullRequestTestBase extends GithubTest {
@Override
public int handleDialog(GithubCreatePullRequestDialog dialog) {
dialog.testSetRequestTitle(BRANCH_NAME);
+ dialog.testSetFork(new GithubFullPath(user, PROJECT_NAME));
dialog.testSetBranch(branch);
- dialog.testSetTarget(new GithubFullPath(user, PROJECT_NAME));
dialog.testCreatePullRequest();
return DialogWrapper.OK_EXIT_CODE;
}
diff --git a/plugins/github/test/org/jetbrains/plugins/github/GithubIssuesTest.java b/plugins/github/test/org/jetbrains/plugins/github/GithubIssuesTest.java
index 1921b9ecc055..1cd499f53c89 100644
--- a/plugins/github/test/org/jetbrains/plugins/github/GithubIssuesTest.java
+++ b/plugins/github/test/org/jetbrains/plugins/github/GithubIssuesTest.java
@@ -19,6 +19,7 @@ import com.intellij.openapi.util.Comparing;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.plugins.github.api.GithubApiUtil;
+import org.jetbrains.plugins.github.api.GithubConnection;
import org.jetbrains.plugins.github.api.GithubIssue;
import org.jetbrains.plugins.github.test.GithubTest;
@@ -32,7 +33,7 @@ public class GithubIssuesTest extends GithubTest {
private static final String REPO_NAME = "IssuesTest";
public void testAssigneeIssues1() throws Exception {
- List<GithubIssue> result = GithubApiUtil.getIssuesAssigned(myAuth, myLogin2, REPO_NAME, myLogin1, 100, false);
+ List<GithubIssue> result = GithubApiUtil.getIssuesAssigned(new GithubConnection(myAuth), myLogin2, REPO_NAME, myLogin1, 100, false);
List<Long> issues = ContainerUtil.map(result, new Function<GithubIssue, Long>() {
@Override
public Long fun(GithubIssue githubIssue) {
@@ -46,7 +47,7 @@ public class GithubIssuesTest extends GithubTest {
}
public void testAssigneeIssues2() throws Exception {
- List<GithubIssue> result = GithubApiUtil.getIssuesAssigned(myAuth, myLogin2, REPO_NAME, myLogin2, 100, false);
+ List<GithubIssue> result = GithubApiUtil.getIssuesAssigned(new GithubConnection(myAuth), myLogin2, REPO_NAME, myLogin2, 100, false);
List<Long> issues = ContainerUtil.map(result, new Function<GithubIssue, Long>() {
@Override
public Long fun(GithubIssue githubIssue) {
@@ -60,7 +61,7 @@ public class GithubIssuesTest extends GithubTest {
}
public void testAssigneeIssues3() throws Exception {
- List<GithubIssue> result = GithubApiUtil.getIssuesAssigned(myAuth, myLogin2, REPO_NAME, "", 100, false);
+ List<GithubIssue> result = GithubApiUtil.getIssuesAssigned(new GithubConnection(myAuth), myLogin2, REPO_NAME, "", 100, false);
List<Long> issues = ContainerUtil.map(result, new Function<GithubIssue, Long>() {
@Override
public Long fun(GithubIssue githubIssue) {
@@ -74,7 +75,7 @@ public class GithubIssuesTest extends GithubTest {
}
public void testAssigneeIssues4() throws Exception {
- List<GithubIssue> result = GithubApiUtil.getIssuesAssigned(myAuth, myLogin2, REPO_NAME, myLogin1, 100, true);
+ List<GithubIssue> result = GithubApiUtil.getIssuesAssigned(new GithubConnection(myAuth), myLogin2, REPO_NAME, myLogin1, 100, true);
List<Long> issues = ContainerUtil.map(result, new Function<GithubIssue, Long>() {
@Override
public Long fun(GithubIssue githubIssue) {
@@ -88,7 +89,7 @@ public class GithubIssuesTest extends GithubTest {
}
public void testAssigneeIssues5() throws Exception {
- List<GithubIssue> result = GithubApiUtil.getIssuesAssigned(myAuth, myLogin2, REPO_NAME, myLogin2, 100, true);
+ List<GithubIssue> result = GithubApiUtil.getIssuesAssigned(new GithubConnection(myAuth), myLogin2, REPO_NAME, myLogin2, 100, true);
List<Long> issues = ContainerUtil.map(result, new Function<GithubIssue, Long>() {
@Override
public Long fun(GithubIssue githubIssue) {
@@ -102,7 +103,7 @@ public class GithubIssuesTest extends GithubTest {
}
public void testAssigneeIssues6() throws Exception {
- List<GithubIssue> result = GithubApiUtil.getIssuesAssigned(myAuth, myLogin2, REPO_NAME, "", 100, true);
+ List<GithubIssue> result = GithubApiUtil.getIssuesAssigned(new GithubConnection(myAuth), myLogin2, REPO_NAME, "", 100, true);
List<Long> issues = ContainerUtil.map(result, new Function<GithubIssue, Long>() {
@Override
public Long fun(GithubIssue githubIssue) {
@@ -116,7 +117,7 @@ public class GithubIssuesTest extends GithubTest {
}
public void testQueriedIssues1() throws Exception {
- List<GithubIssue> result = GithubApiUtil.getIssuesQueried(myAuth, myLogin2, REPO_NAME, "abracadabra", true);
+ List<GithubIssue> result = GithubApiUtil.getIssuesQueried(new GithubConnection(myAuth), myLogin2, REPO_NAME, "abracadabra", true);
List<Long> issues = ContainerUtil.map(result, new Function<GithubIssue, Long>() {
@Override
public Long fun(GithubIssue githubIssue) {
@@ -130,7 +131,7 @@ public class GithubIssuesTest extends GithubTest {
}
public void testQueriedIssues2() throws Exception {
- List<GithubIssue> result = GithubApiUtil.getIssuesQueried(myAuth, myLogin2, REPO_NAME, "commentary", true);
+ List<GithubIssue> result = GithubApiUtil.getIssuesQueried(new GithubConnection(myAuth), myLogin2, REPO_NAME, "commentary", true);
List<Long> issues = ContainerUtil.map(result, new Function<GithubIssue, Long>() {
@Override
public Long fun(GithubIssue githubIssue) {
@@ -144,7 +145,7 @@ public class GithubIssuesTest extends GithubTest {
}
public void testQueriedIssues3() throws Exception {
- List<GithubIssue> result = GithubApiUtil.getIssuesQueried(myAuth, myLogin2, REPO_NAME, "abracadabra", false);
+ List<GithubIssue> result = GithubApiUtil.getIssuesQueried(new GithubConnection(myAuth), myLogin2, REPO_NAME, "abracadabra", false);
List<Long> issues = ContainerUtil.map(result, new Function<GithubIssue, Long>() {
@Override
public Long fun(GithubIssue githubIssue) {
diff --git a/plugins/github/test/org/jetbrains/plugins/github/GithubRequestPagingTest.java b/plugins/github/test/org/jetbrains/plugins/github/GithubRequestPagingTest.java
index 4fec0d1c7a5c..22b06a58ff02 100644
--- a/plugins/github/test/org/jetbrains/plugins/github/GithubRequestPagingTest.java
+++ b/plugins/github/test/org/jetbrains/plugins/github/GithubRequestPagingTest.java
@@ -16,8 +16,10 @@
package org.jetbrains.plugins.github;
import org.jetbrains.plugins.github.api.GithubApiUtil;
+import org.jetbrains.plugins.github.api.GithubConnection;
import org.jetbrains.plugins.github.api.GithubRepo;
import org.jetbrains.plugins.github.test.GithubTest;
+import org.jetbrains.plugins.github.util.GithubAuthData;
import java.util.ArrayList;
import java.util.List;
@@ -36,17 +38,23 @@ public class GithubRequestPagingTest extends GithubTest {
public void testAvailableRepos() throws Throwable {
- List<GithubRepo> availableRepos = GithubApiUtil.getUserRepos(myGitHubSettings.getAuthData(), myLogin2);
- List<String> realData = new ArrayList<String>();
- for (GithubRepo info : availableRepos) {
- realData.add(info.getName());
- }
+ GithubConnection connection = new GithubConnection(myGitHubSettings.getAuthData(), true);
+ try {
+ List<GithubRepo> availableRepos = GithubApiUtil.getUserRepos(connection, myLogin2);
+ List<String> realData = new ArrayList<String>();
+ for (GithubRepo info : availableRepos) {
+ realData.add(info.getName());
+ }
- List<String> expectedData = new ArrayList<String>();
- for (int i = 1; i <= 251; i++) {
- expectedData.add(String.valueOf(i));
- }
+ List<String> expectedData = new ArrayList<String>();
+ for (int i = 1; i <= 251; i++) {
+ expectedData.add(String.valueOf(i));
+ }
- assertContainsElements(realData, expectedData);
+ assertContainsElements(realData, expectedData);
+ }
+ finally {
+ connection.close();
+ }
}
}
diff --git a/plugins/github/test/org/jetbrains/plugins/github/GithubShareProjectTest.java b/plugins/github/test/org/jetbrains/plugins/github/GithubShareProjectTest.java
index c4063629cbbe..4e51fccc0729 100644
--- a/plugins/github/test/org/jetbrains/plugins/github/GithubShareProjectTest.java
+++ b/plugins/github/test/org/jetbrains/plugins/github/GithubShareProjectTest.java
@@ -4,6 +4,7 @@ import com.intellij.notification.NotificationType;
import com.intellij.openapi.components.ServiceManager;
import git4idea.commands.Git;
import org.jetbrains.plugins.github.api.GithubApiUtil;
+import org.jetbrains.plugins.github.api.GithubConnection;
import org.jetbrains.plugins.github.api.GithubRepoDetailed;
import org.jetbrains.plugins.github.util.GithubAuthData;
@@ -100,7 +101,7 @@ public class GithubShareProjectTest extends GithubShareProjectTestBase {
protected void checkGithubExists() throws IOException {
GithubAuthData auth = myGitHubSettings.getAuthData();
- GithubRepoDetailed githubInfo = GithubApiUtil.getDetailedRepoInfo(auth, myLogin1, PROJECT_NAME);
+ GithubRepoDetailed githubInfo = GithubApiUtil.getDetailedRepoInfo(new GithubConnection(auth), myLogin1, PROJECT_NAME);
assertNotNull("GitHub repository does not exist", githubInfo);
}
}
diff --git a/plugins/github/test/org/jetbrains/plugins/github/GithubShareProjectTestBase.java b/plugins/github/test/org/jetbrains/plugins/github/GithubShareProjectTestBase.java
index abfb5ece3819..ea07ca1eaf1d 100644
--- a/plugins/github/test/org/jetbrains/plugins/github/GithubShareProjectTestBase.java
+++ b/plugins/github/test/org/jetbrains/plugins/github/GithubShareProjectTestBase.java
@@ -22,6 +22,7 @@ import git4idea.GitUtil;
import git4idea.repo.GitRepository;
import git4idea.test.TestDialogHandler;
import org.jetbrains.plugins.github.api.GithubApiUtil;
+import org.jetbrains.plugins.github.api.GithubConnection;
import org.jetbrains.plugins.github.test.GithubTest;
import org.jetbrains.plugins.github.ui.GithubShareDialog;
@@ -48,7 +49,7 @@ public abstract class GithubShareProjectTestBase extends GithubTest {
}
protected void deleteGithubRepo() throws IOException {
- GithubApiUtil.deleteGithubRepository(myGitHubSettings.getAuthData(), myLogin1, PROJECT_NAME);
+ GithubApiUtil.deleteGithubRepository(new GithubConnection(myGitHubSettings.getAuthData()), myLogin1, PROJECT_NAME);
}
protected void registerDefaultShareDialogHandler() {
diff --git a/plugins/gradle/resources/i18n/GradleBundle.properties b/plugins/gradle/resources/i18n/GradleBundle.properties
index 88dfd899deed..0f827062fbce 100644
--- a/plugins/gradle/resources/i18n/GradleBundle.properties
+++ b/plugins/gradle/resources/i18n/GradleBundle.properties
@@ -12,7 +12,7 @@ gradle.settings.text.service.dir.path=Service directory path:
gradle.settings.text.vm.options=Gradle VM options:
gradle.settings.text.offline_work=Offline work
gradle.settings.title.service.dir.path=Select gradle service directory to use
-gradle.generic.text.error.jar.not.found=Gradle jars location is unknown
+gradle.generic.text.error.jar.not.found=Gradle JARs location is unknown
gradle.home.setting.type.explicit.incorrect=Gradle location is incorrect.\nLocation:{0}
gradle.home.setting.type.explicit.empty=Gradle location is not specified
diff --git a/plugins/gradle/src/META-INF/plugin.xml b/plugins/gradle/src/META-INF/plugin.xml
index f00346625e81..4e4fea02a0c7 100644
--- a/plugins/gradle/src/META-INF/plugin.xml
+++ b/plugins/gradle/src/META-INF/plugin.xml
@@ -88,7 +88,7 @@
<moduleBuilder builderClass="org.jetbrains.plugins.gradle.service.project.wizard.GradleModuleBuilder"/>
<internalFileTemplate name="Gradle Build Script"/>
<internalFileTemplate name="Gradle Build Script with wrapper"/>
- <projectConfigurable groupId="build" id="reference.settingsdialog.project.gradle"
+ <projectConfigurable groupId="build.tools" groupWeight="110" id="reference.settingsdialog.project.gradle"
instance="org.jetbrains.plugins.gradle.service.settings.GradleConfigurable"
key="gradle.name" bundle="i18n.GradleBundle"/>
<library.presentationProvider implementation="org.jetbrains.plugins.gradle.config.GradleLibraryPresentationProvider" order="last"/>
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/GradleOrderEnumeratorHandler.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/GradleOrderEnumeratorHandler.java
index 113e49a61a25..28de6f8861d7 100644
--- a/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/GradleOrderEnumeratorHandler.java
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/GradleOrderEnumeratorHandler.java
@@ -107,6 +107,8 @@ public class GradleOrderEnumeratorHandler extends OrderEnumerationHandler {
final ExternalSourceDirectorySet directorySet = externalSourceSet.getSources().get(sourceType);
if (directorySet == null) return;
+ if (directorySet.isCompilerOutputPathInherited()) return;
+
result.add(VfsUtilCore.pathToUrl(directorySet.getOutputDir().getAbsolutePath()));
}
}
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/GradleInstallationManager.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/GradleInstallationManager.java
index 07521be885d8..b363eb8b3395 100644
--- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/GradleInstallationManager.java
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/GradleInstallationManager.java
@@ -360,7 +360,7 @@ public class GradleInstallationManager {
filesInfo.setLength(filesInfo.length() - 1);
}
GradleLog.LOG.info(String.format(
- "Gradle sdk check fails. Reason: no one of the given files matches gradle jar pattern (%s). Files: %s",
+ "Gradle sdk check fails. Reason: no one of the given files matches gradle JAR pattern (%s). Files: %s",
GRADLE_JAR_FILE_PATTERN.toString(), filesInfo
));
}
diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java
index ad7ade6a3c58..ac858e56f634 100644
--- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java
+++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java
@@ -230,8 +230,8 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver
File sourceCompileOutputPath = null;
File testCompileOutputPath = null;
- File resourceCompileOutputPath;
- File testResourceCompileOutputPath;
+ File resourceCompileOutputPath = null;
+ File testResourceCompileOutputPath = null;
boolean inheritOutputDirs = false;
ModuleData moduleData = ideModule.getData();
@@ -244,21 +244,22 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver
ExternalProject externalProject = resolverCtx.getExtraProject(gradleModule, ExternalProject.class);
if (externalProject != null) {
externalProject = new DefaultExternalProject(externalProject);
- }
- if (!inheritOutputDirs && (sourceCompileOutputPath == null || testCompileOutputPath == null)) {
- sourceCompileOutputPath = getCompileOutputPath(externalProject, MAIN_SOURCE_SET, ExternalSystemSourceType.SOURCE);
- resourceCompileOutputPath = getCompileOutputPath(externalProject, MAIN_SOURCE_SET, ExternalSystemSourceType.RESOURCE);
- testCompileOutputPath = getCompileOutputPath(externalProject, TEST_SOURCE_SET, ExternalSystemSourceType.TEST);
- testResourceCompileOutputPath = getCompileOutputPath(externalProject, TEST_SOURCE_SET, ExternalSystemSourceType.TEST_RESOURCE);
- }
- else {
- resourceCompileOutputPath = sourceCompileOutputPath;
- testResourceCompileOutputPath = testCompileOutputPath;
-
- if (externalProject != null) {
+ if (!inheritOutputDirs && (sourceCompileOutputPath == null || testCompileOutputPath == null)) {
+ sourceCompileOutputPath = getCompileOutputPath(externalProject, MAIN_SOURCE_SET, ExternalSystemSourceType.SOURCE);
+ resourceCompileOutputPath = getCompileOutputPath(externalProject, MAIN_SOURCE_SET, ExternalSystemSourceType.RESOURCE);
+ testCompileOutputPath = getCompileOutputPath(externalProject, TEST_SOURCE_SET, ExternalSystemSourceType.TEST);
+ testResourceCompileOutputPath = getCompileOutputPath(externalProject, TEST_SOURCE_SET, ExternalSystemSourceType.TEST_RESOURCE);
+ }
+ else if (!inheritOutputDirs) {
+ resourceCompileOutputPath = sourceCompileOutputPath;
+ testResourceCompileOutputPath = testCompileOutputPath;
final ExternalSourceSet mainSourceSet = externalProject.getSourceSets().get(MAIN_SOURCE_SET);
if (mainSourceSet != null) {
+ final ExternalSourceDirectorySet sourceDirectories = mainSourceSet.getSources().get(ExternalSystemSourceType.SOURCE);
+ if (sourceDirectories instanceof DefaultExternalSourceDirectorySet) {
+ ((DefaultExternalSourceDirectorySet)sourceDirectories).setOutputDir(sourceCompileOutputPath);
+ }
final ExternalSourceDirectorySet resourceDirectories = mainSourceSet.getSources().get(ExternalSystemSourceType.RESOURCE);
if (resourceDirectories instanceof DefaultExternalSourceDirectorySet) {
((DefaultExternalSourceDirectorySet)resourceDirectories).setOutputDir(sourceCompileOutputPath);
@@ -266,6 +267,10 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver
}
final ExternalSourceSet testSourceSet = externalProject.getSourceSets().get(TEST_SOURCE_SET);
if (testSourceSet != null) {
+ final ExternalSourceDirectorySet testDirectories = testSourceSet.getSources().get(ExternalSystemSourceType.TEST);
+ if (testDirectories instanceof DefaultExternalSourceDirectorySet) {
+ ((DefaultExternalSourceDirectorySet)testDirectories).setOutputDir(testCompileOutputPath);
+ }
final ExternalSourceDirectorySet testResourceDirectories = testSourceSet.getSources().get(ExternalSystemSourceType.TEST_RESOURCE);
if (testResourceDirectories instanceof DefaultExternalSourceDirectorySet) {
((DefaultExternalSourceDirectorySet)testResourceDirectories).setOutputDir(testCompileOutputPath);
@@ -277,6 +282,9 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver
projectDataNode.createOrReplaceChild(ExternalProjectDataService.KEY, externalProject);
}
}
+ else {
+ LOG.warn(String.format("Unable to get ExternalProject model for '%s'", gradleModule.getName()));
+ }
if (sourceCompileOutputPath != null) {
moduleData.setCompileOutputPath(ExternalSystemSourceType.SOURCE, sourceCompileOutputPath.getAbsolutePath());
diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleFoldersImportingTest.java b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleFoldersImportingTest.java
index 8c57ebb57d29..5fd64533dcc9 100644
--- a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleFoldersImportingTest.java
+++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleFoldersImportingTest.java
@@ -15,6 +15,7 @@
*/
package org.jetbrains.plugins.gradle.importing;
+import org.jetbrains.annotations.NotNull;
import org.junit.Test;
/**
@@ -34,14 +35,39 @@ public class GradleFoldersImportingTest extends GradleImportingTestCase {
assertModules("project");
assertContentRoots("project", getProjectPath());
- assertSources("project", "src/main/java");
- assertResources("project", "src/main/resources");
- assertTestSources("project", "src/test/java");
- assertTestResources("project", "src/test/resources");
- assertExcludes("project", ".gradle", "build");
+ assertDefaultGradleJavaProjectFolders("project");
assertModuleOutput("project",
getProjectPath() + "/build/classes/main",
getProjectPath() + "/build/classes/test");
}
+
+ @Test
+ public void testProjectWithInheritedOutputDirs() throws Exception {
+
+ importProject(
+ "apply plugin: 'java'\n" +
+ "apply plugin: 'idea'\n" +
+ "idea {\n" +
+ " module {\n" +
+ " inheritOutputDirs = true\n" +
+ " }\n" +
+ "}"
+ );
+
+ assertModules("project");
+ assertContentRoots("project", getProjectPath());
+
+ assertDefaultGradleJavaProjectFolders("project");
+
+ assertModuleInheritedOutput("project");
+ }
+
+ protected void assertDefaultGradleJavaProjectFolders(@NotNull String moduleName) {
+ assertSources(moduleName, "src/main/java");
+ assertResources(moduleName, "src/main/resources");
+ assertTestSources(moduleName, "src/test/java");
+ assertTestResources(moduleName, "src/test/resources");
+ assertExcludes(moduleName, ".gradle", "build");
+ }
}
diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleImportingTestCase.java b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleImportingTestCase.java
index f59ccee38658..2cf4c7125918 100644
--- a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleImportingTestCase.java
+++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/importing/GradleImportingTestCase.java
@@ -160,7 +160,7 @@ public abstract class GradleImportingTestCase extends ExternalSystemImportingTes
throw new RuntimeException(e);
}
if (!location.getScheme().equals("file")) {
- throw new RuntimeException(String.format("Cannot determine classpath for wrapper Jar from codebase '%s'.", location));
+ throw new RuntimeException(String.format("Cannot determine classpath for wrapper JAR from codebase '%s'.", location));
}
return new File(location.getPath());
}
diff --git a/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ExternalProjectBuilderImpl.groovy b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ExternalProjectBuilderImpl.groovy
index 3bb6b471b755..1322c13ef54e 100644
--- a/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ExternalProjectBuilderImpl.groovy
+++ b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ExternalProjectBuilderImpl.groovy
@@ -26,6 +26,7 @@ import org.gradle.api.file.FileCopyDetails
import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.SourceSetContainer
import org.gradle.api.tasks.util.PatternFilterable
+import org.gradle.plugins.ide.idea.IdeaPlugin
import org.jetbrains.annotations.NotNull
import org.jetbrains.annotations.Nullable
import org.jetbrains.plugins.gradle.tooling.ErrorMessageBuilder
@@ -109,6 +110,9 @@ class ExternalProjectBuilderImpl implements ModelBuilderService {
}
static Map<String, ExternalSourceSet> getSourceSets(Project project) {
+ final IdeaPlugin ideaPlugin = project.getPlugins().getPlugin(IdeaPlugin.class);
+ boolean inheritOutputDirs = ideaPlugin?.model?.module?.inheritOutputDirs ?: false
+
def result = [:] as Map<String, ExternalSourceSet>
if (!project.hasProperty("sourceSets") || !(project.sourceSets instanceof SourceSetContainer)) {
return result
@@ -128,11 +132,13 @@ class ExternalProjectBuilderImpl implements ModelBuilderService {
resourcesDirectorySet.name = sourceSet.resources.name
resourcesDirectorySet.srcDirs = sourceSet.resources.srcDirs
resourcesDirectorySet.outputDir = sourceSet.output.resourcesDir
+ resourcesDirectorySet.inheritedCompilerOutput = inheritOutputDirs
ExternalSourceDirectorySet javaDirectorySet = new DefaultExternalSourceDirectorySet()
javaDirectorySet.name = sourceSet.allJava.name
javaDirectorySet.srcDirs = sourceSet.allJava.srcDirs
javaDirectorySet.outputDir = sourceSet.output.classesDir
+ javaDirectorySet.inheritedCompilerOutput = inheritOutputDirs
// javaDirectorySet.excludes = javaExcludes + sourceSet.java.excludes;
// javaDirectorySet.includes = javaIncludes + sourceSet.java.includes;
diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/GroovyBundle.properties b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/GroovyBundle.properties
index 4e3c0eb17c38..0b97a8fbaa35 100644
--- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/GroovyBundle.properties
+++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/GroovyBundle.properties
@@ -31,7 +31,7 @@ newscript.menu.action.description=Creates new Groovy Script
cannot.compile.groovy.files.no.facet=Cannot find Groovy home for module ''{0}''.\nYou should either:\n\
- invoke 'Add Framework support' action for this module,\n\
or:\n\
-- add Groovy jars to module classpath manually.
+- add Groovy JARs to module classpath manually.
cannot.compile.groovy.files.no.sdk=Cannot Compile Groovy Files.\nPlease Set up SDK for module ''{0}''.
cannot.compile.groovy.files.no.sdk.mult=Cannot Compile Groovy Files.\nPlease Set up SDK for modules ''{0}''.
cannot.compile=Cannot Compile
diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/dsl/GroovyClassDescriptor.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/dsl/GroovyClassDescriptor.java
index 2281ad12c4dd..33bd366f6261 100644
--- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/dsl/GroovyClassDescriptor.java
+++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/dsl/GroovyClassDescriptor.java
@@ -38,7 +38,7 @@ public class GroovyClassDescriptor {
final AtomicInteger integer = GroovyCategorySupport.getCategoryNameUsage("aaa");
}
catch (NoSuchMethodError e) {
- throw new RuntimeException("Incompatible Groovy jar in classpath: " + GroovyCategorySupport.class.getResource("/") + ", please remove it");
+ throw new RuntimeException("Incompatible Groovy JAR in classpath: " + GroovyCategorySupport.class.getResource("/") + ", please remove it");
}
}
diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml
index f2e3bc180542..cabf8e7f5739 100644
--- a/plugins/groovy/src/META-INF/plugin.xml
+++ b/plugins/groovy/src/META-INF/plugin.xml
@@ -273,7 +273,7 @@
<fileTypeFactory implementation="org.jetbrains.plugins.groovy.GroovyFileTypeLoader"/>
<fileTypeFactory implementation="org.jetbrains.plugins.groovy.dgm.DGMFileTypeFactory"/>
- <projectConfigurable groupId="build" instance="org.jetbrains.plugins.groovy.gant.GantConfigurable" id="reference.settingsdialog.project.gant"
+ <projectConfigurable groupId="build.tools" groupWeight="100" instance="org.jetbrains.plugins.groovy.gant.GantConfigurable" id="reference.settingsdialog.project.gant"
displayName="Gant"/>
<library.presentationProvider implementation="org.jetbrains.plugins.groovy.config.GroovyLibraryPresentationProvider"/>
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/config/GroovyFacetUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/config/GroovyFacetUtil.java
index e69eb97efdfe..952916393b02 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/config/GroovyFacetUtil.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/config/GroovyFacetUtil.java
@@ -28,6 +28,7 @@ import com.intellij.openapi.roots.ModifiableRootModel;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.ui.Messages;
+import com.intellij.openapi.util.io.FileUtil;
import com.intellij.util.PathUtil;
import icons.JetgroovyIcons;
import org.jetbrains.plugins.groovy.GroovyBundle;
@@ -76,8 +77,13 @@ public class GroovyFacetUtil {
}
public static File getBundledGroovyJar() {
- String root = new File(PathUtil.getJarPathForClass(GroovyFacetUtil.class)).isDirectory() ?
- PluginPathManager.getPluginHomePath("groovy") + "/../../lib/" : PathManager.getHomePath() + "/lib/";
+ String root;
+ if (new File(PathUtil.getJarPathForClass(GroovyFacetUtil.class)).isDirectory()) {
+ root = FileUtil.toCanonicalPath(PluginPathManager.getPluginHomePath("groovy") + "/../../lib/");
+ }
+ else {
+ root = PathManager.getHomePath() + "/lib/";
+ }
final File[] groovyJars = LibrariesUtil.getFilesInDirectoryByPattern(root, GroovyConfigUtils.GROOVY_ALL_JAR_PATTERN);
assert groovyJars.length == 1;
return groovyJars[0];
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/ivy/AbstractAttachSourceProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/ivy/AbstractAttachSourceProvider.java
index 53ddae2cc17d..3f2139c174a8 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/ivy/AbstractAttachSourceProvider.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/ivy/AbstractAttachSourceProvider.java
@@ -152,7 +152,7 @@ public abstract class AbstractAttachSourceProvider implements AttachSourcesProvi
final ByteArrayOutputStream out;
try {
- LOG.info("Downloading sources jar: " + myUrl);
+ LOG.info("Downloading sources JAR: " + myUrl);
indicator.checkCanceled();
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionUtil.java
index d93063a53ca4..0c32878b5853 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionUtil.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/completion/GroovyCompletionUtil.java
@@ -31,6 +31,7 @@ import com.intellij.openapi.editor.highlighter.HighlighterIterator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
+import com.intellij.openapi.util.Conditions;
import com.intellij.openapi.util.Iconable;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
@@ -311,7 +312,7 @@ public class GroovyCompletionUtil {
if (element instanceof PsiClass) {
return JavaClassNameCompletionContributor
- .createClassLookupItems((PsiClass)element, afterNew, new GroovyClassNameInsertHandler(), Condition.TRUE);
+ .createClassLookupItems((PsiClass)element, afterNew, new GroovyClassNameInsertHandler(), Conditions.<PsiClass>alwaysTrue());
}
LookupElementBuilder builder = LookupElementBuilder.create(element instanceof PsiPackage ? element : candidate, name);
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcActionBase.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcActionBase.java
index 1745c67bde54..58449bcc082a 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcActionBase.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcActionBase.java
@@ -49,7 +49,8 @@ public abstract class MvcActionBase extends DumbAwareAction {
@Nullable
public static Pair<MvcFramework, Module> guessFramework(AnActionEvent event) {
- final Module module = event.getData(event.getPlace().equals(ActionPlaces.MAIN_MENU) ? LangDataKeys.MODULE : LangDataKeys.MODULE_CONTEXT);
+ final Module module = event.getData(
+ ActionPlaces.isMainMenuOrActionSearch(event.getPlace()) ? LangDataKeys.MODULE : LangDataKeys.MODULE_CONTEXT);
if (module != null) {
MvcFramework commonPluginModuleFramework = MvcFramework.findCommonPluginModuleFramework(module);
diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyDebuggerTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyDebuggerTest.groovy
index 022f775dcf7f..aa7885cf22fe 100644
--- a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyDebuggerTest.groovy
+++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyDebuggerTest.groovy
@@ -107,7 +107,7 @@ class GroovyDebuggerTest extends GroovyCompilerTestCase {
cl.call()
}
finally {
- def handler = debugProcess.executionResult.processHandler
+ def handler = debugProcess.processHandler
resume()
if (!handler.waitFor(ourTimeout)) {
if (handler instanceof OSProcessHandler) {
@@ -428,12 +428,12 @@ public static void main(String[] args) {
int i = 0
def suspendManager = debugProcess.suspendManager
- while (i++ < 1000 && !suspendManager.pausedContext && !debugProcess.executionResult.processHandler.processTerminated) {
+ while (i++ < 1000 && !suspendManager.pausedContext && !debugProcess.processHandler.processTerminated) {
Thread.sleep(10)
}
def context = suspendManager.pausedContext
- assert context : "too long process, terminated=$debugProcess.executionResult.processHandler.processTerminated"
+ assert context : "too long process, terminated=$debugProcess.processHandler.processTerminated"
return context
}
diff --git a/plugins/hg4idea/hg4idea.iml b/plugins/hg4idea/hg4idea.iml
index 93b5a5109bde..d765458336ea 100644
--- a/plugins/hg4idea/hg4idea.iml
+++ b/plugins/hg4idea/hg4idea.iml
@@ -20,6 +20,7 @@
<orderEntry type="module" module-name="vcs-log-api" />
<orderEntry type="module" module-name="vcs-log-impl" />
<orderEntry type="module" module-name="dvcs-api" />
+ <orderEntry type="module" module-name="lang-impl" />
</component>
</module>
diff --git a/plugins/hg4idea/src/META-INF/plugin.xml b/plugins/hg4idea/src/META-INF/plugin.xml
index 26b69326a703..dc32359a4aec 100644
--- a/plugins/hg4idea/src/META-INF/plugin.xml
+++ b/plugins/hg4idea/src/META-INF/plugin.xml
@@ -75,7 +75,7 @@
<action id="hg4idea.merge.files" class="org.zmlx.hg4idea.action.HgMerge" icon="AllIcons.Vcs.MergeSourcesTree"/>
<separator/>
- <action id="hg4idea.branches" class="org.zmlx.hg4idea.action.HgBranchesAction" text="_Branches..."/>
+ <action id="hg4idea.branches" class="org.zmlx.hg4idea.branch.HgBranchesAction" text="_Branches..."/>
<action id="hg4idea.tag" class="org.zmlx.hg4idea.action.HgCreateTagAction"/>
<action id="hg4idea.updateTo" class="org.zmlx.hg4idea.action.HgUpdateToAction"/>
<action id="hg4idea.resolve.mark" class="org.zmlx.hg4idea.action.HgMarkResolved"/>
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/HgProjectSettings.java b/plugins/hg4idea/src/org/zmlx/hg4idea/HgProjectSettings.java
index 936587d19755..8abac1bb0b1e 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/HgProjectSettings.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/HgProjectSettings.java
@@ -12,6 +12,8 @@
// limitations under the License.
package org.zmlx.hg4idea;
+import com.intellij.dvcs.branch.DvcsBranchSync;
+import com.intellij.dvcs.branch.DvcsSyncBranchSettings;
import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
@@ -24,7 +26,7 @@ import org.jetbrains.annotations.NotNull;
name = "hg4idea.settings",
storages = @Storage(file = StoragePathMacros.WORKSPACE_FILE)
)
-public class HgProjectSettings implements PersistentStateComponent<HgProjectSettings.State> {
+public class HgProjectSettings implements PersistentStateComponent<HgProjectSettings.State>, DvcsSyncBranchSettings {
@NotNull private final HgGlobalSettings myAppSettings;
@NotNull private final Project myProject;
@@ -37,10 +39,12 @@ public class HgProjectSettings implements PersistentStateComponent<HgProjectSett
}
public static class State {
+
public boolean myCheckIncoming = true;
public boolean myCheckOutgoing = true;
public Boolean CHECK_INCOMING_OUTGOING = null;
public boolean myIgnoreWhitespacesInAnnotations = true;
+ public DvcsBranchSync SYNC_SETTING = DvcsBranchSync.NOT_DECIDED;
}
public State getState() {
@@ -62,6 +66,15 @@ public class HgProjectSettings implements PersistentStateComponent<HgProjectSett
return myState.myIgnoreWhitespacesInAnnotations;
}
+ @NotNull
+ public DvcsBranchSync getSyncSetting() {
+ return myState.SYNC_SETTING;
+ }
+
+ public void setSyncSetting(@NotNull DvcsBranchSync syncSetting) {
+ myState.SYNC_SETTING = syncSetting;
+ }
+
public void setCheckIncomingOutgoing(boolean checkIncomingOutgoing) {
myState.CHECK_INCOMING_OUTGOING = checkIncomingOutgoing;
}
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractGlobalAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractGlobalAction.java
index d6282ebe8786..8a521202aa3c 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractGlobalAction.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgAbstractGlobalAction.java
@@ -34,7 +34,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
-abstract class HgAbstractGlobalAction extends AnAction {
+public abstract class HgAbstractGlobalAction extends AnAction {
protected HgAbstractGlobalAction(Icon icon) {
super(icon);
}
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchPopup.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchPopup.java
deleted file mode 100644
index c31e14e348d8..000000000000
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchPopup.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright 2000-2013 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.zmlx.hg4idea.action;
-
-import com.intellij.dvcs.DvcsUtil;
-import com.intellij.dvcs.ui.BranchActionGroupPopup;
-import com.intellij.dvcs.ui.RootAction;
-import com.intellij.openapi.actionSystem.ActionGroup;
-import com.intellij.openapi.actionSystem.AnAction;
-import com.intellij.openapi.actionSystem.DefaultActionGroup;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.ui.popup.ListPopup;
-import com.intellij.openapi.util.Condition;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.ui.popup.list.ListPopupImpl;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-import org.zmlx.hg4idea.repo.HgRepository;
-import org.zmlx.hg4idea.util.HgUtil;
-
-import javax.swing.*;
-import java.util.List;
-
-/**
- * <p>
- * The popup which allows to quickly switch and control Hg branches.
- * </p>
- * <p>
- * Use {@link #asListPopup()} to achieve the {@link com.intellij.openapi.ui.popup.ListPopup} itself.
- * </p>
- *
- * @author NadyaZabrodina
- */
-public class HgBranchPopup {
-
- private final Project myProject;
-
- private final HgRepository myCurrentRepository;
- private final ListPopupImpl myPopup;
-
- public ListPopup asListPopup() {
- return myPopup;
- }
-
- /**
- * @param currentRepository Current repository, which means the repository of the currently open or selected file.
- */
- public static HgBranchPopup getInstance(@NotNull Project project, @NotNull HgRepository currentRepository) {
- return new HgBranchPopup(project, currentRepository);
- }
-
- private HgBranchPopup(@NotNull Project project, @NotNull HgRepository currentRepository) {
- myProject = project;
- myCurrentRepository = currentRepository;
- String title = createPopupTitle(currentRepository);
-
- Condition<AnAction> preselectActionCondition = new Condition<AnAction>() {
- @Override
- public boolean value(AnAction action) {
- return false;
- }
- };
- myPopup = new BranchActionGroupPopup(title, project, preselectActionCondition, createActions());
- setCurrentBranchInfo();
- }
-
-
- @NotNull
- private static String createPopupTitle(@NotNull HgRepository currentRepository) {
- String title = "Hg Branches";
- title += " in " + DvcsUtil.getShortRepositoryName(currentRepository);
- return title;
- }
-
- private void setCurrentBranchInfo() {
- String branchText = "Current branch : ";
- //always display heavy branch name for additional info //
- myPopup.setAdText(branchText + myCurrentRepository.getCurrentBranch(), SwingConstants.CENTER);
- }
-
-
- private ActionGroup createActions() {
- DefaultActionGroup popupGroup = new DefaultActionGroup(null, false);
- fillPopupWithCurrentRepositoryActions(popupGroup, createRepositoriesActions());
- popupGroup.addSeparator();
- return popupGroup;
- }
-
-
- @Nullable
- private DefaultActionGroup createRepositoriesActions() {
- List<VirtualFile> repositories = HgUtil.getHgRepositories(myProject);
- if (repositories.size() == 1) {
- return null; // if project has only one repository all branches, bookmarks and actions should be inline and no repository group needed
- }
- DefaultActionGroup popupGroup = new DefaultActionGroup(null, false);
- popupGroup.addSeparator("Repositories");
- boolean isMultiRepoConfig = repositories.size() > 1;
- for (VirtualFile repository : repositories) {
- HgRepository repo = HgUtil.getRepositoryManager(myProject).getRepositoryForRoot(repository);
- if (repo != null) {
- popupGroup.add(new RootAction<HgRepository>(repo, isMultiRepoConfig ? myCurrentRepository : null,
- new HgBranchPopupActions(repo.getProject(), repo).createActions(null),
- HgUtil.getDisplayableBranchOrBookmarkText(repo)));
- }
- }
- return popupGroup;
- }
-
- protected void fillPopupWithCurrentRepositoryActions(@NotNull DefaultActionGroup popupGroup, @Nullable DefaultActionGroup actions) {
- popupGroup.addAll(new HgBranchPopupActions(myProject, myCurrentRepository).createActions(actions));
- }
-}
-
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCommonBranchActions.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCommonBranchActions.java
deleted file mode 100644
index c79ae1ca0b7c..000000000000
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgCommonBranchActions.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright 2000-2014 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.zmlx.hg4idea.action;
-
-import com.intellij.openapi.actionSystem.ActionGroup;
-import com.intellij.openapi.actionSystem.AnAction;
-import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.fileEditor.FileDocumentManager;
-import com.intellij.openapi.progress.ProgressIndicator;
-import com.intellij.openapi.progress.Task;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vcs.VcsException;
-import com.intellij.openapi.vcs.VcsNotifier;
-import com.intellij.openapi.vcs.update.UpdatedFiles;
-import com.intellij.openapi.vfs.VirtualFile;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-import org.zmlx.hg4idea.HgVcs;
-import org.zmlx.hg4idea.HgVcsMessages;
-import org.zmlx.hg4idea.command.HgMergeCommand;
-import org.zmlx.hg4idea.command.HgUpdateCommand;
-import org.zmlx.hg4idea.execution.HgCommandResult;
-import org.zmlx.hg4idea.provider.update.HgConflictResolver;
-import org.zmlx.hg4idea.provider.update.HgHeadMerger;
-import org.zmlx.hg4idea.repo.HgRepository;
-import org.zmlx.hg4idea.util.HgErrorUtil;
-
-public class HgCommonBranchActions extends ActionGroup {
-
- @NotNull protected final Project myProject;
- @NotNull protected String myBranchName;
- @NotNull protected final HgRepository mySelectedRepository;
-
- HgCommonBranchActions(@NotNull Project project, @NotNull HgRepository selectedRepository, @NotNull String branchName) {
- super("", true);
- myProject = project;
- myBranchName = branchName;
- mySelectedRepository = selectedRepository;
- getTemplatePresentation().setText(myBranchName, false); // no mnemonics
- }
-
- @NotNull
- @Override
- public AnAction[] getChildren(@Nullable AnActionEvent e) {
- return new AnAction[]{
- new UpdateAction(myProject, mySelectedRepository, myBranchName),
- new MergeAction(myProject, mySelectedRepository, myBranchName)
- };
- }
-
- private static class MergeAction extends HgBranchAbstractAction {
-
- public MergeAction(@NotNull Project project,
- @NotNull HgRepository selectedRepository,
- @NotNull String branchName) {
- super(project, "Merge", selectedRepository, branchName);
- }
-
- @Override
- public void actionPerformed(AnActionEvent e) {
- FileDocumentManager.getInstance().saveAllDocuments();
- final UpdatedFiles updatedFiles = UpdatedFiles.create();
- final HgMergeCommand hgMergeCommand = new HgMergeCommand(myProject, mySelectedRepository.getRoot());
- hgMergeCommand.setRevision(myBranchName);//there is no difference between branch or revision or bookmark as parameter to merge,
- // we need just a string
- new Task.Backgroundable(myProject, "Merging changes...") {
- @Override
- public void run(@NotNull ProgressIndicator indicator) {
- try {
- new HgHeadMerger(myProject, hgMergeCommand)
- .merge(mySelectedRepository.getRoot());
- new HgConflictResolver(myProject, updatedFiles).resolve(mySelectedRepository.getRoot());
- }
-
- catch (VcsException exception) {
- assert myProject != null; // myProject couldn't be null, see annotation for Merge action
- if (exception.isWarning()) {
- VcsNotifier.getInstance(myProject).notifyWarning("Warning during merge", exception.getMessage());
- }
- else {
- VcsNotifier.getInstance(myProject).notifyError("Exception during merge", exception.getMessage());
- }
- }
- catch (Exception e1) {
- HgAbstractGlobalAction.handleException(myProject, e1);
- }
- }
- }.queue();
- }
- }
-
- private static class UpdateAction extends HgBranchAbstractAction {
-
- public UpdateAction(@NotNull Project project,
- @NotNull HgRepository selectedRepository,
- @NotNull String branchName) {
- super(project, "Update", selectedRepository, branchName);
- }
-
- @Override
- public void actionPerformed(AnActionEvent e) {
- final VirtualFile repository = mySelectedRepository.getRoot();
- FileDocumentManager.getInstance().saveAllDocuments();
- final HgUpdateCommand hgUpdateCommand = new HgUpdateCommand(myProject, repository);
- hgUpdateCommand.setBranch(myBranchName);
- new Task.Backgroundable(myProject, HgVcsMessages.message("action.hg4idea.updateTo.description", myBranchName)) {
- @Override
- public void run(@NotNull ProgressIndicator indicator) {
- HgCommandResult result = hgUpdateCommand.execute();
- assert myProject != null; // myProject couldn't be null, see annotation for updateTo action
- if (HgErrorUtil.hasErrorsInCommandExecution(result)) {
- new HgCommandResultNotifier(myProject).notifyError(result, "", "Update failed");
- new HgConflictResolver(myProject).resolve(repository);
- }
- myProject.getMessageBus().syncPublisher(HgVcs.BRANCH_TOPIC).update(myProject, null);
- }
- }.queue();
- }
- }
-} \ No newline at end of file
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchAbstractAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgBranchAbstractAction.java
index 78b67013ed54..3998dedd0cc5 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchAbstractAction.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgBranchAbstractAction.java
@@ -13,24 +13,26 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.zmlx.hg4idea.action;
+package org.zmlx.hg4idea.branch;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
import org.zmlx.hg4idea.repo.HgRepository;
+import java.util.List;
+
public abstract class HgBranchAbstractAction extends DumbAwareAction {
@NotNull protected final Project myProject;
- @NotNull protected final HgRepository mySelectedRepository;
+ @NotNull protected final List<HgRepository> myRepositories;
@NotNull protected final String myBranchName;
public HgBranchAbstractAction(@NotNull Project project, @NotNull String title,
- @NotNull HgRepository selectedRepository,
+ @NotNull List<HgRepository> repositories,
@NotNull String branchName) {
super(title);
myProject = project;
- mySelectedRepository = selectedRepository;
+ myRepositories = repositories;
myBranchName = branchName;
}
} \ No newline at end of file
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgBranchPopup.java b/plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgBranchPopup.java
new file mode 100644
index 000000000000..c0d6f58d5e0e
--- /dev/null
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgBranchPopup.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.zmlx.hg4idea.branch;
+
+import com.intellij.dvcs.branch.DvcsBranchPopup;
+import com.intellij.dvcs.repo.AbstractRepositoryManager;
+import com.intellij.dvcs.ui.RootAction;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.DefaultActionGroup;
+import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Condition;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.zmlx.hg4idea.HgProjectSettings;
+import org.zmlx.hg4idea.repo.HgRepository;
+import org.zmlx.hg4idea.repo.HgRepositoryManager;
+import org.zmlx.hg4idea.util.HgUtil;
+
+import javax.swing.*;
+import java.util.List;
+
+/**
+ * <p>
+ * The popup which allows to quickly switch and control Hg branches.
+ * </p>
+ * <p>
+ * Use {@link #asListPopup()} to achieve the {@link com.intellij.openapi.ui.popup.ListPopup} itself.
+ * </p>
+ */
+public class HgBranchPopup extends DvcsBranchPopup<HgRepository> {
+
+ /**
+ * @param currentRepository Current repository, which means the repository of the currently open or selected file.
+ */
+ public static HgBranchPopup getInstance(@NotNull Project project, @NotNull HgRepository currentRepository) {
+
+ HgRepositoryManager manager = HgUtil.getRepositoryManager(project);
+ HgProjectSettings hgProjectSettings = ServiceManager.getService(project, HgProjectSettings.class);
+ HgMultiRootBranchConfig hgMultiRootBranchConfig = new HgMultiRootBranchConfig(manager.getRepositories());
+
+ Condition<AnAction> preselectActionCondition = new Condition<AnAction>() {
+ @Override
+ public boolean value(AnAction action) {
+ return false;
+ }
+ };
+ return new HgBranchPopup(currentRepository, manager, hgMultiRootBranchConfig, hgProjectSettings,
+ preselectActionCondition);
+ }
+
+ private HgBranchPopup(@NotNull HgRepository currentRepository,
+ @NotNull HgRepositoryManager repositoryManager,
+ @NotNull HgMultiRootBranchConfig hgMultiRootBranchConfig, @NotNull HgProjectSettings vcsSettings,
+ @NotNull Condition<AnAction> preselectActionCondition) {
+ super(currentRepository, repositoryManager, hgMultiRootBranchConfig, vcsSettings, preselectActionCondition);
+ }
+
+ protected void setCurrentBranchInfo() {
+ String branchText = "Current branch : ";
+ //always display heavy branch name for additional info //
+ myPopup.setAdText(branchText + myCurrentRepository.getCurrentBranch(), SwingConstants.CENTER);
+ }
+
+ @Override
+ protected void fillWithCommonRepositoryActions(@NotNull DefaultActionGroup popupGroup,
+ @NotNull AbstractRepositoryManager<HgRepository> repositoryManager) {
+ List<HgRepository> allRepositories = repositoryManager.getRepositories();
+ popupGroup.add(new HgBranchPopupActions.HgNewBranchAction(myProject, allRepositories, myCurrentRepository));
+ popupGroup.addAction(new HgBranchPopupActions.HgNewBookmarkAction(myProject, allRepositories, myCurrentRepository));
+ popupGroup.addAction(new HgBranchPopupActions.HgShowUnnamedHeadsForCurrentBranchAction(myProject, myCurrentRepository));
+ popupGroup.addAll(createRepositoriesActions());
+
+ popupGroup.addSeparator("Common Branches");
+ for (String branch : myMultiRootBranchConfig.getLocalBranchNames()) {
+ List<HgRepository> repositories = filterRepositoriesNotOnThisBranch(branch, allRepositories);
+ if (!repositories.isEmpty()) {
+ popupGroup.add(new HgCommonBranchActions(myProject, repositories, branch));
+ }
+ }
+ popupGroup.addSeparator("Common Bookmarks");
+ for (String branch : ((HgMultiRootBranchConfig)myMultiRootBranchConfig).getBookmarkNames()) {
+ List<HgRepository> repositories = filterRepositoriesNotOnThisBranch(branch, allRepositories);
+ if (!repositories.isEmpty()) {
+ popupGroup.add(new HgBranchPopupActions.BookmarkActions(myProject, repositories, branch));
+ }
+ }
+ }
+
+ @NotNull
+ protected DefaultActionGroup createRepositoriesActions() {
+ DefaultActionGroup popupGroup = new DefaultActionGroup(null, false);
+ popupGroup.addSeparator("Repositories");
+ for (HgRepository repository : myRepositoryManager.getRepositories()) {
+ popupGroup.add(new RootAction<HgRepository>(repository, highlightCurrentRepo() ? myCurrentRepository : null,
+ new HgBranchPopupActions(repository.getProject(), repository).createActions(null),
+ HgUtil.getDisplayableBranchOrBookmarkText(repository)));
+ }
+ return popupGroup;
+ }
+
+ protected void fillPopupWithCurrentRepositoryActions(@NotNull DefaultActionGroup popupGroup, @Nullable DefaultActionGroup actions) {
+ popupGroup.addAll(new HgBranchPopupActions(myProject, myCurrentRepository).createActions(actions));
+ }
+}
+
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchPopupActions.java b/plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgBranchPopupActions.java
index 45dd12bd9c81..10b97235f559 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchPopupActions.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgBranchPopupActions.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.zmlx.hg4idea.action;
+package org.zmlx.hg4idea.branch;
import com.intellij.dvcs.DvcsUtil;
import com.intellij.dvcs.repo.Repository;
@@ -35,6 +35,8 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.zmlx.hg4idea.HgNameWithHashInfo;
import org.zmlx.hg4idea.HgRevisionNumber;
+import org.zmlx.hg4idea.action.HgAbstractGlobalAction;
+import org.zmlx.hg4idea.action.HgCommandResultNotifier;
import org.zmlx.hg4idea.command.HgBookmarkCommand;
import org.zmlx.hg4idea.command.HgBranchCreateCommand;
import org.zmlx.hg4idea.command.HgWorkingCopyRevisionsCommand;
@@ -73,7 +75,7 @@ public class HgBranchPopupActions {
List<String> bookmarkNames = getNamesWithoutHashes(myRepository.getBookmarks());
String currentBookmark = myRepository.getCurrentBookmark();
for (String bookmark : bookmarkNames) {
- AnAction bookmarkAction = new BookmarkActions(myProject, myRepository, bookmark);
+ AnAction bookmarkAction = new BookmarkActions(myProject, Collections.singletonList(myRepository), bookmark);
if (bookmark.equals(currentBookmark)) {
bookmarkAction.getTemplatePresentation().setIcon(PlatformIcons.CHECK_ICON);
}
@@ -85,13 +87,13 @@ public class HgBranchPopupActions {
Collections.sort(branchNamesList);
for (String branch : branchNamesList) {
if (!branch.equals(myRepository.getCurrentBranch())) { // don't show current branch in the list
- popupGroup.add(new HgCommonBranchActions(myProject, myRepository, branch));
+ popupGroup.add(new HgCommonBranchActions(myProject, Collections.singletonList(myRepository), branch));
}
}
return popupGroup;
}
- private static class HgNewBranchAction extends NewBranchAction<HgRepository> {
+ public static class HgNewBranchAction extends NewBranchAction<HgRepository> {
@NotNull final HgRepository myPreselectedRepo;
HgNewBranchAction(@NotNull Project project, @NotNull List<HgRepository> repositories, @NotNull HgRepository preselectedRepo) {
@@ -105,25 +107,27 @@ public class HgBranchPopupActions {
if (name == null) {
return;
}
- try {
- new HgBranchCreateCommand(myProject, myPreselectedRepo.getRoot(), name).execute(new HgCommandResultHandler() {
- @Override
- public void process(@Nullable HgCommandResult result) {
- myPreselectedRepo.update();
- if (HgErrorUtil.hasErrorsInCommandExecution(result)) {
- new HgCommandResultNotifier(myProject)
- .notifyError(result, "Creation failed", "Branch creation [" + name + "] failed");
+ for (final HgRepository repository : myRepositories) {
+ try {
+ new HgBranchCreateCommand(myProject, repository.getRoot(), name).execute(new HgCommandResultHandler() {
+ @Override
+ public void process(@Nullable HgCommandResult result) {
+ repository.update();
+ if (HgErrorUtil.hasErrorsInCommandExecution(result)) {
+ new HgCommandResultNotifier(myProject)
+ .notifyError(result, "Creation failed", "Branch creation [" + name + "] failed");
+ }
}
- }
- });
- }
- catch (HgCommandException exception) {
- HgAbstractGlobalAction.handleException(myProject, "Can't create new branch: ", exception);
+ });
+ }
+ catch (HgCommandException exception) {
+ HgAbstractGlobalAction.handleException(myProject, "Can't create new branch: ", exception);
+ }
}
}
}
- private static class HgNewBookmarkAction extends DumbAwareAction {
+ public static class HgNewBookmarkAction extends DumbAwareAction {
@NotNull protected final List<HgRepository> myRepositories;
@NotNull protected Project myProject;
@NotNull final HgRepository myPreselectedRepo;
@@ -149,18 +153,20 @@ public class HgBranchPopupActions {
final HgBookmarkDialog bookmarkDialog = new HgBookmarkDialog(myPreselectedRepo);
bookmarkDialog.show();
if (bookmarkDialog.isOK()) {
- try {
- final String name = bookmarkDialog.getName();
- new HgBookmarkCommand(myProject, myPreselectedRepo.getRoot(), name).createBookmark(bookmarkDialog.isActive());
- }
- catch (HgCommandException exception) {
- HgAbstractGlobalAction.handleException(myProject, exception);
+ final String name = bookmarkDialog.getName();
+ for (HgRepository repository : myRepositories) {
+ try {
+ new HgBookmarkCommand(myProject, repository.getRoot(), name).createBookmark(bookmarkDialog.isActive());
+ }
+ catch (HgCommandException exception) {
+ HgAbstractGlobalAction.handleException(myProject, exception);
+ }
}
}
}
}
- static private class HgShowUnnamedHeadsForCurrentBranchAction extends ActionGroup {
+ public static class HgShowUnnamedHeadsForCurrentBranchAction extends ActionGroup {
@NotNull final Project myProject;
@NotNull final HgRepository myRepository;
@NotNull final String myCurrentBranchName;
@@ -210,7 +216,7 @@ public class HgBranchPopupActions {
public AnAction[] getChildren(@Nullable AnActionEvent e) {
List<AnAction> branchHeadActions = new ArrayList<AnAction>();
for (Hash hash : myHeads) {
- branchHeadActions.add(new HgCommonBranchActions(myProject, myRepository, hash.toShortString()));
+ branchHeadActions.add(new HgCommonBranchActions(myProject, Collections.singletonList(myRepository), hash.toShortString()));
}
return ContainerUtil.toArray(branchHeadActions, new AnAction[branchHeadActions.size()]);
}
@@ -232,29 +238,31 @@ public class HgBranchPopupActions {
*/
static class BookmarkActions extends HgCommonBranchActions {
- BookmarkActions(@NotNull Project project, @NotNull HgRepository selectedRepository, @NotNull String branchName) {
- super(project, selectedRepository, branchName);
+ BookmarkActions(@NotNull Project project, @NotNull List<HgRepository> repositories, @NotNull String branchName) {
+ super(project, repositories, branchName);
}
@NotNull
@Override
public AnAction[] getChildren(@Nullable AnActionEvent e) {
- return ArrayUtil.append(super.getChildren(e), new DeleteBookmarkAction(myProject, mySelectedRepository, myBranchName));
+ return ArrayUtil.append(super.getChildren(e), new DeleteBookmarkAction(myProject, myRepositories, myBranchName));
}
private static class DeleteBookmarkAction extends HgBranchAbstractAction {
- DeleteBookmarkAction(@NotNull Project project, @NotNull HgRepository selectedRepository, @NotNull String branchName) {
- super(project, "Delete", selectedRepository, branchName);
+ DeleteBookmarkAction(@NotNull Project project, @NotNull List<HgRepository> repositories, @NotNull String branchName) {
+ super(project, "Delete", repositories, branchName);
}
@Override
public void actionPerformed(AnActionEvent e) {
- try {
- new HgBookmarkCommand(myProject, mySelectedRepository.getRoot(), myBranchName).deleteBookmark();
- }
- catch (HgCommandException exception) {
- HgAbstractGlobalAction.handleException(myProject, exception);
+ for (HgRepository repository : myRepositories) {
+ try {
+ new HgBookmarkCommand(myProject, repository.getRoot(), myBranchName).deleteBookmark();
+ }
+ catch (HgCommandException exception) {
+ HgAbstractGlobalAction.handleException(myProject, exception);
+ }
}
}
}
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgBranchUtil.java b/plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgBranchUtil.java
new file mode 100644
index 000000000000..9dbdd3ea7f65
--- /dev/null
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgBranchUtil.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.zmlx.hg4idea.branch;
+
+import com.intellij.util.containers.ContainerUtil;
+import com.intellij.vcs.log.Hash;
+import org.jetbrains.annotations.NotNull;
+import org.zmlx.hg4idea.HgNameWithHashInfo;
+import org.zmlx.hg4idea.repo.HgRepository;
+import org.zmlx.hg4idea.util.HgUtil;
+
+import java.util.*;
+
+public class HgBranchUtil {
+
+ /**
+ * Only common hg heavy branches
+ */
+ @NotNull
+ public static Collection<String> getCommonBranches(@NotNull Collection<HgRepository> repositories) {
+ Collection<String> commonBranches = null;
+ for (HgRepository repository : repositories) {
+ Map<String, Set<Hash>> branchesWithHashes = repository.getBranches();
+ Collection<String> names = branchesWithHashes.keySet();
+ if (commonBranches == null) {
+ commonBranches = names;
+ }
+ else {
+ commonBranches = ContainerUtil.intersection(commonBranches, names);
+ }
+ }
+ if (commonBranches != null) {
+ ArrayList<String> common = new ArrayList<String>(commonBranches);
+ Collections.sort(common);
+ return common;
+ }
+ else {
+ return Collections.emptyList();
+ }
+ }
+
+ @NotNull
+ public static Collection<String> getCommonBookmarks(@NotNull Collection<HgRepository> repositories) {
+ Collection<String> commonBookmarkNames = null;
+ for (HgRepository repository : repositories) {
+ Collection<HgNameWithHashInfo> bookmarksInfo = repository.getBookmarks();
+ Collection<String> names = HgUtil.getNamesWithoutHashes(bookmarksInfo);
+ if (commonBookmarkNames == null) {
+ commonBookmarkNames = names;
+ }
+ else {
+ commonBookmarkNames = ContainerUtil.intersection(commonBookmarkNames, names);
+ }
+ }
+ if (commonBookmarkNames != null) {
+ ArrayList<String> common = new ArrayList<String>(commonBookmarkNames);
+ Collections.sort(common);
+ return common;
+ }
+ else {
+ return Collections.emptyList();
+ }
+ }
+}
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchesAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgBranchesAction.java
index d799cde1705c..b078da12548f 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgBranchesAction.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgBranchesAction.java
@@ -13,11 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.zmlx.hg4idea.action;
+package org.zmlx.hg4idea.branch;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import org.zmlx.hg4idea.action.HgAbstractGlobalSingleRepoAction;
import org.zmlx.hg4idea.repo.HgRepository;
import java.util.Collection;
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgCommonBranchActions.java b/plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgCommonBranchActions.java
new file mode 100644
index 000000000000..ecba99f7b532
--- /dev/null
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgCommonBranchActions.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.zmlx.hg4idea.branch;
+
+import com.intellij.openapi.actionSystem.ActionGroup;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.progress.ProgressIndicator;
+import com.intellij.openapi.progress.Task;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vcs.VcsException;
+import com.intellij.openapi.vcs.VcsNotifier;
+import com.intellij.openapi.vcs.update.UpdatedFiles;
+import com.intellij.openapi.vfs.VirtualFile;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.zmlx.hg4idea.HgVcs;
+import org.zmlx.hg4idea.HgVcsMessages;
+import org.zmlx.hg4idea.action.HgAbstractGlobalAction;
+import org.zmlx.hg4idea.action.HgCommandResultNotifier;
+import org.zmlx.hg4idea.command.HgMergeCommand;
+import org.zmlx.hg4idea.command.HgUpdateCommand;
+import org.zmlx.hg4idea.execution.HgCommandResult;
+import org.zmlx.hg4idea.provider.update.HgConflictResolver;
+import org.zmlx.hg4idea.provider.update.HgHeadMerger;
+import org.zmlx.hg4idea.repo.HgRepository;
+import org.zmlx.hg4idea.util.HgErrorUtil;
+
+import java.util.List;
+
+public class HgCommonBranchActions extends ActionGroup {
+
+ @NotNull protected final Project myProject;
+ @NotNull protected String myBranchName;
+ @NotNull List<HgRepository> myRepositories;
+
+ HgCommonBranchActions(@NotNull Project project, @NotNull List<HgRepository> repositories, @NotNull String branchName) {
+ super("", true);
+ myProject = project;
+ myBranchName = branchName;
+ myRepositories = repositories;
+ getTemplatePresentation().setText(myBranchName, false); // no mnemonics
+ }
+
+ @NotNull
+ @Override
+ public AnAction[] getChildren(@Nullable AnActionEvent e) {
+ return new AnAction[]{
+ new UpdateAction(myProject, myRepositories, myBranchName),
+ new MergeAction(myProject, myRepositories, myBranchName)
+ };
+ }
+
+ private static class MergeAction extends HgBranchAbstractAction {
+
+ public MergeAction(@NotNull Project project,
+ @NotNull List<HgRepository> repositories,
+ @NotNull String branchName) {
+ super(project, "Merge", repositories, branchName);
+ }
+
+ @Override
+ public void actionPerformed(AnActionEvent e) {
+ FileDocumentManager.getInstance().saveAllDocuments();
+ final UpdatedFiles updatedFiles = UpdatedFiles.create();
+ for (final HgRepository repository : myRepositories) {
+ final HgMergeCommand hgMergeCommand = new HgMergeCommand(myProject, repository.getRoot());
+ hgMergeCommand.setRevision(myBranchName);//there is no difference between branch or revision or bookmark as parameter to merge,
+ // we need just a string
+ new Task.Backgroundable(myProject, "Merging changes...") {
+ @Override
+ public void run(@NotNull ProgressIndicator indicator) {
+ try {
+ new HgHeadMerger(myProject, hgMergeCommand)
+ .merge(repository.getRoot());
+ new HgConflictResolver(myProject, updatedFiles).resolve(repository.getRoot());
+ }
+
+ catch (VcsException exception) {
+ assert myProject != null; // myProject couldn't be null, see annotation for Merge action
+ if (exception.isWarning()) {
+ VcsNotifier.getInstance(myProject).notifyWarning("Warning during merge", exception.getMessage());
+ }
+ else {
+ VcsNotifier.getInstance(myProject).notifyError("Exception during merge", exception.getMessage());
+ }
+ }
+ catch (Exception e1) {
+ HgAbstractGlobalAction.handleException(myProject, e1);
+ }
+ }
+ }.queue();
+ }
+ }
+ }
+
+ private static class UpdateAction extends HgBranchAbstractAction {
+
+ public UpdateAction(@NotNull Project project,
+ @NotNull List<HgRepository> repositories,
+ @NotNull String branchName) {
+ super(project, "Update", repositories, branchName);
+ }
+
+ @Override
+ public void actionPerformed(AnActionEvent e) {
+ FileDocumentManager.getInstance().saveAllDocuments();
+ for (HgRepository repo : myRepositories) {
+ final VirtualFile repository = repo.getRoot();
+ final HgUpdateCommand hgUpdateCommand = new HgUpdateCommand(myProject, repository);
+ hgUpdateCommand.setBranch(myBranchName);
+ new Task.Backgroundable(myProject, HgVcsMessages.message("action.hg4idea.updateTo.description", myBranchName)) {
+ @Override
+ public void run(@NotNull ProgressIndicator indicator) {
+ HgCommandResult result = hgUpdateCommand.execute();
+ assert myProject != null; // myProject couldn't be null, see annotation for updateTo action
+ if (HgErrorUtil.hasErrorsInCommandExecution(result)) {
+ new HgCommandResultNotifier(myProject).notifyError(result, "", "Update failed");
+ new HgConflictResolver(myProject).resolve(repository);
+ }
+ myProject.getMessageBus().syncPublisher(HgVcs.BRANCH_TOPIC).update(myProject, repository);
+ }
+ }.queue();
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgMultiRootBranchConfig.java b/plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgMultiRootBranchConfig.java
new file mode 100644
index 000000000000..e762fb8992ab
--- /dev/null
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/branch/HgMultiRootBranchConfig.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.zmlx.hg4idea.branch;
+
+import com.intellij.dvcs.branch.DvcsMultiRootBranchConfig;
+import org.jetbrains.annotations.NotNull;
+import org.zmlx.hg4idea.repo.HgRepository;
+
+import java.util.Collection;
+
+public class HgMultiRootBranchConfig extends DvcsMultiRootBranchConfig<HgRepository> {
+
+ public HgMultiRootBranchConfig(@NotNull Collection<HgRepository> repositories) {
+ super(repositories);
+ }
+
+ @NotNull
+ @Override
+ public Collection<String> getLocalBranchNames() {
+ return HgBranchUtil.getCommonBranches(myRepositories);
+ }
+
+ @NotNull
+ Collection<String> getBookmarkNames() {
+ return HgBranchUtil.getCommonBookmarks(myRepositories);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ for (HgRepository repository : myRepositories) {
+ sb.append(repository.getPresentableUrl()).append(":").append(repository.getCurrentBranchName()).append(":")
+ .append(repository.getState());
+ }
+ return sb.toString();
+ }
+}
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCommitCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCommitCommand.java
index 5aa632e0a4ea..794c7096d207 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCommitCommand.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgCommitCommand.java
@@ -53,6 +53,7 @@ public class HgCommitCommand {
private final boolean myAmend;
private Set<HgFile> myFiles = Collections.emptySet();
+ @NotNull private List<String> mySubrepos = Collections.emptyList();
public HgCommitCommand(Project project, @NotNull VirtualFile root, String message, boolean amend) {
myProject = project;
@@ -70,6 +71,10 @@ public class HgCommitCommand {
myFiles = files;
}
+ public void setSubrepos(@NotNull List<String> subrepos) {
+ mySubrepos = subrepos;
+ }
+
public void execute() throws HgCommandException, VcsException {
if (StringUtil.isEmptyOrSpaces(myMessage)) {
throw new HgCommandException(HgVcsMessages.message("hg4idea.commit.error.messageEmpty"));
@@ -88,7 +93,8 @@ public class HgCommitCommand {
});
List<List<String>> chunkedCommits = VcsFileUtil.chunkRelativePaths(relativePaths);
int size = chunkedCommits.size();
- commitChunkFiles(chunkedCommits.get(0), myAmend);
+ // commit with subrepo should be first, because it's not possible to amend with --subrepos argument;
+ commitChunkFiles(chunkedCommits.get(0), myAmend, !mySubrepos.isEmpty());
HgVcs vcs = HgVcs.getInstance(myProject);
boolean amendCommit = vcs != null && vcs.getVersion().isAmendSupported();
for (int i = 1; i < size; i++) {
@@ -105,14 +111,23 @@ public class HgCommitCommand {
messageBus.syncPublisher(HgVcs.BRANCH_TOPIC).update(myProject, null);
}
- private void commitChunkFiles(List<String> chunk, boolean amendCommit) throws VcsException {
+ private void commitChunkFiles(@NotNull List<String> chunk, boolean amendCommit) throws VcsException {
+ commitChunkFiles(chunk, amendCommit, false);
+ }
+
+ private void commitChunkFiles(@NotNull List<String> chunk, boolean amendCommit, boolean withSubrepos) throws VcsException {
List<String> parameters = new LinkedList<String>();
parameters.add("--logfile");
parameters.add(saveCommitMessage().getAbsolutePath());
- parameters.addAll(chunk);
- if (amendCommit) {
+ // note: for now mercurial could not perform amend commit with -S option
+ if (withSubrepos) {
+ parameters.add("-S");
+ parameters.addAll(mySubrepos);
+ }
+ else if (amendCommit) {
parameters.add("--amend");
}
+ parameters.addAll(chunk);
HgCommandExecutor executor = new HgCommandExecutor(myProject);
executor.setCharset(myCharset);
ensureSuccess(executor.executeInCurrentThread(myRoot, "commit", parameters));
@@ -129,5 +144,4 @@ public class HgCommitCommand {
}
return tempFile;
}
-
}
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgCommandExecutor.java b/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgCommandExecutor.java
index 7cf8f65559ea..f27d6a0d6550 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgCommandExecutor.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgCommandExecutor.java
@@ -49,7 +49,7 @@ import java.util.List;
*/
public class HgCommandExecutor {
- protected static final Logger LOG = Logger.getInstance(HgRemoteCommandExecutor.class.getName());
+ protected static final Logger LOG = Logger.getInstance(HgCommandExecutor.class.getName());
private static final List<String> DEFAULT_OPTIONS = Arrays.asList("--config", "ui.merge=internal:merge");
protected final Project myProject;
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgHistoryUtil.java b/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgHistoryUtil.java
index de565484e2d5..2d3a7bce191b 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgHistoryUtil.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgHistoryUtil.java
@@ -54,9 +54,9 @@ public class HgHistoryUtil {
}
@NotNull
- public static List<? extends VcsCommitMetadata> loadMetadata(@NotNull final Project project,
- @NotNull final VirtualFile root, int limit,
- @NotNull List<String> parameters) throws VcsException {
+ public static List<VcsCommitMetadata> loadMetadata(@NotNull final Project project,
+ @NotNull final VirtualFile root, int limit,
+ @NotNull List<String> parameters) throws VcsException {
final VcsLogObjectsFactory factory = getObjectsFactoryWithDisposeCheck(project);
if (factory == null) {
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgLogProvider.java b/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgLogProvider.java
index 3b989e448b61..109e83899e5b 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgLogProvider.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgLogProvider.java
@@ -22,9 +22,11 @@ import com.intellij.openapi.util.Couple;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.VcsKey;
import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.util.CollectConsumer;
import com.intellij.util.Consumer;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.vcs.log.*;
+import com.intellij.vcs.log.impl.LogDataImpl;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.zmlx.hg4idea.HgNameWithHashInfo;
@@ -59,18 +61,23 @@ public class HgLogProvider implements VcsLogProvider {
@NotNull
@Override
- public List<? extends VcsCommitMetadata> readFirstBlock(@NotNull VirtualFile root,
- @NotNull Requirements requirements) throws VcsException {
- return HgHistoryUtil.loadMetadata(myProject, root, requirements.getCommitCount(), Collections.<String>emptyList());
+ public DetailedLogData readFirstBlock(@NotNull VirtualFile root,
+ @NotNull Requirements requirements) throws VcsException {
+ List<VcsCommitMetadata> commits = HgHistoryUtil.loadMetadata(myProject, root, requirements.getCommitCount(),
+ Collections.<String>emptyList());
+ return new LogDataImpl(readAllRefs(root), commits);
}
@Override
- public void readAllHashes(@NotNull VirtualFile root, @NotNull Consumer<VcsUser> userRegistry,
- @NotNull Consumer<TimedVcsCommit> commitConsumer) throws VcsException {
- List<TimedVcsCommit> commits = HgHistoryUtil.readAllHashes(myProject, root, userRegistry, Collections.<String>emptyList());
+ @NotNull
+ public LogData readAllHashes(@NotNull VirtualFile root, @NotNull final Consumer<TimedVcsCommit> commitConsumer) throws VcsException {
+ Set<VcsUser> userRegistry = ContainerUtil.newHashSet();
+ List<TimedVcsCommit> commits = HgHistoryUtil.readAllHashes(myProject, root, new CollectConsumer<VcsUser>(userRegistry),
+ Collections.<String>emptyList());
for (TimedVcsCommit commit : commits) {
commitConsumer.consume(commit);
}
+ return new LogDataImpl(readAllRefs(root), userRegistry);
}
@NotNull
@@ -87,16 +94,15 @@ public class HgLogProvider implements VcsLogProvider {
}
@NotNull
- @Override
- public Collection<VcsRef> readAllRefs(@NotNull VirtualFile root) throws VcsException {
+ private Set<VcsRef> readAllRefs(@NotNull VirtualFile root) throws VcsException {
myRepositoryManager.waitUntilInitialized();
if (myProject.isDisposed()) {
- return Collections.emptyList();
+ return Collections.emptySet();
}
HgRepository repository = myRepositoryManager.getRepositoryForRoot(root);
if (repository == null) {
LOG.error("Repository not found for root " + root);
- return Collections.emptyList();
+ return Collections.emptySet();
}
repository.update();
@@ -106,7 +112,7 @@ public class HgLogProvider implements VcsLogProvider {
Collection<HgNameWithHashInfo> tags = repository.getTags();
Collection<HgNameWithHashInfo> localTags = repository.getLocalTags();
- Collection<VcsRef> refs = new ArrayList<VcsRef>(branches.size() + bookmarks.size());
+ Set<VcsRef> refs = new HashSet<VcsRef>(branches.size() + bookmarks.size());
for (Map.Entry<String, Set<Hash>> entry : branches.entrySet()) {
String branchName = entry.getKey();
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgChangeProvider.java b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgChangeProvider.java
index 02e49354f3ab..14a288171504 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgChangeProvider.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgChangeProvider.java
@@ -17,19 +17,24 @@ import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.*;
import com.intellij.openapi.vcs.changes.*;
+import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.ui.JBColor;
+import com.intellij.util.Function;
+import com.intellij.util.containers.ContainerUtil;
import com.intellij.vcsUtil.VcsUtil;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import org.zmlx.hg4idea.*;
import org.zmlx.hg4idea.command.HgResolveCommand;
import org.zmlx.hg4idea.command.HgResolveStatusEnum;
import org.zmlx.hg4idea.command.HgStatusCommand;
import org.zmlx.hg4idea.command.HgWorkingCopyRevisionsCommand;
+import org.zmlx.hg4idea.repo.HgRepository;
import org.zmlx.hg4idea.util.HgUtil;
-import java.awt.*;
+import java.io.File;
import java.util.*;
-import java.util.List;
public class HgChangeProvider implements ChangeProvider {
@@ -38,7 +43,7 @@ public class HgChangeProvider implements ChangeProvider {
public static final FileStatus COPIED = FileStatusFactory.getInstance().createFileStatus("COPIED", "Copied", FileStatus.COLOR_ADDED);
public static final FileStatus RENAMED = FileStatusFactory.getInstance().createFileStatus("RENAMED", "Renamed",
- Color.cyan.darker().darker());
+ JBColor.CYAN.darker().darker());
private static final EnumMap<HgFileStatusEnum, HgChangeProcessor> PROCESSORS =
new EnumMap<HgFileStatusEnum, HgChangeProcessor>(HgFileStatusEnum.class);
@@ -85,21 +90,42 @@ public class HgChangeProvider implements ChangeProvider {
final Map<HgFile, HgResolveStatusEnum> list = new HgResolveCommand(myProject).getListSynchronously(repo);
hgChanges.addAll(new HgStatusCommand.Builder(true).build(myProject).execute(repo, entry.getValue()));
+ final HgRepository hgRepo = HgUtil.getRepositoryForFile(myProject, repo);
+ if (hgRepo != null && hgRepo.hasSubrepos()) {
+ hgChanges.addAll(ContainerUtil.mapNotNull(hgRepo.getSubrepos(), new Function<HgNameWithHashInfo, HgChange>() {
+ @Override
+ public HgChange fun(HgNameWithHashInfo info) {
+ return findChange(hgRepo, info);
+ }
+ }));
+ }
+
sendChanges(builder, hgChanges, list, workingRevision, parentRevision);
}
return hgChanges;
}
+ @Nullable
+ private HgChange findChange(@NotNull HgRepository hgRepo, @NotNull HgNameWithHashInfo info) {
+ File file = new File(hgRepo.getRoot().getPath(), info.getName());
+ VirtualFile virtualSubrepoFile = VfsUtil.findFileByIoFile(file, false);
+ HgRepository subrepo = HgUtil.getRepositoryForFile(myProject, virtualSubrepoFile);
+ if (subrepo != null && !info.getHash().asString().equals(subrepo.getCurrentRevision())) {
+ return new HgChange(new HgFile(hgRepo.getRoot(), new FilePathImpl(virtualSubrepoFile)), HgFileStatusEnum.MODIFIED);
+ }
+ return null;
+ }
+
private void sendChanges(ChangelistBuilder builder, Set<HgChange> changes,
- Map<HgFile, HgResolveStatusEnum> resolveStatus, HgRevisionNumber workingRevision,
- HgRevisionNumber parentRevision) {
+ Map<HgFile, HgResolveStatusEnum> resolveStatus, HgRevisionNumber workingRevision,
+ HgRevisionNumber parentRevision) {
for (HgChange change : changes) {
HgFile afterFile = change.afterFile();
HgFile beforeFile = change.beforeFile();
HgFileStatusEnum status = change.getStatus();
if (resolveStatus.containsKey(afterFile)
- && resolveStatus.get(afterFile) == HgResolveStatusEnum.UNRESOLVED) {
+ && resolveStatus.get(afterFile) == HgResolveStatusEnum.UNRESOLVED) {
builder.processChange(
new Change(
new HgContentRevision(myProject, beforeFile, parentRevision),
@@ -286,9 +312,9 @@ public class HgChangeProvider implements ChangeProvider {
HgFile afterFile
);
- final void processChange(ContentRevision contentRevisionBefore,
- ContentRevision contentRevisionAfter, FileStatus fileStatus,
- ChangelistBuilder builder, VcsKey vcsKey) {
+ static void processChange(ContentRevision contentRevisionBefore,
+ ContentRevision contentRevisionAfter, FileStatus fileStatus,
+ ChangelistBuilder builder, VcsKey vcsKey) {
if (contentRevisionBefore == null && contentRevisionAfter == null) {
return;
}
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgCurrentBinaryContentRevision.java b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgCurrentBinaryContentRevision.java
index 8be5a7b0a9dd..a11a6c54e0c2 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgCurrentBinaryContentRevision.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgCurrentBinaryContentRevision.java
@@ -14,20 +14,28 @@ package org.zmlx.hg4idea.provider;
import com.intellij.openapi.vcs.changes.CurrentBinaryContentRevision;
import com.intellij.openapi.vcs.history.VcsRevisionNumber;
+import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.zmlx.hg4idea.HgFile;
-final class HgCurrentBinaryContentRevision extends CurrentBinaryContentRevision {
- private VcsRevisionNumber revisionNumber;
+final public class HgCurrentBinaryContentRevision extends CurrentBinaryContentRevision {
+ @NotNull private VcsRevisionNumber myRevisionNumber;
+ @NotNull private VirtualFile myRepositoryRoot;
- HgCurrentBinaryContentRevision(HgFile hgFile, VcsRevisionNumber revisionNumber) {
+ HgCurrentBinaryContentRevision(@NotNull HgFile hgFile, @NotNull VcsRevisionNumber revisionNumber) {
super(hgFile.toFilePath());
- this.revisionNumber = revisionNumber;
+ myRepositoryRoot = hgFile.getRepo();
+ myRevisionNumber = revisionNumber;
}
@NotNull
@Override
public VcsRevisionNumber getRevisionNumber() {
- return revisionNumber;
+ return myRevisionNumber;
+ }
+
+ @NotNull
+ public VirtualFile getRepositoryRoot() {
+ return myRepositoryRoot;
}
}
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgCurrentContentRevision.java b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgCurrentContentRevision.java
index c6c4bf72710b..3c427d8d7db9 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgCurrentContentRevision.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgCurrentContentRevision.java
@@ -34,7 +34,7 @@ class HgCurrentContentRevision extends CurrentContentRevision {
return revisionNumber;
}
- public static ContentRevision create(@NotNull HgFile hgFile, HgRevisionNumber revision) {
+ public static ContentRevision create(@NotNull HgFile hgFile, @NotNull HgRevisionNumber revision) {
VirtualFile virtualFile = VcsUtil.getVirtualFile(hgFile.getFile());
if (virtualFile == null) {
return null;
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/commit/HgCheckinEnvironment.java b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/commit/HgCheckinEnvironment.java
index 06b74148156e..509e4f82eaff 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/commit/HgCheckinEnvironment.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/commit/HgCheckinEnvironment.java
@@ -20,21 +20,21 @@ import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
+import com.intellij.openapi.util.Condition;
import com.intellij.openapi.vcs.CheckinProjectPanel;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.VcsException;
-import com.intellij.openapi.vcs.changes.Change;
-import com.intellij.openapi.vcs.changes.ChangeList;
-import com.intellij.openapi.vcs.changes.ContentRevision;
-import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager;
+import com.intellij.openapi.vcs.changes.*;
import com.intellij.openapi.vcs.checkin.CheckinEnvironment;
import com.intellij.openapi.vcs.ui.RefreshableOnComponent;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.FunctionUtil;
import com.intellij.util.NullableFunction;
import com.intellij.util.PairConsumer;
+import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.UIUtil;
import com.intellij.vcsUtil.VcsUtil;
+import com.intellij.xml.util.XmlStringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.zmlx.hg4idea.*;
@@ -43,17 +43,23 @@ import org.zmlx.hg4idea.command.*;
import org.zmlx.hg4idea.execution.HgCommandException;
import org.zmlx.hg4idea.execution.HgCommandExecutor;
import org.zmlx.hg4idea.execution.HgCommandResult;
+import org.zmlx.hg4idea.provider.HgCurrentBinaryContentRevision;
import org.zmlx.hg4idea.repo.HgRepository;
-import org.zmlx.hg4idea.repo.HgRepositoryManager;
import org.zmlx.hg4idea.util.HgUtil;
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
import java.util.*;
+import java.util.List;
public class HgCheckinEnvironment implements CheckinEnvironment {
private final Project myProject;
private boolean myNextCommitIsPushed;
private boolean myNextCommitAmend; // If true, the next commit is amended
+ private boolean myShouldCommitSubrepos;
public HgCheckinEnvironment(Project project) {
myProject = project;
@@ -83,21 +89,21 @@ public class HgCheckinEnvironment implements CheckinEnvironment {
@NotNull NullableFunction<Object, Object> parametersHolder,
Set<String> feedback) {
List<VcsException> exceptions = new LinkedList<VcsException>();
- Map<VirtualFile, Set<HgFile>> repositoriesMap = getFilesByRepository(changes);
- for (Map.Entry<VirtualFile, Set<HgFile>> entry : repositoriesMap.entrySet()) {
+ Map<HgRepository, Set<HgFile>> repositoriesMap = getFilesByRepository(changes);
+ for (Map.Entry<HgRepository, Set<HgFile>> entry : repositoriesMap.entrySet()) {
- VirtualFile repo = entry.getKey();
+ HgRepository repo = entry.getKey();
Set<HgFile> selectedFiles = entry.getValue();
+ HgCommitCommand command =
+ new HgCommitCommand(myProject, repo.getRoot(), preparedComment, myNextCommitAmend);
- HgCommitCommand command = new HgCommitCommand(myProject, repo, preparedComment, myNextCommitAmend);
-
- if (isMergeCommit(repo)) {
+ if (isMergeCommit(repo.getRoot())) {
//partial commits are not allowed during merges
//verifyResult that all changed files in the repo are selected
//If so, commit the entire repository
//If not, abort
- Set<HgFile> changedFilesNotInCommit = getChangedFilesNotInCommit(repo, selectedFiles);
+ Set<HgFile> changedFilesNotInCommit = getChangedFilesNotInCommit(repo.getRoot(), selectedFiles);
boolean partial = !changedFilesNotInCommit.isEmpty();
@@ -122,6 +128,9 @@ public class HgCheckinEnvironment implements CheckinEnvironment {
// so no need to set the files on the command, because then mercurial will complain
} else {
command.setFiles(selectedFiles);
+ if (myShouldCommitSubrepos && repo.hasSubrepos()) {
+ command.setSubrepos(HgUtil.getNamesWithoutHashes(repo.getSubrepos()));
+ }
}
try {
command.execute();
@@ -134,9 +143,7 @@ public class HgCheckinEnvironment implements CheckinEnvironment {
// push if needed
if (myNextCommitIsPushed && exceptions.isEmpty()) {
- final Set<VirtualFile> preselectedFiles = repositoriesMap.keySet();
- HgRepositoryManager repositoryManager = HgUtil.getRepositoryManager(myProject);
- final List<HgRepository> preselectedRepositories = HgActionUtil.collectRepositoriesFromFiles(repositoryManager, preselectedFiles);
+ final List<HgRepository> preselectedRepositories = ContainerUtil.newArrayList(repositoriesMap.keySet());
UIUtil.invokeLaterIfNeeded(new Runnable() {
public void run() {
new VcsPushDialog(myProject, preselectedRepositories).show();
@@ -154,7 +161,8 @@ public class HgCheckinEnvironment implements CheckinEnvironment {
private Set<HgFile> getChangedFilesNotInCommit(VirtualFile repo, Set<HgFile> selectedFiles) {
List<HgRevisionNumber> parents = new HgWorkingCopyRevisionsCommand(myProject).parents(repo);
- HgStatusCommand statusCommand = new HgStatusCommand.Builder(true).unknown(false).ignored(false).baseRevision(parents.get(0)).build(myProject);
+ HgStatusCommand statusCommand =
+ new HgStatusCommand.Builder(true).unknown(false).ignored(false).baseRevision(parents.get(0)).build(myProject);
Set<HgChange> allChangedFilesInRepo = statusCommand.execute(repo);
Set<HgFile> filesNotIncluded = new HashSet<HgFile>();
@@ -229,29 +237,29 @@ public class HgCheckinEnvironment implements CheckinEnvironment {
}
@NotNull
- private Map<VirtualFile, Set<HgFile>> getFilesByRepository(List<Change> changes) {
- Map<VirtualFile, Set<HgFile>> result = new HashMap<VirtualFile, Set<HgFile>>();
+ private Map<HgRepository, Set<HgFile>> getFilesByRepository(List<Change> changes) {
+ Map<HgRepository, Set<HgFile>> result = new HashMap<HgRepository, Set<HgFile>>();
for (Change change : changes) {
ContentRevision afterRevision = change.getAfterRevision();
ContentRevision beforeRevision = change.getBeforeRevision();
if (afterRevision != null) {
- addFile(result, afterRevision.getFile());
+ addFile(result, afterRevision);
}
if (beforeRevision != null) {
- addFile(result, beforeRevision.getFile());
+ addFile(result, beforeRevision);
}
}
return result;
}
- private void addFile(Map<VirtualFile, Set<HgFile>> result, FilePath filePath) {
- if (filePath == null) {
- return;
- }
-
- VirtualFile repo = VcsUtil.getVcsRootFor(myProject, filePath);
- if (repo == null || filePath.isDirectory()) {
+ private void addFile(Map<HgRepository, Set<HgFile>> result, ContentRevision contentRevision) {
+ FilePath filePath = contentRevision.getFile();
+ // try to find repository from hgFile from change
+ HgRepository repo = HgUtil.getRepositoryForFile(myProject, contentRevision instanceof HgCurrentBinaryContentRevision
+ ? ((HgCurrentBinaryContentRevision)contentRevision).getRepositoryRoot()
+ : ChangesUtil.findValidParentAccurately(filePath));
+ if (repo == null) {
return;
}
@@ -261,7 +269,7 @@ public class HgCheckinEnvironment implements CheckinEnvironment {
result.put(repo, hgFiles);
}
- hgFiles.add(new HgFile(repo, filePath));
+ hgFiles.add(new HgFile(repo.getRoot(), filePath));
}
public void setNextCommitIsPushed() {
@@ -272,27 +280,55 @@ public class HgCheckinEnvironment implements CheckinEnvironment {
* Commit options for hg
*/
private class HgCommitAdditionalComponent extends DvcsCommitAdditionalComponent {
+ @NotNull private final JCheckBox myCommitSubrepos;
public HgCommitAdditionalComponent(@NotNull Project project, @NotNull CheckinProjectPanel panel) {
super(project, panel);
HgVcs myVcs = HgVcs.getInstance(myProject);
myAmend.setEnabled(myVcs != null && myVcs.getVersion().isAmendSupported());
+ final Insets insets = new Insets(2, 2, 2, 2);
+ // add commit subrepos checkbox
+ GridBagConstraints c = new GridBagConstraints();
+ c.anchor = GridBagConstraints.CENTER;
+ c.insets = insets;
+ c.gridx = 1;
+ c.gridy = 2;
+ c.weightx = 1;
+ c.fill = GridBagConstraints.HORIZONTAL;
+ myCommitSubrepos = new JCheckBox("Commit subrepositories", false);
+ myCommitSubrepos.setToolTipText(XmlStringUtil.wrapInHtml(
+ "Commit all subrepos for selected repositories.<br>" +
+ " <code>hg ci <i><b>files</b></i> -S <i><b>subrepos</b></i></code>"));
+ myCommitSubrepos.setMnemonic('s');
+ myPanel.add(myCommitSubrepos, c);
+ Collection<HgRepository> repos =
+ HgActionUtil.collectRepositoriesFromFiles(HgUtil.getRepositoryManager(myProject), myCheckinPanel.getRoots());
+ myCommitSubrepos.setVisible(ContainerUtil.exists(repos, new Condition<HgRepository>() {
+ @Override
+ public boolean value(HgRepository repository) {
+ return repository.hasSubrepos();
+ }
+ }));
+ myCommitSubrepos.addActionListener(new MySelectionListener(myAmend));
+ myAmend.addActionListener(new MySelectionListener(myCommitSubrepos));
}
@Override
public void refresh() {
super.refresh();
- myNextCommitAmend = false;
+ restoreState();
}
@Override
public void saveState() {
myNextCommitAmend = myAmend.isSelected();
+ myShouldCommitSubrepos = myCommitSubrepos.isSelected();
}
@Override
public void restoreState() {
myNextCommitAmend = false;
+ myShouldCommitSubrepos = false;
}
@NotNull
@@ -313,5 +349,25 @@ public class HgCheckinEnvironment implements CheckinEnvironment {
HgCommandResult result = commandExecutor.executeInCurrentThread(repo, "log", args);
return result == null ? "" : result.getRawOutput();
}
+
+ private class MySelectionListener implements ActionListener {
+ JCheckBox myUnselectedComponent;
+
+ public MySelectionListener(JCheckBox unselectedComponent) {
+ myUnselectedComponent = unselectedComponent;
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ JCheckBox source = (JCheckBox)e.getSource();
+ if (source.isSelected()) {
+ myUnselectedComponent.setSelected(false);
+ myUnselectedComponent.setEnabled(false);
+ }
+ else{
+ myUnselectedComponent.setEnabled(true);
+ }
+ }
+ }
}
}
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushSupport.java b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushSupport.java
index 13f4aaa08f6a..af584d52c32c 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushSupport.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushSupport.java
@@ -15,28 +15,19 @@
*/
package org.zmlx.hg4idea.push;
-import com.intellij.dvcs.DvcsUtil;
import com.intellij.dvcs.push.*;
import com.intellij.dvcs.repo.RepositoryManager;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.AbstractVcs;
-import com.intellij.ui.SimpleColoredText;
-import com.intellij.ui.SimpleTextAttributes;
-import com.intellij.util.Function;
import com.intellij.util.ObjectUtils;
-import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.zmlx.hg4idea.HgVcs;
import org.zmlx.hg4idea.repo.HgRepository;
import org.zmlx.hg4idea.util.HgUtil;
-import java.util.List;
-
public class HgPushSupport extends PushSupport<HgRepository, HgPushSource, HgTarget> {
- private final static String ENTER_REMOTE = "Enter Remote";
@NotNull private final Project myProject;
@NotNull private final HgVcs myVcs;
@@ -72,28 +63,11 @@ public class HgPushSupport extends PushSupport<HgRepository, HgPushSource, HgTar
@NotNull
@Override
- public List<String> getTargetNames(@NotNull HgRepository repository) {
- return ContainerUtil.sorted(ContainerUtil.map(repository.getRepositoryConfig().getPaths(), new Function<String, String>() {
- @Override
- public String fun(String s) {
- return HgUtil.removePasswordIfNeeded(s);
- }
- }));
- }
-
- @NotNull
- @Override
public HgPushSource getSource(@NotNull HgRepository repository) {
- String localBranch = HgUtil.getActiveBranchName(repository);
+ String localBranch = repository.getCurrentBranchName();
return new HgPushSource(localBranch);
}
- @Override
- @NotNull
- public HgTarget createTarget(@NotNull HgRepository repository, @NotNull String targetName) {
- return new HgTarget(targetName);
- }
-
@NotNull
@Override
public RepositoryManager<HgRepository> getRepositoryManager() {
@@ -106,18 +80,8 @@ public class HgPushSupport extends PushSupport<HgRepository, HgPushSource, HgTar
}
@Override
- @Nullable
- public VcsError validate(@NotNull HgRepository repository, @Nullable String targetToValidate) {
- return StringUtil.isEmptyOrSpaces(targetToValidate)
- ? VcsError.createEmptyTargetError(DvcsUtil.getShortRepositoryName(repository))
- : null;
- }
-
- @Override
- public SimpleColoredText renderTarget(@Nullable HgTarget target) {
- if (target == null || StringUtil.isEmptyOrSpaces(target.getPresentation())) {
- return new SimpleColoredText(ENTER_REMOTE, SimpleTextAttributes.GRAY_ITALIC_ATTRIBUTES);
- }
- return new SimpleColoredText(target.getPresentation(), SimpleTextAttributes.SYNTHETIC_ATTRIBUTES);
+ @NotNull
+ public PushTargetPanel<HgTarget> createTargetPanel(@NotNull HgRepository repository, @Nullable HgTarget defaultTarget) {
+ return new HgPushTargetPanel(repository, defaultTarget);
}
}
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushTargetPanel.java b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushTargetPanel.java
new file mode 100644
index 000000000000..e3d02ea4e3fb
--- /dev/null
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgPushTargetPanel.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.zmlx.hg4idea.push;
+
+import com.intellij.dvcs.DvcsUtil;
+import com.intellij.dvcs.push.PushTargetPanel;
+import com.intellij.dvcs.push.VcsError;
+import com.intellij.openapi.ui.ValidationInfo;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.ui.ColoredTreeCellRenderer;
+import com.intellij.ui.SimpleTextAttributes;
+import com.intellij.ui.TextFieldWithAutoCompletion;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.zmlx.hg4idea.repo.HgRepository;
+import org.zmlx.hg4idea.util.HgUtil;
+
+import java.awt.*;
+import java.util.List;
+
+public class HgPushTargetPanel extends PushTargetPanel<HgTarget> {
+
+ private final static String ENTER_REMOTE = "Enter Remote";
+ private final HgRepository myRepository;
+ private final TextFieldWithAutoCompletion<String> myDestTargetPanel;
+ private String myOldText;
+
+ public HgPushTargetPanel(@NotNull HgRepository repository, @Nullable HgTarget defaultTarget) {
+ setLayout(new BorderLayout());
+ setOpaque(false);
+ myRepository = repository;
+ final List<String> targetVariants = HgUtil.getTargetNames(repository);
+ myOldText = defaultTarget != null ? defaultTarget.getPresentation() : "";
+ myDestTargetPanel = new PushTargetTextField(repository.getProject(), targetVariants, myOldText);
+ add(myDestTargetPanel, BorderLayout.CENTER);
+ }
+
+ @Override
+ public void render(@NotNull ColoredTreeCellRenderer renderer) {
+ String targetText = myDestTargetPanel.getText();
+ if (StringUtil.isEmptyOrSpaces(targetText)) {
+ renderer.append(ENTER_REMOTE, SimpleTextAttributes.GRAY_ITALIC_ATTRIBUTES, this);
+ }
+ renderer.append(targetText, SimpleTextAttributes.SYNTHETIC_ATTRIBUTES, this);
+ }
+
+ @Override
+ @NotNull
+ public HgTarget getValue() {
+ return createValidPushTarget();
+ }
+
+ @NotNull
+ private HgTarget createValidPushTarget() {
+ return new HgTarget(myDestTargetPanel.getText());
+ }
+
+ @Override
+ public void fireOnCancel() {
+ myDestTargetPanel.setText(myOldText);
+ }
+
+ @Override
+ public void fireOnChange() {
+ myOldText = myDestTargetPanel.getText();
+ }
+
+ @Nullable
+ public ValidationInfo verify() {
+ if (StringUtil.isEmptyOrSpaces(myDestTargetPanel.getText())) {
+ return new ValidationInfo(VcsError.createEmptyTargetError(DvcsUtil.getShortRepositoryName(myRepository)).getText(), this);
+ }
+ return null;
+ }
+}
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgTarget.java b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgTarget.java
index 8f5aca3838ca..87a5d3bf321e 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgTarget.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/push/HgTarget.java
@@ -26,7 +26,6 @@ public class HgTarget implements PushTarget {
myTarget = name;
}
- @Override
@NotNull
public String getPresentation() {
return HgUtil.removePasswordIfNeeded(myTarget);
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/push/PushTargetTextField.java b/plugins/hg4idea/src/org/zmlx/hg4idea/push/PushTargetTextField.java
new file mode 100644
index 000000000000..c05cb9133121
--- /dev/null
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/push/PushTargetTextField.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.zmlx.hg4idea.push;
+
+import com.intellij.openapi.editor.ex.EditorEx;
+import com.intellij.openapi.project.Project;
+import com.intellij.ui.TextFieldWithAutoCompletion;
+import com.intellij.ui.TextFieldWithAutoCompletionListProvider;
+import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.ui.UIUtil;
+import org.jetbrains.annotations.NotNull;
+
+import java.awt.event.FocusAdapter;
+import java.awt.event.FocusEvent;
+import java.util.List;
+
+public class PushTargetTextField extends TextFieldWithAutoCompletion<String> {
+
+ public PushTargetTextField(@NotNull Project project, @NotNull final List<String> targetVariants, @NotNull String defaultTargetName) {
+ super(project, getCompletionProvider(targetVariants), true, defaultTargetName);
+ setBorder(UIUtil.getTableFocusCellHighlightBorder());
+ setOneLineMode(true);
+ addFocusListener(new FocusAdapter() {
+ @Override
+ public void focusGained(FocusEvent e) {
+ selectAll();
+ }
+ });
+ }
+
+ @Override
+ public boolean shouldHaveBorder() {
+ return false;
+ }
+
+ @Override
+ protected void updateBorder(@NotNull final EditorEx editor) {
+ }
+
+ @NotNull
+ private static TextFieldWithAutoCompletionListProvider<String> getCompletionProvider(@NotNull final List<String> targetVariants) {
+ return new StringsCompletionProvider(targetVariants, null) {
+ @Override
+ public int compare(String item1, String item2) {
+ return Integer.valueOf(ContainerUtil.indexOf(targetVariants, item1)).compareTo(ContainerUtil.indexOf(targetVariants, item2));
+ }
+ };
+ }
+
+}
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepoInfo.java b/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepoInfo.java
index f73375f9c791..55efa0b43418 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepoInfo.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepoInfo.java
@@ -34,6 +34,7 @@ public class HgRepoInfo {
@NotNull private Set<HgNameWithHashInfo> myBookmarks = Collections.emptySet();
@NotNull private Set<HgNameWithHashInfo> myTags = Collections.emptySet();
@NotNull private Set<HgNameWithHashInfo> myLocalTags = Collections.emptySet();
+ @NotNull Set<HgNameWithHashInfo> mySubrepos = Collections.emptySet();
public HgRepoInfo(@NotNull String currentBranch,
@Nullable String currentRevision,
@@ -43,7 +44,7 @@ public class HgRepoInfo {
@NotNull Collection<HgNameWithHashInfo> bookmarks,
@Nullable String currentBookmark,
@NotNull Collection<HgNameWithHashInfo> tags,
- @NotNull Collection<HgNameWithHashInfo> localTags) {
+ @NotNull Collection<HgNameWithHashInfo> localTags, @NotNull Collection<HgNameWithHashInfo> subrepos) {
myCurrentBranch = currentBranch;
myCurrentRevision = currentRevision;
myTipRevision = currentTipRevision;
@@ -53,6 +54,7 @@ public class HgRepoInfo {
myCurrentBookmark = currentBookmark;
myTags = new LinkedHashSet<HgNameWithHashInfo>(tags);
myLocalTags = new LinkedHashSet<HgNameWithHashInfo>(localTags);
+ mySubrepos = new HashSet<HgNameWithHashInfo>(subrepos);
}
@NotNull
@@ -116,6 +118,7 @@ public class HgRepoInfo {
if (!myBookmarks.equals(info.myBookmarks)) return false;
if (!myTags.equals(info.myTags)) return false;
if (!myLocalTags.equals(info.myLocalTags)) return false;
+ if (!mySubrepos.equals(info.mySubrepos)) return false;
return true;
}
@@ -123,7 +126,7 @@ public class HgRepoInfo {
@Override
public int hashCode() {
return Objects.hashCode(myCurrentBranch, myCurrentRevision, myTipRevision, myCurrentBookmark, myState, myBranches, myBookmarks, myTags,
- myLocalTags);
+ myLocalTags, mySubrepos);
}
@Override
@@ -132,4 +135,13 @@ public class HgRepoInfo {
return String.format("HgRepository{myCurrentBranch=%s, myCurrentRevision='%s', myState=%s}",
myCurrentBranch, myCurrentRevision, myState);
}
+
+ public boolean hasSubrepos() {
+ return !mySubrepos.isEmpty();
+ }
+
+ @NotNull
+ public Collection<HgNameWithHashInfo> getSubrepos() {
+ return mySubrepos;
+ }
}
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepository.java b/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepository.java
index 8a5c4fc81e53..8d3b66f0ba54 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepository.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepository.java
@@ -71,5 +71,10 @@ public interface HgRepository extends Repository {
@NotNull
HgConfig getRepositoryConfig();
+ boolean hasSubrepos();
+
+ @NotNull
+ Collection<HgNameWithHashInfo> getSubrepos();
+
void updateConfig();
}
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryImpl.java b/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryImpl.java
index b670fb056c0c..6203f259b9bc 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryImpl.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryImpl.java
@@ -21,6 +21,7 @@ import com.intellij.openapi.Disposable;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vcs.AbstractVcs;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
@@ -99,6 +100,19 @@ public class HgRepositoryImpl extends RepositoryImpl implements HgRepository {
@Nullable
@Override
+ /**
+ * Return active bookmark name if exist or heavy branch name otherwise
+ */
+ public String getCurrentBranchName() {
+ String branchOrBookMarkName = getCurrentBookmark();
+ if (StringUtil.isEmptyOrSpaces(branchOrBookMarkName)) {
+ branchOrBookMarkName = getCurrentBranch();
+ }
+ return branchOrBookMarkName;
+ }
+
+ @Nullable
+ @Override
public AbstractVcs getVcs() {
return HgVcs.getInstance(getProject());
}
@@ -163,6 +177,16 @@ public class HgRepositoryImpl extends RepositoryImpl implements HgRepository {
}
@Override
+ public boolean hasSubrepos() {
+ return myInfo.hasSubrepos();
+ }
+
+ @NotNull
+ public Collection<HgNameWithHashInfo> getSubrepos() {
+ return myInfo.getSubrepos();
+ }
+
+ @Override
public boolean isFresh() {
return myIsFresh;
}
@@ -199,7 +223,8 @@ public class HgRepositoryImpl extends RepositoryImpl implements HgRepository {
return
new HgRepoInfo(myReader.readCurrentBranch(), myReader.readCurrentRevision(), myReader.readCurrentTipRevision(), myReader.readState(),
myReader.readBranches(),
- myReader.readBookmarks(), myReader.readCurrentBookmark(), myReader.readTags(), myReader.readLocalTags());
+ myReader.readBookmarks(), myReader.readCurrentBookmark(), myReader.readTags(), myReader.readLocalTags(),
+ myReader.readSubrepos());
}
public void updateConfig() {
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryReader.java b/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryReader.java
index 923087d0b3b2..fab661a99a32 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryReader.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/repo/HgRepositoryReader.java
@@ -48,10 +48,10 @@ public class HgRepositoryReader {
private static Pattern HASH_NAME = Pattern.compile("\\s*([0-9a-fA-F]+)\\s+(.+)");
private static Pattern HASH_STATUS_NAME = Pattern.compile("\\s*([0-9a-fA-F]+)\\s+\\w\\s+(.+)");
- //hash + name_or_revision_num; hash + status_character + name_or_revision_num
+ //hash + name_or_revision_num; hash + status_character + name_or_revision_num
@NotNull private final File myHgDir; // .hg
- @NotNull private File myBranchHeadsFile; // .hg/cache/branch* + part depends on version
+ @NotNull private File myBranchHeadsFile; // .hg/cache/branch* + part depends on version
@NotNull private final File myCacheDir; // .hg/cache (does not exist before first commit)
@NotNull private final File myCurrentBranch; // .hg/branch
@NotNull private final File myBookmarksFile; //.hg/bookmarks
@@ -59,6 +59,8 @@ public class HgRepositoryReader {
@NotNull private final File myTagsFile; //.hgtags - not in .hg directory!!!
@NotNull private final File myLocalTagsFile; // .hg/localtags
@NotNull private final File myDirStateFile; // .hg/dirstate
+ @NotNull private final File mySubrepoFile; // .hgsubstate
+
@NotNull private final VcsLogObjectsFactory myVcsObjectsFactory;
private final boolean myStatusInBranchFile;
@NotNull final HgVcs myVcs;
@@ -76,6 +78,7 @@ public class HgRepositoryReader {
myCurrentBookmark = new File(myHgDir, "bookmarks.current");
myLocalTagsFile = new File(myHgDir, "localtags");
myTagsFile = new File(myHgDir.getParentFile(), ".hgtags");
+ mySubrepoFile = new File(myHgDir.getParentFile(), ".hgsubstate");
myDirStateFile = new File(myHgDir, "dirstate");
myVcsObjectsFactory = ServiceManager.getService(vcs.getProject(), VcsLogObjectsFactory.class);
}
@@ -192,6 +195,10 @@ public class HgRepositoryReader {
return new File(myHgDir, "merge").exists();
}
+ public boolean hasSubrepos() {
+ return mySubrepoFile.exists();
+ }
+
public boolean isRebaseInProgress() {
return new File(myHgDir, "rebasestate").exists();
}
@@ -248,4 +255,11 @@ public class HgRepositoryReader {
public String readCurrentBookmark() {
return myCurrentBookmark.exists() ? RepositoryUtil.tryLoadFile(myCurrentBookmark) : null;
}
+
+ @NotNull
+ public Collection<HgNameWithHashInfo> readSubrepos() {
+ if (!hasSubrepos()) return Collections.emptySet();
+ return readReference(mySubrepoFile);
+ }
+
}
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/status/ui/HgStatusWidget.java b/plugins/hg4idea/src/org/zmlx/hg4idea/status/ui/HgStatusWidget.java
index 05a62338a9ce..9c89e74f8759 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/status/ui/HgStatusWidget.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/status/ui/HgStatusWidget.java
@@ -32,7 +32,7 @@ import org.jetbrains.annotations.Nullable;
import org.zmlx.hg4idea.HgProjectSettings;
import org.zmlx.hg4idea.HgUpdater;
import org.zmlx.hg4idea.HgVcs;
-import org.zmlx.hg4idea.action.HgBranchPopup;
+import org.zmlx.hg4idea.branch.HgBranchPopup;
import org.zmlx.hg4idea.repo.HgRepository;
import org.zmlx.hg4idea.util.HgUtil;
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgConfigurationProjectPanel.form b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgConfigurationProjectPanel.form
index 38dc6eb52908..cc1ea793d2c7 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgConfigurationProjectPanel.form
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgConfigurationProjectPanel.form
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.zmlx.hg4idea.ui.HgConfigurationProjectPanel">
- <grid id="27dc6" binding="myMainPanel" layout-manager="GridLayoutManager" row-count="3" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+ <grid id="27dc6" binding="myMainPanel" layout-manager="GridLayoutManager" row-count="4" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
- <xy x="20" y="20" width="623" height="228"/>
+ <xy x="20" y="20" width="623" height="299"/>
</constraints>
<properties/>
<border type="none"/>
@@ -11,7 +11,7 @@
<grid id="8c1f" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
- <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="8" fill="2" indent="0" use-parent-layout="false"/>
+ <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="8" fill="2" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<clientProperties>
@@ -39,16 +39,43 @@
</component>
</children>
</grid>
+ <vspacer id="4088f">
+ <constraints>
+ <grid row="3" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
+ </constraints>
+ </vspacer>
+ <grid id="c2117" binding="myRepositorySettingsPanel" layout-manager="GridLayoutManager" row-count="1" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+ <margin top="0" left="0" bottom="0" right="0"/>
+ <constraints>
+ <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="8" fill="2" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties/>
+ <clientProperties>
+ <BorderFactoryClass class="java.lang.String" value="com.intellij.ui.IdeBorderFactory$PlainSmallWithIndent"/>
+ </clientProperties>
+ <border type="etched" title="Repository Settings"/>
+ <children>
+ <component id="fadf2" class="com.intellij.ui.components.JBCheckBox" binding="mySyncBranchControl">
+ <constraints>
+ <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <text value="Control &amp;branches from different roots synchronously"/>
+ <toolTipText value="If selected, you would be able to checkout, compare, delete and create new branches in all Git roots with a single action"/>
+ </properties>
+ </component>
+ </children>
+ </grid>
<grid id="4e3f3" layout-manager="GridLayoutManager" row-count="1" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
- <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
+ <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<clientProperties>
<BorderFactoryClass class="java.lang.String" value="com.intellij.ui.IdeBorderFactory$PlainSmallWithIndent"/>
</clientProperties>
- <border type="etched" title="Path to hg executable"/>
+ <border type="none"/>
<children>
<component id="83ec6" class="com.intellij.openapi.ui.TextFieldWithBrowseButton" binding="myPathSelector" custom-create="true">
<constraints>
@@ -65,7 +92,7 @@
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
- <text value="&amp;Specify executable path"/>
+ <text value="&amp;Path to hg executable"/>
</properties>
</component>
<component id="61549" class="javax.swing.JButton" binding="myTestButton">
@@ -80,11 +107,6 @@
</component>
</children>
</grid>
- <vspacer id="4088f">
- <constraints>
- <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
- </constraints>
- </vspacer>
</children>
</grid>
<buttonGroups>
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgConfigurationProjectPanel.java b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgConfigurationProjectPanel.java
index 2aff9073d266..619536de0f88 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgConfigurationProjectPanel.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/ui/HgConfigurationProjectPanel.java
@@ -12,14 +12,18 @@
// limitations under the License.
package org.zmlx.hg4idea.ui;
+import com.intellij.dvcs.branch.DvcsBranchSync;
+import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
+import com.intellij.ui.components.JBCheckBox;
import org.jetbrains.annotations.NotNull;
import org.zmlx.hg4idea.HgProjectSettings;
import org.zmlx.hg4idea.HgVcs;
import org.zmlx.hg4idea.HgVcsMessages;
+import org.zmlx.hg4idea.repo.HgRepositoryManager;
import org.zmlx.hg4idea.util.HgUtil;
import org.zmlx.hg4idea.util.HgVersion;
@@ -36,6 +40,8 @@ public class HgConfigurationProjectPanel {
private JCheckBox myIgnoredWhitespacesInAnnotationsCbx;
private TextFieldWithBrowseButton myPathSelector;
private JButton myTestButton;
+ private JBCheckBox mySyncBranchControl;
+ private JPanel myRepositorySettingsPanel;
private final HgVcs myVcs;
public HgConfigurationProjectPanel(@NotNull HgProjectSettings projectSettings, @NotNull Project project) {
@@ -58,12 +64,15 @@ public class HgConfigurationProjectPanel {
);
}
});
+ final HgRepositoryManager repositoryManager = ServiceManager.getService(project, HgRepositoryManager.class);
+ myRepositorySettingsPanel.setVisible(repositoryManager != null && repositoryManager.moreThanOneRoot());
}
public boolean isModified() {
boolean executableModified = !getCurrentPath().equals(myProjectSettings.getHgExecutable());
return executableModified ||
myCheckIncomingOutgoingCbx.isSelected() != myProjectSettings.isCheckIncomingOutgoing() ||
+ ((myProjectSettings.getSyncSetting() == DvcsBranchSync.SYNC) != mySyncBranchControl.isSelected()) ||
myIgnoredWhitespacesInAnnotationsCbx.isSelected() != myProjectSettings.isWhitespacesIgnoredInAnnotations();
}
@@ -71,6 +80,7 @@ public class HgConfigurationProjectPanel {
myProjectSettings.setCheckIncomingOutgoing(myCheckIncomingOutgoingCbx.isSelected());
myProjectSettings.setIgnoreWhitespacesInAnnotations(myIgnoredWhitespacesInAnnotationsCbx.isSelected());
myProjectSettings.setHgExecutable(getCurrentPath());
+ myProjectSettings.setSyncSetting(mySyncBranchControl.isSelected() ? DvcsBranchSync.SYNC : DvcsBranchSync.DONT);
myVcs.checkVersion();
}
@@ -82,6 +92,7 @@ public class HgConfigurationProjectPanel {
myCheckIncomingOutgoingCbx.setSelected(myProjectSettings.isCheckIncomingOutgoing());
myIgnoredWhitespacesInAnnotationsCbx.setSelected(myProjectSettings.isWhitespacesIgnoredInAnnotations());
myPathSelector.setText(myProjectSettings.getGlobalSettings().getHgExecutable());
+ mySyncBranchControl.setSelected(myProjectSettings.getSyncSetting() == DvcsBranchSync.SYNC);
}
public JPanel getPanel() {
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgUtil.java b/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgUtil.java
index 3bb14721f0a8..fcf275f70703 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgUtil.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/util/HgUtil.java
@@ -41,6 +41,7 @@ import com.intellij.openapi.wm.StatusBar;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.openapi.wm.impl.status.StatusBarUtil;
import com.intellij.ui.GuiUtils;
+import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.vcsUtil.VcsUtil;
import org.jetbrains.annotations.NotNull;
@@ -584,16 +585,7 @@ public abstract class HgUtil {
if (state != HgRepository.State.NORMAL) {
branchText += state.toString() + " ";
}
- return branchText + getActiveBranchName(repository);
- }
-
- @NotNull
- public static String getActiveBranchName(@NotNull HgRepository repository) {
- String branchOrBookMarkName = repository.getCurrentBookmark();
- if (StringUtil.isEmptyOrSpaces(branchOrBookMarkName)) {
- branchOrBookMarkName = repository.getCurrentBranch();
- }
- return branchOrBookMarkName;
+ return branchText + repository.getCurrentBranchName();
}
@NotNull
@@ -716,4 +708,14 @@ public abstract class HgUtil {
}
return Couple.of(userName, email);
}
+
+ @NotNull
+ public static List<String> getTargetNames(@NotNull HgRepository repository) {
+ return ContainerUtil.sorted(ContainerUtil.map(repository.getRepositoryConfig().getPaths(), new Function<String, String>() {
+ @Override
+ public String fun(String s) {
+ return removePasswordIfNeeded(s);
+ }
+ }));
+ }
}
diff --git a/plugins/java-decompiler/engine/.gitattributes b/plugins/java-decompiler/engine/.gitattributes
new file mode 100644
index 000000000000..f1df734f9f0b
--- /dev/null
+++ b/plugins/java-decompiler/engine/.gitattributes
@@ -0,0 +1 @@
+*.dec text
diff --git a/plugins/java-decompiler/engine/build.xml b/plugins/java-decompiler/engine/build.xml
new file mode 100644
index 000000000000..8dde32e6adda
--- /dev/null
+++ b/plugins/java-decompiler/engine/build.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="Fernflower" default="dist" basedir=".">
+
+ <target name="init">
+ <property name="src" value="${basedir}/src"/>
+ <property name="out" value="${basedir}/out/production"/>
+ <property name="dist" value="${basedir}/fernflower.jar"/>
+ <property name="test-src" value="${basedir}/test"/>
+ <property name="test-out" value="${basedir}/out/test"/>
+ </target>
+
+ <!-- external dependencies, adjust to your own -->
+ <path id="junit">
+ <file name="${basedir}/../../../lib/junit-4.11.jar"/>
+ <file name="${basedir}/../../../lib/hamcrest-core-1.3.jar"/>
+ <file name="${basedir}/../../../lib/hamcrest-library-1.3.jar"/>
+ </path>
+
+ <target name="clean" depends="init">
+ <delete includeemptydirs="true" failonerror="false">
+ <fileset dir="${out}"/>
+ <fileset dir="${test-out}"/>
+ <fileset file="${dist}"/>
+ </delete>
+ </target>
+
+ <target name="compile" depends="init,clean">
+ <mkdir dir="${out}"/>
+ <javac srcdir="${src}" destdir="${out}" source="1.6" target="1.6" encoding="UTF-8" debug="true" includeantruntime="false"/>
+ </target>
+
+ <target name="dist" depends="init,compile">
+ <jar jarfile="${dist}" compress="true" basedir="${out}" includes="**/*.class">
+ <manifest>
+ <attribute name="Main-Class" value="org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler"/>
+ </manifest>
+ </jar>
+ </target>
+
+ <target name="test-compile" depends="init,compile">
+ <mkdir dir="${test-out}"/>
+ <javac srcdir="${test-src}" destdir="${test-out}" source="1.6" target="1.6" encoding="UTF-8" debug="true" includeantruntime="false">
+ <classpath path="${out}"/>
+ <classpath refid="junit"/>
+ </javac>
+ </target>
+
+ <target name="test" depends="init,test-compile">
+ <junit printsummary="true" haltonfailure="true">
+ <classpath path="${test-out}:${out}"/>
+ <classpath refid="junit"/>
+ <batchtest>
+ <fileset dir="${test-src}" includes="**/*Test.java"/>
+ </batchtest>
+ </junit>
+ </target>
+
+</project>
diff --git a/plugins/java-decompiler/engine/readme.txt b/plugins/java-decompiler/engine/readme.txt
new file mode 100644
index 000000000000..b0ea2733f6f3
--- /dev/null
+++ b/plugins/java-decompiler/engine/readme.txt
@@ -0,0 +1,88 @@
+1. About the decompiler
+
+Fernflower is the first actually working analytical decompiler for Java and
+probably for a high-level programming language in general. Naturally it is still
+under development, please send your bug reports and improvement suggestions at
+fernflower.decompiler@gmail.com
+
+
+2. License
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+
+3. Running from the command line
+
+java -jar fernflower.jar [-<option>=<value>]* [<source>]+ <destination>
+
+* means 0 or more times
++ means 1 or more times
+
+<source>: file or directory with files to be decompiled. Directories are recursively scanned. Allowed file extensions are class, zip and jar.
+ Sources prefixed with -e= mean "library" files that won't be decompiled, but taken into account when analysing relationships between
+ classes or methods. Especially renaming of identifiers (s. option 'ren') can benefit from information about external classes.
+<destination>: destination directory
+<option>,<value>: command line option with the corresponding value, see 4.
+
+Examples:
+
+java -jar fernflower.jar -hes=0 -hdc=0 c:\Temp\binary\ -e=c:\Java\rt.jar c:\Temp\source\
+
+java -jar fernflower.jar -dgs=1 c:\Temp\binary\library.jar c:\Temp\binary\Boot.class c:\Temp\source\
+
+
+4. Command line options
+
+With the exception of mpm and urc the value of 1 means the option is activated, 0 - deactivated. Default
+value, if any, is given between parentheses.
+
+Typically, the following options will be changed by user, if any: hes, hdc, dgs, mpm, ren, urc
+The rest of options can be left as they are: they are aimed at professional reverse engineers.
+
+rbr (1): hide bridge methods
+rsy (0): hide synthetic class members
+din (1): decompile inner classes
+dc4 (1): collapse 1.4 class references
+das (1): decompile assertions
+hes (1): hide empty super invocation
+hdc (1): hide empty default constructor
+dgs (0): decompile generic signatures
+ner (1): assume return not throwing exceptions
+den (1): decompile enumerations
+rgn (1): remove getClass() invocation, when it is part of a qualified new statement
+lit (0): output numeric literals "as-is"
+asc (0): encode non-ASCII characters in string and character literals as Unicode escapes
+bto (1): interpret int 1 as boolean true (workaround to a compiler bug)
+nns (1): allow for not set synthetic attribute (workaround to a compiler bug)
+uto (1): consider nameless types as java.lang.Object (workaround to a compiler architecture flaw)
+udv (1): reconstruct variable names from debug information, if present
+rer (1): remove empty exception ranges
+fdi (1): de-inline finally structures
+mpm (0): maximum allowed processing time per decompiled method, in seconds. 0 means no upper limit
+ren (0): rename ambiguous (resp. obfuscated) classes and class elements
+urc : full name of user-supplied class implementing IIdentifierRenamer. It is used to determine which class identifiers
+ should be renamed and provides new identifier names. For more information see section 5
+inn (1): check for IntelliJ IDEA-specific @NotNull annotation and remove inserted code if found
+lac (0): decompile lambda expressions to anonymous classes
+nls (0): define new line character to be used for output. 0 - '\r\n' (Windows), 1 - '\n' (Linux), default is OS-dependent
+ind : indentation string (default is " " (3 spaces))
+
+The default logging level is INFO. This value can be overwritten by setting the option 'log' as follows:
+log (INFO): possible values TRACE, INFO, WARN, ERROR
+
+
+5. Renaming identifiers
+
+Some obfuscators give classes and their member elements short, meaningless and above all ambiguous names. Recompiling of such
+code leads to a great number of conflicts. Therefore it is advisable to let the decompiler rename elements in its turn,
+ensuring uniqueness of each identifier.
+
+Option 'ren' (i.e. -ren=1) activates renaming functionality. Default renaming strategy goes as follows:
+- rename an element if its name is a reserved word or is shorter than 3 characters
+- new names are built according to a simple pattern: (class|method|field)_<consecutive unique number>
+You can overwrite this rules by providing your own implementation of the 4 key methods invoked by the decompiler while renaming. Simply
+pass a class that implements org.jetbrains.java.decompiler.main.extern.IIdentifierRenamer in the option 'urc'
+(e.g. -urc=com.mypackage.MyRenamer) to Fernflower. The class must be available on the application classpath.
+
+The meaning of each method should be clear from naming: toBeRenamed determine whether the element will be renamed, while the other three
+provide new names for classes, methods and fields respectively.
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/CodeConstants.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/CodeConstants.java
new file mode 100644
index 000000000000..4a7ef0fc1815
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/CodeConstants.java
@@ -0,0 +1,370 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code;
+
+public interface CodeConstants {
+
+ // ----------------------------------------------------------------------
+ // BYTECODE VERSIONS
+ // ----------------------------------------------------------------------
+
+ int BYTECODE_JAVA_LE_4 = 1;
+ int BYTECODE_JAVA_5 = 2;
+ int BYTECODE_JAVA_6 = 3;
+ int BYTECODE_JAVA_7 = 4;
+ int BYTECODE_JAVA_8 = 5;
+
+ // ----------------------------------------------------------------------
+ // VARIABLE TYPES
+ // ----------------------------------------------------------------------
+
+ int TYPE_BYTE = 0;
+ int TYPE_CHAR = 1;
+ int TYPE_DOUBLE = 2;
+ int TYPE_FLOAT = 3;
+ int TYPE_INT = 4;
+ int TYPE_LONG = 5;
+ int TYPE_SHORT = 6;
+ int TYPE_BOOLEAN = 7;
+ int TYPE_OBJECT = 8;
+ int TYPE_ADDRESS = 9;
+ int TYPE_VOID = 10;
+ int TYPE_ANY = 11;
+ int TYPE_GROUP2EMPTY = 12;
+ int TYPE_NULL = 13;
+ int TYPE_NOTINITIALIZED = 14;
+ int TYPE_BYTECHAR = 15;
+ int TYPE_SHORTCHAR = 16;
+ int TYPE_UNKNOWN = 17;
+ int TYPE_GENVAR = 18;
+
+ // ----------------------------------------------------------------------
+ // VARIABLE TYPE FAMILIES
+ // ----------------------------------------------------------------------
+
+ int TYPE_FAMILY_UNKNOWN = 0;
+ int TYPE_FAMILY_BOOLEAN = 1;
+ int TYPE_FAMILY_INTEGER = 2;
+ int TYPE_FAMILY_FLOAT = 3;
+ int TYPE_FAMILY_LONG = 4;
+ int TYPE_FAMILY_DOUBLE = 5;
+ int TYPE_FAMILY_OBJECT = 6;
+
+ // ----------------------------------------------------------------------
+ // MODULE CONSTANTS
+ // ----------------------------------------------------------------------
+
+ int STACKSIZE_SIMPLE = 1;
+ int STACKSIZE_DOUBLE = 2;
+
+ int VAR_LOCAL = 0;
+ int VAR_STACK = 1;
+
+ int VAR_WRITE = 0;
+ int VAR_READ = 1;
+
+
+ // ----------------------------------------------------------------------
+ // ACCESS FLAGS
+ // ----------------------------------------------------------------------
+
+ int ACC_PUBLIC = 0x0001;
+ int ACC_PRIVATE = 0x0002;
+ int ACC_PROTECTED = 0x0004;
+ int ACC_STATIC = 0x0008;
+ int ACC_FINAL = 0x0010;
+ int ACC_SYNCHRONIZED = 0x0020;
+ int ACC_NATIVE = 0x0100;
+ int ACC_ABSTRACT = 0x0400;
+ int ACC_STRICT = 0x0800;
+ int ACC_VOLATILE = 0x0040;
+ int ACC_BRIDGE = 0x0040;
+ int ACC_TRANSIENT = 0x0080;
+ int ACC_VARARGS = 0x0080;
+ int ACC_SYNTHETIC = 0x1000;
+ int ACC_ANNOTATION = 0x2000;
+ int ACC_ENUM = 0x4000;
+
+ // ----------------------------------------------------------------------
+ // CLASS FLAGS
+ // ----------------------------------------------------------------------
+
+ int ACC_SUPER = 0x0020;
+ int ACC_INTERFACE = 0x0200;
+
+
+ // ----------------------------------------------------------------------
+ // DEPENDENCY CONSTANTS
+ // ----------------------------------------------------------------------
+
+ int DEP_CONSTANT = 0;
+ int DEP_UNKNOWN = 1;
+ int DEP_GENERAL = 2;
+ int DEP_PARAMS = 4;
+ int DEP_STATIC = 8;
+
+ // ----------------------------------------------------------------------
+ // INSTRUCTION GROUPS
+ // ----------------------------------------------------------------------
+
+ int GROUP_GENERAL = 1;
+ int GROUP_JUMP = 2;
+ int GROUP_SWITCH = 3;
+ int GROUP_INVOCATION = 4;
+ int GROUP_FIELDACCESS = 5;
+ int GROUP_RETURN = 6;
+
+ // ----------------------------------------------------------------------
+ // POOL CONSTANTS
+ // ----------------------------------------------------------------------
+
+ int CONSTANT_Utf8 = 1;
+ int CONSTANT_Integer = 3;
+ int CONSTANT_Float = 4;
+ int CONSTANT_Long = 5;
+ int CONSTANT_Double = 6;
+ int CONSTANT_Class = 7;
+ int CONSTANT_String = 8;
+ int CONSTANT_Fieldref = 9;
+ int CONSTANT_Methodref = 10;
+ int CONSTANT_InterfaceMethodref = 11;
+ int CONSTANT_NameAndType = 12;
+ int CONSTANT_MethodHandle = 15;
+ int CONSTANT_MethodType = 16;
+ int CONSTANT_InvokeDynamic = 18;
+
+ // ----------------------------------------------------------------------
+ // MethodHandle reference_kind values
+ // ----------------------------------------------------------------------
+
+ int CONSTANT_MethodHandle_REF_getField = 1;
+ int CONSTANT_MethodHandle_REF_getStatic = 2;
+ int CONSTANT_MethodHandle_REF_putField = 3;
+ int CONSTANT_MethodHandle_REF_putStatic = 4;
+ int CONSTANT_MethodHandle_REF_invokeVirtual = 5;
+ int CONSTANT_MethodHandle_REF_invokeStatic = 6;
+ int CONSTANT_MethodHandle_REF_invokeSpecial = 7;
+ int CONSTANT_MethodHandle_REF_newInvokeSpecial = 8;
+ int CONSTANT_MethodHandle_REF_invokeInterface = 9;
+
+ // ----------------------------------------------------------------------
+ // VM OPCODES
+ // ----------------------------------------------------------------------
+
+ int opc_nop = 0;
+ int opc_aconst_null = 1;
+ int opc_iconst_m1 = 2;
+ int opc_iconst_0 = 3;
+ int opc_iconst_1 = 4;
+ int opc_iconst_2 = 5;
+ int opc_iconst_3 = 6;
+ int opc_iconst_4 = 7;
+ int opc_iconst_5 = 8;
+ int opc_lconst_0 = 9;
+ int opc_lconst_1 = 10;
+ int opc_fconst_0 = 11;
+ int opc_fconst_1 = 12;
+ int opc_fconst_2 = 13;
+ int opc_dconst_0 = 14;
+ int opc_dconst_1 = 15;
+ int opc_bipush = 16;
+ int opc_sipush = 17;
+ int opc_ldc = 18;
+ int opc_ldc_w = 19;
+ int opc_ldc2_w = 20;
+ int opc_iload = 21;
+ int opc_lload = 22;
+ int opc_fload = 23;
+ int opc_dload = 24;
+ int opc_aload = 25;
+ int opc_iload_0 = 26;
+ int opc_iload_1 = 27;
+ int opc_iload_2 = 28;
+ int opc_iload_3 = 29;
+ int opc_lload_0 = 30;
+ int opc_lload_1 = 31;
+ int opc_lload_2 = 32;
+ int opc_lload_3 = 33;
+ int opc_fload_0 = 34;
+ int opc_fload_1 = 35;
+ int opc_fload_2 = 36;
+ int opc_fload_3 = 37;
+ int opc_dload_0 = 38;
+ int opc_dload_1 = 39;
+ int opc_dload_2 = 40;
+ int opc_dload_3 = 41;
+ int opc_aload_0 = 42;
+ int opc_aload_1 = 43;
+ int opc_aload_2 = 44;
+ int opc_aload_3 = 45;
+ int opc_iaload = 46;
+ int opc_laload = 47;
+ int opc_faload = 48;
+ int opc_daload = 49;
+ int opc_aaload = 50;
+ int opc_baload = 51;
+ int opc_caload = 52;
+ int opc_saload = 53;
+ int opc_istore = 54;
+ int opc_lstore = 55;
+ int opc_fstore = 56;
+ int opc_dstore = 57;
+ int opc_astore = 58;
+ int opc_istore_0 = 59;
+ int opc_istore_1 = 60;
+ int opc_istore_2 = 61;
+ int opc_istore_3 = 62;
+ int opc_lstore_0 = 63;
+ int opc_lstore_1 = 64;
+ int opc_lstore_2 = 65;
+ int opc_lstore_3 = 66;
+ int opc_fstore_0 = 67;
+ int opc_fstore_1 = 68;
+ int opc_fstore_2 = 69;
+ int opc_fstore_3 = 70;
+ int opc_dstore_0 = 71;
+ int opc_dstore_1 = 72;
+ int opc_dstore_2 = 73;
+ int opc_dstore_3 = 74;
+ int opc_astore_0 = 75;
+ int opc_astore_1 = 76;
+ int opc_astore_2 = 77;
+ int opc_astore_3 = 78;
+ int opc_iastore = 79;
+ int opc_lastore = 80;
+ int opc_fastore = 81;
+ int opc_dastore = 82;
+ int opc_aastore = 83;
+ int opc_bastore = 84;
+ int opc_castore = 85;
+ int opc_sastore = 86;
+ int opc_pop = 87;
+ int opc_pop2 = 88;
+ int opc_dup = 89;
+ int opc_dup_x1 = 90;
+ int opc_dup_x2 = 91;
+ int opc_dup2 = 92;
+ int opc_dup2_x1 = 93;
+ int opc_dup2_x2 = 94;
+ int opc_swap = 95;
+ int opc_iadd = 96;
+ int opc_ladd = 97;
+ int opc_fadd = 98;
+ int opc_dadd = 99;
+ int opc_isub = 100;
+ int opc_lsub = 101;
+ int opc_fsub = 102;
+ int opc_dsub = 103;
+ int opc_imul = 104;
+ int opc_lmul = 105;
+ int opc_fmul = 106;
+ int opc_dmul = 107;
+ int opc_idiv = 108;
+ int opc_ldiv = 109;
+ int opc_fdiv = 110;
+ int opc_ddiv = 111;
+ int opc_irem = 112;
+ int opc_lrem = 113;
+ int opc_frem = 114;
+ int opc_drem = 115;
+ int opc_ineg = 116;
+ int opc_lneg = 117;
+ int opc_fneg = 118;
+ int opc_dneg = 119;
+ int opc_ishl = 120;
+ int opc_lshl = 121;
+ int opc_ishr = 122;
+ int opc_lshr = 123;
+ int opc_iushr = 124;
+ int opc_lushr = 125;
+ int opc_iand = 126;
+ int opc_land = 127;
+ int opc_ior = 128;
+ int opc_lor = 129;
+ int opc_ixor = 130;
+ int opc_lxor = 131;
+ int opc_iinc = 132;
+ int opc_i2l = 133;
+ int opc_i2f = 134;
+ int opc_i2d = 135;
+ int opc_l2i = 136;
+ int opc_l2f = 137;
+ int opc_l2d = 138;
+ int opc_f2i = 139;
+ int opc_f2l = 140;
+ int opc_f2d = 141;
+ int opc_d2i = 142;
+ int opc_d2l = 143;
+ int opc_d2f = 144;
+ int opc_i2b = 145;
+ int opc_i2c = 146;
+ int opc_i2s = 147;
+ int opc_lcmp = 148;
+ int opc_fcmpl = 149;
+ int opc_fcmpg = 150;
+ int opc_dcmpl = 151;
+ int opc_dcmpg = 152;
+ int opc_ifeq = 153;
+ int opc_ifne = 154;
+ int opc_iflt = 155;
+ int opc_ifge = 156;
+ int opc_ifgt = 157;
+ int opc_ifle = 158;
+ int opc_if_icmpeq = 159;
+ int opc_if_icmpne = 160;
+ int opc_if_icmplt = 161;
+ int opc_if_icmpge = 162;
+ int opc_if_icmpgt = 163;
+ int opc_if_icmple = 164;
+ int opc_if_acmpeq = 165;
+ int opc_if_acmpne = 166;
+ int opc_goto = 167;
+ int opc_jsr = 168;
+ int opc_ret = 169;
+ int opc_tableswitch = 170;
+ int opc_lookupswitch = 171;
+ int opc_ireturn = 172;
+ int opc_lreturn = 173;
+ int opc_freturn = 174;
+ int opc_dreturn = 175;
+ int opc_areturn = 176;
+ int opc_return = 177;
+ int opc_getstatic = 178;
+ int opc_putstatic = 179;
+ int opc_getfield = 180;
+ int opc_putfield = 181;
+ int opc_invokevirtual = 182;
+ int opc_invokespecial = 183;
+ int opc_invokestatic = 184;
+ int opc_invokeinterface = 185;
+ int opc_invokedynamic = 186;
+ int opc_xxxunusedxxx = 186;
+ int opc_new = 187;
+ int opc_newarray = 188;
+ int opc_anewarray = 189;
+ int opc_arraylength = 190;
+ int opc_athrow = 191;
+ int opc_checkcast = 192;
+ int opc_instanceof = 193;
+ int opc_monitorenter = 194;
+ int opc_monitorexit = 195;
+ int opc_wide = 196;
+ int opc_multianewarray = 197;
+ int opc_ifnull = 198;
+ int opc_ifnonnull = 199;
+ int opc_goto_w = 200;
+ int opc_jsr_w = 201;
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/ConstantsUtil.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/ConstantsUtil.java
new file mode 100644
index 000000000000..79eecdffa673
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/ConstantsUtil.java
@@ -0,0 +1,482 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code;
+
+import org.jetbrains.java.decompiler.code.optinstructions.*;
+
+public class ConstantsUtil {
+
+ public static String getName(int opcode) {
+ return opcodeNames[opcode];
+ }
+
+ public static Instruction getInstructionInstance(int opcode, boolean wide, int group, int bytecode_version, int[] operands) {
+
+ Instruction instr = getInstructionInstance(opcode, bytecode_version);
+ instr.wide = wide;
+ instr.group = group;
+ instr.bytecode_version = bytecode_version;
+ instr.setOperands(operands);
+
+ return instr;
+ }
+
+ private static Instruction getInstructionInstance(int opcode, int bytecode_version) {
+ try {
+ Instruction instr;
+
+ if ((opcode >= CodeConstants.opc_ifeq &&
+ opcode <= CodeConstants.opc_if_acmpne) ||
+ opcode == CodeConstants.opc_ifnull ||
+ opcode == CodeConstants.opc_ifnonnull) {
+ instr = new IfInstruction();
+ }
+ else {
+
+ Class cl = opcodeClasses[opcode];
+
+ if (opcode == CodeConstants.opc_invokedynamic && bytecode_version < CodeConstants.BYTECODE_JAVA_7) {
+ cl = null; // instruction unused in Java 6 and before
+ }
+
+ if (cl == null) {
+ instr = new Instruction();
+ }
+ else {
+ instr = (Instruction)cl.newInstance();
+ }
+ }
+
+ instr.opcode = opcode;
+ return instr;
+ }
+ catch (Exception ex) {
+ return null;
+ }
+ }
+
+
+ private static String[] opcodeNames = {
+ "nop", // "nop",
+ "aconst_null", // "aconst_null",
+ "iconst_m1", // "iconst_m1",
+ "iconst_0", // "iconst_0",
+ "iconst_1", // "iconst_1",
+ "iconst_2", // "iconst_2",
+ "iconst_3", // "iconst_3",
+ "iconst_4", // "iconst_4",
+ "iconst_5", // "iconst_5",
+ "lconst_0", // "lconst_0",
+ "lconst_1", // "lconst_1",
+ "fconst_0", // "fconst_0",
+ "fconst_1", // "fconst_1",
+ "fconst_2", // "fconst_2",
+ "dconst_0", // "dconst_0",
+ "dconst_1", // "dconst_1",
+ "bipush", // "bipush",
+ "sipush", // "sipush",
+ "ldc", // "ldc",
+ "ldc_w", // "ldc_w",
+ "ldc2_w", // "ldc2_w",
+ "iload", // "iload",
+ "lload", // "lload",
+ "fload", // "fload",
+ "dload", // "dload",
+ "aload", // "aload",
+ "iload_0", // "iload_0",
+ "iload_1", // "iload_1",
+ "iload_2", // "iload_2",
+ "iload_3", // "iload_3",
+ "lload_0", // "lload_0",
+ "lload_1", // "lload_1",
+ "lload_2", // "lload_2",
+ "lload_3", // "lload_3",
+ "fload_0", // "fload_0",
+ "fload_1", // "fload_1",
+ "fload_2", // "fload_2",
+ "fload_3", // "fload_3",
+ "dload_0", // "dload_0",
+ "dload_1", // "dload_1",
+ "dload_2", // "dload_2",
+ "dload_3", // "dload_3",
+ "aload_0", // "aload_0",
+ "aload_1", // "aload_1",
+ "aload_2", // "aload_2",
+ "aload_3", // "aload_3",
+ "iaload", // "iaload",
+ "laload", // "laload",
+ "faload", // "faload",
+ "daload", // "daload",
+ "aaload", // "aaload",
+ "baload", // "baload",
+ "caload", // "caload",
+ "saload", // "saload",
+ "istore", // "istore",
+ "lstore", // "lstore",
+ "fstore", // "fstore",
+ "dstore", // "dstore",
+ "astore", // "astore",
+ "istore_0", // "istore_0",
+ "istore_1", // "istore_1",
+ "istore_2", // "istore_2",
+ "istore_3", // "istore_3",
+ "lstore_0", // "lstore_0",
+ "lstore_1", // "lstore_1",
+ "lstore_2", // "lstore_2",
+ "lstore_3", // "lstore_3",
+ "fstore_0", // "fstore_0",
+ "fstore_1", // "fstore_1",
+ "fstore_2", // "fstore_2",
+ "fstore_3", // "fstore_3",
+ "dstore_0", // "dstore_0",
+ "dstore_1", // "dstore_1",
+ "dstore_2", // "dstore_2",
+ "dstore_3", // "dstore_3",
+ "astore_0", // "astore_0",
+ "astore_1", // "astore_1",
+ "astore_2", // "astore_2",
+ "astore_3", // "astore_3",
+ "iastore", // "iastore",
+ "lastore", // "lastore",
+ "fastore", // "fastore",
+ "dastore", // "dastore",
+ "aastore", // "aastore",
+ "bastore", // "bastore",
+ "castore", // "castore",
+ "sastore", // "sastore",
+ "pop", // "pop",
+ "pop2", // "pop2",
+ "dup", // "dup",
+ "dup_x1", // "dup_x1",
+ "dup_x2", // "dup_x2",
+ "dup2", // "dup2",
+ "dup2_x1", // "dup2_x1",
+ "dup2_x2", // "dup2_x2",
+ "swap", // "swap",
+ "iadd", // "iadd",
+ "ladd", // "ladd",
+ "fadd", // "fadd",
+ "dadd", // "dadd",
+ "isub", // "isub",
+ "lsub", // "lsub",
+ "fsub", // "fsub",
+ "dsub", // "dsub",
+ "imul", // "imul",
+ "lmul", // "lmul",
+ "fmul", // "fmul",
+ "dmul", // "dmul",
+ "idiv", // "idiv",
+ "ldiv", // "ldiv",
+ "fdiv", // "fdiv",
+ "ddiv", // "ddiv",
+ "irem", // "irem",
+ "lrem", // "lrem",
+ "frem", // "frem",
+ "drem", // "drem",
+ "ineg", // "ineg",
+ "lneg", // "lneg",
+ "fneg", // "fneg",
+ "dneg", // "dneg",
+ "ishl", // "ishl",
+ "lshl", // "lshl",
+ "ishr", // "ishr",
+ "lshr", // "lshr",
+ "iushr", // "iushr",
+ "lushr", // "lushr",
+ "iand", // "iand",
+ "land", // "land",
+ "ior", // "ior",
+ "lor", // "lor",
+ "ixor", // "ixor",
+ "lxor", // "lxor",
+ "iinc", // "iinc",
+ "i2l", // "i2l",
+ "i2f", // "i2f",
+ "i2d", // "i2d",
+ "l2i", // "l2i",
+ "l2f", // "l2f",
+ "l2d", // "l2d",
+ "f2i", // "f2i",
+ "f2l", // "f2l",
+ "f2d", // "f2d",
+ "d2i", // "d2i",
+ "d2l", // "d2l",
+ "d2f", // "d2f",
+ "i2b", // "i2b",
+ "i2c", // "i2c",
+ "i2s", // "i2s",
+ "lcmp", // "lcmp",
+ "fcmpl", // "fcmpl",
+ "fcmpg", // "fcmpg",
+ "dcmpl", // "dcmpl",
+ "dcmpg", // "dcmpg",
+ "ifeq", // "ifeq",
+ "ifne", // "ifne",
+ "iflt", // "iflt",
+ "ifge", // "ifge",
+ "ifgt", // "ifgt",
+ "ifle", // "ifle",
+ "if_icmpeq", // "if_icmpeq",
+ "if_icmpne", // "if_icmpne",
+ "if_icmplt", // "if_icmplt",
+ "if_icmpge", // "if_icmpge",
+ "if_icmpgt", // "if_icmpgt",
+ "if_icmple", // "if_icmple",
+ "if_acmpeq", // "if_acmpeq",
+ "if_acmpne", // "if_acmpne",
+ "goto", // "goto",
+ "jsr", // "jsr",
+ "ret", // "ret",
+ "tableswitch", // "tableswitch",
+ "lookupswitch", // "lookupswitch",
+ "ireturn", // "ireturn",
+ "lreturn", // "lreturn",
+ "freturn", // "freturn",
+ "dreturn", // "dreturn",
+ "areturn", // "areturn",
+ "return", // "return",
+ "getstatic", // "getstatic",
+ "putstatic", // "putstatic",
+ "getfield", // "getfield",
+ "putfield", // "putfield",
+ "invokevirtual", // "invokevirtual",
+ "invokespecial", // "invokespecial",
+ "invokestatic", // "invokestatic",
+ "invokeinterface", // "invokeinterface",
+ //"xxxunusedxxx", // "xxxunusedxxx", Java 6 and before
+ "invokedynamic", // "invokedynamic", Java 7 and later
+ "new", // "new",
+ "newarray", // "newarray",
+ "anewarray", // "anewarray",
+ "arraylength", // "arraylength",
+ "athrow", // "athrow",
+ "checkcast", // "checkcast",
+ "instanceof", // "instanceof",
+ "monitorenter", // "monitorenter",
+ "monitorexit", // "monitorexit",
+ "wide", // "wide",
+ "multianewarray", // "multianewarray",
+ "ifnull", // "ifnull",
+ "ifnonnull", // "ifnonnull",
+ "goto_w", // "goto_w",
+ "jsr_w" // "jsr_w"
+ };
+
+ private static Class[] opcodeClasses = {
+ null, // "nop",
+ null, // "aconst_null",
+ null, // "iconst_m1",
+ null, // "iconst_0",
+ null, // "iconst_1",
+ null, // "iconst_2",
+ null, // "iconst_3",
+ null, // "iconst_4",
+ null, // "iconst_5",
+ null, // "lconst_0",
+ null, // "lconst_1",
+ null, // "fconst_0",
+ null, // "fconst_1",
+ null, // "fconst_2",
+ null, // "dconst_0",
+ null, // "dconst_1",
+ BIPUSH.class, // "bipush",
+ SIPUSH.class, // "sipush",
+ LDC.class, // "ldc",
+ LDC_W.class, // "ldc_w",
+ LDC2_W.class, // "ldc2_w",
+ ILOAD.class, // "iload",
+ LLOAD.class, // "lload",
+ FLOAD.class, // "fload",
+ DLOAD.class, // "dload",
+ ALOAD.class, // "aload",
+ null, // "iload_0",
+ null, // "iload_1",
+ null, // "iload_2",
+ null, // "iload_3",
+ null, // "lload_0",
+ null, // "lload_1",
+ null, // "lload_2",
+ null, // "lload_3",
+ null, // "fload_0",
+ null, // "fload_1",
+ null, // "fload_2",
+ null, // "fload_3",
+ null, // "dload_0",
+ null, // "dload_1",
+ null, // "dload_2",
+ null, // "dload_3",
+ null, // "aload_0",
+ null, // "aload_1",
+ null, // "aload_2",
+ null, // "aload_3",
+ null, // "iaload",
+ null, // "laload",
+ null, // "faload",
+ null, // "daload",
+ null, // "aaload",
+ null, // "baload",
+ null, // "caload",
+ null, // "saload",
+ ISTORE.class, // "istore",
+ LSTORE.class, // "lstore",
+ FSTORE.class, // "fstore",
+ DSTORE.class, // "dstore",
+ ASTORE.class, // "astore",
+ null, // "istore_0",
+ null, // "istore_1",
+ null, // "istore_2",
+ null, // "istore_3",
+ null, // "lstore_0",
+ null, // "lstore_1",
+ null, // "lstore_2",
+ null, // "lstore_3",
+ null, // "fstore_0",
+ null, // "fstore_1",
+ null, // "fstore_2",
+ null, // "fstore_3",
+ null, // "dstore_0",
+ null, // "dstore_1",
+ null, // "dstore_2",
+ null, // "dstore_3",
+ null, // "astore_0",
+ null, // "astore_1",
+ null, // "astore_2",
+ null, // "astore_3",
+ null, // "iastore",
+ null, // "lastore",
+ null, // "fastore",
+ null, // "dastore",
+ null, // "aastore",
+ null, // "bastore",
+ null, // "castore",
+ null, // "sastore",
+ null, // "pop",
+ null, // "pop2",
+ null, // "dup",
+ null, // "dup_x1",
+ null, // "dup_x2",
+ null, // "dup2",
+ null, // "dup2_x1",
+ null, // "dup2_x2",
+ null, // "swap",
+ null, // "iadd",
+ null, // "ladd",
+ null, // "fadd",
+ null, // "dadd",
+ null, // "isub",
+ null, // "lsub",
+ null, // "fsub",
+ null, // "dsub",
+ null, // "imul",
+ null, // "lmul",
+ null, // "fmul",
+ null, // "dmul",
+ null, // "idiv",
+ null, // "ldiv",
+ null, // "fdiv",
+ null, // "ddiv",
+ null, // "irem",
+ null, // "lrem",
+ null, // "frem",
+ null, // "drem",
+ null, // "ineg",
+ null, // "lneg",
+ null, // "fneg",
+ null, // "dneg",
+ null, // "ishl",
+ null, // "lshl",
+ null, // "ishr",
+ null, // "lshr",
+ null, // "iushr",
+ null, // "lushr",
+ null, // "iand",
+ null, // "land",
+ null, // "ior",
+ null, // "lor",
+ null, // "ixor",
+ null, // "lxor",
+ IINC.class, // "iinc",
+ null, // "i2l",
+ null, // "i2f",
+ null, // "i2d",
+ null, // "l2i",
+ null, // "l2f",
+ null, // "l2d",
+ null, // "f2i",
+ null, // "f2l",
+ null, // "f2d",
+ null, // "d2i",
+ null, // "d2l",
+ null, // "d2f",
+ null, // "i2b",
+ null, // "i2c",
+ null, // "i2s",
+ null, // "lcmp",
+ null, // "fcmpl",
+ null, // "fcmpg",
+ null, // "dcmpl",
+ null, // "dcmpg",
+ null, // "ifeq",
+ null, // "ifne",
+ null, // "iflt",
+ null, // "ifge",
+ null, // "ifgt",
+ null, // "ifle",
+ null, // "if_icmpeq",
+ null, // "if_icmpne",
+ null, // "if_icmplt",
+ null, // "if_icmpge",
+ null, // "if_icmpgt",
+ null, // "if_icmple",
+ null, // "if_acmpeq",
+ null, // "if_acmpne",
+ GOTO.class, // "goto",
+ JSR.class, // "jsr",
+ RET.class, // "ret",
+ TABLESWITCH.class, // "tableswitch",
+ LOOKUPSWITCH.class, // "lookupswitch",
+ null, // "ireturn",
+ null, // "lreturn",
+ null, // "freturn",
+ null, // "dreturn",
+ null, // "areturn",
+ null, // "return",
+ GETSTATIC.class, // "getstatic",
+ PUTSTATIC.class, // "putstatic",
+ GETFIELD.class, // "getfield",
+ PUTFIELD.class, // "putfield",
+ INVOKEVIRTUAL.class, // "invokevirtual",
+ INVOKESPECIAL.class, // "invokespecial",
+ INVOKESTATIC.class, // "invokestatic",
+ INVOKEINTERFACE.class, // "invokeinterface",
+ INVOKEDYNAMIC.class, // "xxxunusedxxx" Java 6 and before, "invokedynamic" Java 7 and later
+ NEW.class, // "new",
+ NEWARRAY.class, // "newarray",
+ ANEWARRAY.class, // "anewarray",
+ null, // "arraylength",
+ null, // "athrow",
+ CHECKCAST.class, // "checkcast",
+ INSTANCEOF.class, // "instanceof",
+ null, // "monitorenter",
+ null, // "monitorexit",
+ null, // "wide",
+ MULTIANEWARRAY.class, // "multianewarray",
+ null, // "ifnull",
+ null, // "ifnonnull",
+ GOTO_W.class, // "goto_w",
+ JSR_W.class // "jsr_w"
+ };
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/ExceptionHandler.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/ExceptionHandler.java
new file mode 100644
index 000000000000..2927294d8d4a
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/ExceptionHandler.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code;
+
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class ExceptionHandler {
+
+ public int from = 0;
+ public int to = 0;
+ public int handler = 0;
+
+ public int from_instr = 0;
+ public int to_instr = 0;
+ public int handler_instr = 0;
+
+ public int class_index = 0;
+ public String exceptionClass = null;
+
+ public ExceptionHandler() {
+ }
+
+ public ExceptionHandler(int from_raw, int to_raw, int handler_raw, String exceptionClass) {
+ this.from = from_raw;
+ this.to = to_raw;
+ this.handler = handler_raw;
+ this.exceptionClass = exceptionClass;
+ }
+
+ public void writeToStream(DataOutputStream out) throws IOException {
+ out.writeShort(from);
+ out.writeShort(to);
+ out.writeShort(handler);
+ out.writeShort(class_index);
+ }
+
+ public String toString() {
+
+ String new_line_separator = DecompilerContext.getNewLineSeparator();
+
+ return "from: " + from + " to: " + to + " handler: " + handler + new_line_separator +
+ "from_instr: " + from_instr + " to_instr: " + to_instr + " handler_instr: " + handler_instr + new_line_separator +
+ "exceptionClass: " + exceptionClass + new_line_separator;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/ExceptionTable.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/ExceptionTable.java
new file mode 100644
index 000000000000..e828a7f9dc97
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/ExceptionTable.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code;
+
+import org.jetbrains.java.decompiler.code.interpreter.Util;
+import org.jetbrains.java.decompiler.struct.StructContext;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ExceptionTable {
+
+ private List<ExceptionHandler> handlers = new ArrayList<ExceptionHandler>();
+
+ public ExceptionTable() {
+ }
+
+ public ExceptionTable(List<ExceptionHandler> handlers) {
+ this.handlers = handlers;
+ }
+
+
+ public ExceptionHandler getHandlerByClass(StructContext context, int line, String valclass, boolean withany) {
+
+ ExceptionHandler res = null; // no handler found
+
+ for (ExceptionHandler handler : handlers) {
+ if (handler.from <= line && handler.to > line) {
+ String name = handler.exceptionClass;
+
+ if ((withany && name == null) || // any -> finally or synchronized handler
+ (name != null && Util.instanceOf(context, valclass, name))) {
+ res = handler;
+ break;
+ }
+ }
+ }
+
+ return res;
+ }
+
+ public List<ExceptionHandler> getHandlers() {
+ return handlers;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/FullInstructionSequence.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/FullInstructionSequence.java
new file mode 100644
index 000000000000..eb8f8192e29f
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/FullInstructionSequence.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code;
+
+import org.jetbrains.java.decompiler.util.VBStyleCollection;
+
+
+public class FullInstructionSequence extends InstructionSequence {
+
+ // *****************************************************************************
+ // constructors
+ // *****************************************************************************
+
+ public FullInstructionSequence(VBStyleCollection<Instruction, Integer> collinstr, ExceptionTable extable) {
+ this.collinstr = collinstr;
+ this.exceptionTable = extable;
+
+ // translate raw exception handlers to instr
+ for (ExceptionHandler handler : extable.getHandlers()) {
+ handler.from_instr = this.getPointerByAbsOffset(handler.from);
+ handler.to_instr = this.getPointerByAbsOffset(handler.to);
+ handler.handler_instr = this.getPointerByAbsOffset(handler.handler);
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/IfInstruction.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/IfInstruction.java
new file mode 100644
index 000000000000..1d4bf6c535bd
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/IfInstruction.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+/*
+ * opc_ifeq, opc_ifne, opc_iflt, opc_ifge, opc_ifgt, opc_ifle, opc_if_icmpeq, opc_if_icmpne, opc_if_icmplt,
+ * opc_if_icmpge, opc_if_icmpgt, opc_if_icmple, opc_if_acmpeq, opc_if_acmpne, opc_ifnull, opc_ifnonnull
+ */
+
+public class IfInstruction extends JumpInstruction {
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opcode);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/Instruction.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/Instruction.java
new file mode 100644
index 000000000000..d77f3b4f4ede
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/Instruction.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class Instruction implements CodeConstants {
+
+ // *****************************************************************************
+ // public fields
+ // *****************************************************************************
+
+ public int opcode;
+
+ public int group = CodeConstants.GROUP_GENERAL;
+
+ public boolean wide = false;
+
+ public int bytecode_version = BYTECODE_JAVA_LE_4;
+
+ // *****************************************************************************
+ // private fields
+ // *****************************************************************************
+
+ private int[] operands = null;
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public Instruction() {
+ }
+
+ public int length() {
+ return 1;
+ }
+
+ public int operandsCount() {
+ return (operands == null) ? 0 : operands.length;
+ }
+
+ public int getOperand(int index) {
+ return operands[index];
+ }
+
+ public Instruction clone() {
+ return ConstantsUtil.getInstructionInstance(opcode, wide, group, bytecode_version, operands == null ? null : operands.clone());
+ }
+
+ public String toString() {
+
+ String res = wide ? "@wide " : "";
+ res += "@" + ConstantsUtil.getName(opcode);
+
+ int len = operandsCount();
+ for (int i = 0; i < len; i++) {
+ int op = operands[i];
+ if (op < 0) {
+ res += " -" + Integer.toHexString(-op);
+ }
+ else {
+ res += " " + Integer.toHexString(op);
+ }
+ }
+
+ return res;
+ }
+
+ public boolean canFallthrough() {
+ return opcode != opc_goto && opcode != opc_goto_w && opcode != opc_ret &&
+ !(opcode >= opc_ireturn && opcode <= opc_return) && opcode != opc_athrow
+ && opcode != opc_jsr && opcode != opc_tableswitch && opcode != opc_lookupswitch;
+ }
+
+ public boolean equalsInstruction(Instruction instr) {
+ if (opcode != instr.opcode || wide != instr.wide
+ || operandsCount() != instr.operandsCount()) {
+ return false;
+ }
+
+ if (operands != null) {
+ for (int i = 0; i < operands.length; i++) {
+ if (operands[i] != instr.getOperand(i)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ // should be overwritten by subclasses
+ public void initInstruction(InstructionSequence seq) {
+ }
+
+ // should be overwritten by subclasses
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opcode);
+ }
+
+ // *****************************************************************************
+ // getter and setter methods
+ // *****************************************************************************
+
+ public int[] getOperands() {
+ return operands;
+ }
+
+ public void setOperands(int[] operands) {
+ this.operands = operands;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/InstructionSequence.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/InstructionSequence.java
new file mode 100644
index 000000000000..709a85da3952
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/InstructionSequence.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code;
+
+import org.jetbrains.java.decompiler.code.interpreter.Util;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.struct.StructContext;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import org.jetbrains.java.decompiler.util.VBStyleCollection;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+
+public abstract class InstructionSequence {
+
+ // *****************************************************************************
+ // private fields
+ // *****************************************************************************
+
+ protected VBStyleCollection<Instruction, Integer> collinstr = new VBStyleCollection<Instruction, Integer>();
+
+ protected int pointer = 0;
+
+ protected ExceptionTable exceptionTable = new ExceptionTable();
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ // to nbe overwritten
+ public InstructionSequence clone() {
+ return null;
+ }
+
+ public void clear() {
+ collinstr.clear();
+ pointer = 0;
+ exceptionTable = new ExceptionTable();
+ }
+
+ public void addInstruction(Instruction inst, int offset) {
+ collinstr.addWithKey(inst, offset);
+ }
+
+ public void addInstruction(int index, Instruction inst, int offset) {
+ collinstr.addWithKeyAndIndex(index, inst, offset);
+ }
+
+ public void addSequence(InstructionSequence seq) {
+ for (int i = 0; i < seq.length(); i++) {
+ addInstruction(seq.getInstr(i), -1); // TODO: any sensible value possible?
+ }
+ }
+
+ public void removeInstruction(int index) {
+ collinstr.remove(index);
+ }
+
+ public Instruction getCurrentInstr() {
+ return collinstr.get(pointer);
+ }
+
+ public Instruction getInstr(int index) {
+ return collinstr.get(index);
+ }
+
+ public Instruction getLastInstr() {
+ return collinstr.getLast();
+ }
+
+ public int getCurrentOffset() {
+ return collinstr.getKey(pointer).intValue();
+ }
+
+public int getOffset(int index) {
+ return collinstr.getKey(index).intValue();
+ }
+
+ public int getPointerByAbsOffset(int offset) {
+ Integer absoffset = new Integer(offset);
+ if (collinstr.containsKey(absoffset)) {
+ return collinstr.getIndexByKey(absoffset);
+ }
+ else {
+ return -1;
+ }
+ }
+
+ public int getPointerByRelOffset(int offset) {
+ Integer absoffset = new Integer(collinstr.getKey(pointer).intValue() + offset);
+ if (collinstr.containsKey(absoffset)) {
+ return collinstr.getIndexByKey(absoffset);
+ }
+ else {
+ return -1;
+ }
+ }
+
+ public void setPointerByAbsOffset(int offset) {
+ Integer absoffset = new Integer(collinstr.getKey(pointer).intValue() + offset);
+ if (collinstr.containsKey(absoffset)) {
+ pointer = collinstr.getIndexByKey(absoffset);
+ }
+ }
+
+ public int length() {
+ return collinstr.size();
+ }
+
+ public boolean isEmpty() {
+ return collinstr.isEmpty();
+ }
+
+ public void addToPointer(int diff) {
+ this.pointer += diff;
+ }
+
+ public String toString() {
+ return toString(0);
+ }
+
+ public String toString(int indent) {
+
+ String new_line_separator = DecompilerContext.getNewLineSeparator();
+
+ StringBuilder buf = new StringBuilder();
+
+ for (int i = 0; i < collinstr.size(); i++) {
+ buf.append(InterpreterUtil.getIndentString(indent));
+ buf.append(collinstr.getKey(i).intValue());
+ buf.append(": ");
+ buf.append(collinstr.get(i).toString());
+ buf.append(new_line_separator);
+ }
+
+ return buf.toString();
+ }
+
+ public void writeCodeToStream(DataOutputStream out) throws IOException {
+
+ for (int i = 0; i < collinstr.size(); i++) {
+ collinstr.get(i).writeToStream(out, collinstr.getKey(i).intValue());
+ }
+ }
+
+ public void writeExceptionsToStream(DataOutputStream out) throws IOException {
+
+ List<ExceptionHandler> handlers = exceptionTable.getHandlers();
+
+ out.writeShort(handlers.size());
+ for (int i = 0; i < handlers.size(); i++) {
+ handlers.get(i).writeToStream(out);
+ }
+ }
+
+ public void sortHandlers(final StructContext context) {
+
+ Collections.sort(exceptionTable.getHandlers(), new Comparator<ExceptionHandler>() {
+
+ public int compare(ExceptionHandler handler0, ExceptionHandler handler1) {
+
+ if (handler0.to == handler1.to) {
+ if (handler0.exceptionClass == null) {
+ return 1;
+ }
+ else {
+ if (handler1.exceptionClass == null) {
+ return -1;
+ }
+ else if (handler0.exceptionClass.equals(handler1.exceptionClass)) {
+ return (handler0.from > handler1.from) ? -1 : 1; // invalid code
+ }
+ else {
+ if (Util.instanceOf(context, handler0.exceptionClass, handler1.exceptionClass)) {
+ return -1;
+ }
+ else {
+ return 1;
+ }
+ }
+ }
+ }
+ else {
+ return (handler0.to > handler1.to) ? 1 : -1;
+ }
+ }
+ });
+ }
+
+
+ // *****************************************************************************
+ // getter and setter methods
+ // *****************************************************************************
+
+ public int getPointer() {
+ return pointer;
+ }
+
+ public void setPointer(int pointer) {
+ this.pointer = pointer;
+ }
+
+ public ExceptionTable getExceptionTable() {
+ return exceptionTable;
+ }
+
+ public void setExceptionTable(ExceptionTable exceptionTable) {
+ this.exceptionTable = exceptionTable;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/JumpInstruction.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/JumpInstruction.java
new file mode 100644
index 000000000000..44f4ff9a9b11
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/JumpInstruction.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code;
+
+/*
+ * opc_ifeq, opc_ifne, opc_iflt, opc_ifge, opc_ifgt, opc_ifle, opc_if_icmpeq, opc_if_icmpne, opc_if_icmplt,
+ * opc_if_icmpge, opc_if_icmpgt, opc_if_icmple, opc_if_acmpeq, opc_if_acmpne, opc_ifnull, opc_ifnonnull
+ * opc_goto, opc_jsr, opc_goto_w, opc_jsr_w
+ */
+
+
+public class JumpInstruction extends Instruction {
+
+ public int destination;
+
+ public JumpInstruction() {
+ }
+
+ public void initInstruction(InstructionSequence seq) {
+ destination = seq.getPointerByRelOffset(this.getOperand(0));
+ }
+
+ public JumpInstruction clone() {
+ JumpInstruction newinstr = (JumpInstruction)super.clone();
+
+ newinstr.destination = destination;
+ return newinstr;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/SimpleInstructionSequence.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/SimpleInstructionSequence.java
new file mode 100644
index 000000000000..bcc3c4a8da96
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/SimpleInstructionSequence.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code;
+
+import org.jetbrains.java.decompiler.util.VBStyleCollection;
+
+public class SimpleInstructionSequence extends InstructionSequence {
+
+ public SimpleInstructionSequence() {
+ }
+
+ public SimpleInstructionSequence(VBStyleCollection<Instruction, Integer> collinstr) {
+ this.collinstr = collinstr;
+ }
+
+ public SimpleInstructionSequence clone() {
+ SimpleInstructionSequence newseq = new SimpleInstructionSequence(collinstr.clone());
+ newseq.setPointer(this.getPointer());
+
+ return newseq;
+ }
+
+ public void removeInstruction(int index) {
+ collinstr.remove(index);
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/SwitchInstruction.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/SwitchInstruction.java
new file mode 100644
index 000000000000..6aa6a7f7eb34
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/SwitchInstruction.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code;
+
+/*
+ * opc_tableswitch, lookupswitch
+ */
+
+public class SwitchInstruction extends Instruction {
+
+ private int[] destinations;
+
+ private int[] values;
+
+ private int defaultdest;
+
+ public SwitchInstruction() {
+ }
+
+
+ public void initInstruction(InstructionSequence seq) {
+
+ int pref = (opcode == CodeConstants.opc_tableswitch ? 3 : 2);
+ int len = this.getOperands().length - pref;
+ defaultdest = seq.getPointerByRelOffset(this.getOperand(0));
+
+ int low = 0;
+
+ if (opcode == CodeConstants.opc_lookupswitch) {
+ len /= 2;
+ }
+ else {
+ low = this.getOperand(1);
+ }
+
+ destinations = new int[len];
+ values = new int[len];
+
+ for (int i = 0, k = 0; i < len; i++, k++) {
+ if (opcode == CodeConstants.opc_lookupswitch) {
+ values[i] = this.getOperand(pref + k);
+ k++;
+ }
+ else {
+ values[i] = low + k;
+ }
+ destinations[i] = seq.getPointerByRelOffset(this.getOperand(pref + k));
+ }
+ }
+
+ public SwitchInstruction clone() {
+ SwitchInstruction newinstr = (SwitchInstruction)super.clone();
+
+ newinstr.defaultdest = defaultdest;
+ newinstr.destinations = destinations.clone();
+ newinstr.values = values.clone();
+
+ return newinstr;
+ }
+
+ public int[] getDestinations() {
+ return destinations;
+ }
+
+ public void setDestinations(int[] destinations) {
+ this.destinations = destinations;
+ }
+
+ public int getDefaultdest() {
+ return defaultdest;
+ }
+
+ public void setDefaultdest(int defaultdest) {
+ this.defaultdest = defaultdest;
+ }
+
+ public int[] getValues() {
+ return values;
+ }
+
+ public void setValues(int[] values) {
+ this.values = values;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/cfg/BasicBlock.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/cfg/BasicBlock.java
new file mode 100644
index 000000000000..61b0a63fd4da
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/cfg/BasicBlock.java
@@ -0,0 +1,266 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.cfg;
+
+import org.jetbrains.java.decompiler.code.Instruction;
+import org.jetbrains.java.decompiler.code.InstructionSequence;
+import org.jetbrains.java.decompiler.code.SimpleInstructionSequence;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.modules.decompiler.decompose.IGraphNode;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class BasicBlock implements IGraphNode {
+
+ // *****************************************************************************
+ // public fields
+ // *****************************************************************************
+
+ public int id = 0;
+
+ public int mark = 0;
+
+ // *****************************************************************************
+ // private fields
+ // *****************************************************************************
+
+ private InstructionSequence seq = new SimpleInstructionSequence();
+
+ private List<BasicBlock> preds = new ArrayList<BasicBlock>();
+
+ private List<BasicBlock> succs = new ArrayList<BasicBlock>();
+
+ private List<Integer> instrOldOffsets = new ArrayList<Integer>();
+
+ private List<BasicBlock> predExceptions = new ArrayList<BasicBlock>();
+
+ private List<BasicBlock> succExceptions = new ArrayList<BasicBlock>();
+
+
+ public BasicBlock() {
+ }
+
+ public BasicBlock(int id) {
+ this.id = id;
+ }
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public Object clone() {
+
+ BasicBlock block = new BasicBlock();
+ block.id = id;
+ block.setSeq(seq.clone());
+ block.setInstrOldOffsets(new ArrayList<Integer>(instrOldOffsets));
+
+ return block;
+ }
+
+ public void free() {
+ preds.clear();
+ succs.clear();
+ instrOldOffsets.clear();
+ succExceptions.clear();
+ seq = new SimpleInstructionSequence();
+ }
+
+ public Instruction getInstruction(int index) {
+ return seq.getInstr(index);
+ }
+
+ public Instruction getLastInstruction() {
+ if (seq.isEmpty()) {
+ return null;
+ }
+ else {
+ return seq.getLastInstr();
+ }
+ }
+
+ public int size() {
+ return seq.length();
+ }
+
+ public void addPredecessor(BasicBlock block) {
+ preds.add(block);
+ }
+
+ public void removePredecessor(BasicBlock block) {
+ while (preds.remove(block)) ;
+ }
+
+ public void addSuccessor(BasicBlock block) {
+ succs.add(block);
+ block.addPredecessor(this);
+ }
+
+ public void removeSuccessor(BasicBlock block) {
+ while (succs.remove(block)) ;
+ block.removePredecessor(this);
+ }
+
+ // FIXME: unify block comparisons: id or direkt equality
+ public void replaceSuccessor(BasicBlock oldBlock, BasicBlock newBlock) {
+ for (int i = 0; i < succs.size(); i++) {
+ if (succs.get(i).id == oldBlock.id) {
+ succs.set(i, newBlock);
+ oldBlock.removePredecessor(this);
+ newBlock.addPredecessor(this);
+ }
+ }
+
+ for (int i = 0; i < succExceptions.size(); i++) {
+ if (succExceptions.get(i).id == oldBlock.id) {
+ succExceptions.set(i, newBlock);
+ oldBlock.removePredecessorException(this);
+ newBlock.addPredecessorException(this);
+ }
+ }
+ }
+
+ public void addPredecessorException(BasicBlock block) {
+ predExceptions.add(block);
+ }
+
+ public void removePredecessorException(BasicBlock block) {
+ while (predExceptions.remove(block)) ;
+ }
+
+ public void addSuccessorException(BasicBlock block) {
+ if (!succExceptions.contains(block)) {
+ succExceptions.add(block);
+ block.addPredecessorException(this);
+ }
+ }
+
+ public void removeSuccessorException(BasicBlock block) {
+ while (succExceptions.remove(block)) ;
+ block.removePredecessorException(this);
+ }
+
+ public String toString() {
+ return toString(0);
+ }
+
+ public String toString(int indent) {
+
+ String new_line_separator = DecompilerContext.getNewLineSeparator();
+
+ return id + ":" + new_line_separator + seq.toString(indent);
+ }
+
+ public String toStringOldIndices() {
+
+ String new_line_separator = DecompilerContext.getNewLineSeparator();
+
+ StringBuilder buf = new StringBuilder();
+
+ for (int i = 0; i < seq.length(); i++) {
+ if (i < instrOldOffsets.size()) {
+ buf.append(instrOldOffsets.get(i));
+ }
+ else {
+ buf.append("-1");
+ }
+ buf.append(": ");
+ buf.append(seq.getInstr(i).toString());
+ buf.append(new_line_separator);
+ }
+
+ return buf.toString();
+ }
+
+ public boolean isSuccessor(BasicBlock block) {
+ for (BasicBlock succ : succs) {
+ if (succ.id == block.id) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean isPredecessor(BasicBlock block) {
+ for (int i = 0; i < preds.size(); i++) {
+ if (preds.get(i).id == block.id) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // *****************************************************************************
+ // getter and setter methods
+ // *****************************************************************************
+
+ public List<Integer> getInstrOldOffsets() {
+ return instrOldOffsets;
+ }
+
+ public void setInstrOldOffsets(List<Integer> instrInds) {
+ this.instrOldOffsets = instrInds;
+ }
+
+ public List<? extends IGraphNode> getPredecessors() {
+ List<BasicBlock> lst = new ArrayList<BasicBlock>(preds);
+ lst.addAll(predExceptions);
+ return lst;
+ }
+
+ public List<BasicBlock> getPreds() {
+ return preds;
+ }
+
+ public void setPreds(List<BasicBlock> preds) {
+ this.preds = preds;
+ }
+
+ public InstructionSequence getSeq() {
+ return seq;
+ }
+
+ public void setSeq(InstructionSequence seq) {
+ this.seq = seq;
+ }
+
+ public List<BasicBlock> getSuccs() {
+ return succs;
+ }
+
+ public void setSuccs(List<BasicBlock> succs) {
+ this.succs = succs;
+ }
+
+
+ public List<BasicBlock> getSuccExceptions() {
+ return succExceptions;
+ }
+
+
+ public void setSuccExceptions(List<BasicBlock> succExceptions) {
+ this.succExceptions = succExceptions;
+ }
+
+ public List<BasicBlock> getPredExceptions() {
+ return predExceptions;
+ }
+
+ public void setPredExceptions(List<BasicBlock> predExceptions) {
+ this.predExceptions = predExceptions;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/cfg/ControlFlowGraph.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/cfg/ControlFlowGraph.java
new file mode 100644
index 000000000000..44c58f04e196
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/cfg/ControlFlowGraph.java
@@ -0,0 +1,884 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.cfg;
+
+import org.jetbrains.java.decompiler.code.*;
+import org.jetbrains.java.decompiler.code.interpreter.InstructionImpact;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.modules.code.DeadCodeHelper;
+import org.jetbrains.java.decompiler.struct.StructMethod;
+import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
+import org.jetbrains.java.decompiler.struct.gen.DataPoint;
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+import org.jetbrains.java.decompiler.util.ListStack;
+import org.jetbrains.java.decompiler.util.VBStyleCollection;
+
+import java.util.*;
+import java.util.Map.Entry;
+
+public class ControlFlowGraph implements CodeConstants {
+
+ public int last_id = 0;
+
+ // *****************************************************************************
+ // private fields
+ // *****************************************************************************
+
+ private VBStyleCollection<BasicBlock, Integer> blocks;
+
+ private BasicBlock first;
+
+ private BasicBlock last;
+
+ private List<ExceptionRangeCFG> exceptions;
+
+ private Map<BasicBlock, BasicBlock> subroutines;
+
+ private Set<BasicBlock> finallyExits = new HashSet<BasicBlock>();
+
+ // *****************************************************************************
+ // constructors
+ // *****************************************************************************
+
+ public ControlFlowGraph(InstructionSequence seq) {
+ buildBlocks(seq);
+ }
+
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public void free() {
+
+ for (BasicBlock block : blocks) {
+ block.free();
+ }
+
+ blocks.clear();
+ first = null;
+ last = null;
+ exceptions.clear();
+ finallyExits.clear();
+ }
+
+ public void removeMarkers() {
+ for (BasicBlock block : blocks) {
+ block.mark = 0;
+ }
+ }
+
+ public String toString() {
+
+ String new_line_separator = DecompilerContext.getNewLineSeparator();
+
+ StringBuilder buf = new StringBuilder();
+
+ for (BasicBlock block : blocks) {
+ buf.append("----- Block ").append(block.id).append(" -----").append(new_line_separator);
+ buf.append(block.toString());
+ buf.append("----- Edges -----").append(new_line_separator);
+
+ List<BasicBlock> suc = block.getSuccs();
+ for (int j = 0; j < suc.size(); j++) {
+ buf.append(">>>>>>>>(regular) Block ").append(suc.get(j).id).append(new_line_separator);
+ }
+ suc = block.getSuccExceptions();
+ for (int j = 0; j < suc.size(); j++) {
+ BasicBlock handler = suc.get(j);
+ ExceptionRangeCFG range = getExceptionRange(handler, block);
+
+ if (range == null) {
+ buf.append(">>>>>>>>(exception) Block ").append(handler.id).append("\t").append("ERROR: range not found!")
+ .append(new_line_separator);
+ }
+ else {
+ List<String> exceptionTypes = range.getExceptionTypes();
+ if (exceptionTypes == null) {
+ buf.append(">>>>>>>>(exception) Block ").append(handler.id).append("\t").append("NULL").append(new_line_separator);
+ }
+ else {
+ for (String exceptionType : exceptionTypes) {
+ buf.append(">>>>>>>>(exception) Block ").append(handler.id).append("\t").append(exceptionType).append(new_line_separator);
+ }
+ }
+ }
+ }
+ buf.append("----- ----- -----").append(new_line_separator);
+ }
+
+ return buf.toString();
+ }
+
+ public void inlineJsr(StructMethod mt) {
+ processJsr();
+ removeJsr(mt);
+
+ removeMarkers();
+
+ DeadCodeHelper.removeEmptyBlocks(this);
+ }
+
+ public void removeBlock(BasicBlock block) {
+
+ while (block.getSuccs().size() > 0) {
+ block.removeSuccessor(block.getSuccs().get(0));
+ }
+
+ while (block.getSuccExceptions().size() > 0) {
+ block.removeSuccessorException(block.getSuccExceptions().get(0));
+ }
+
+ while (block.getPreds().size() > 0) {
+ block.getPreds().get(0).removeSuccessor(block);
+ }
+
+ while (block.getPredExceptions().size() > 0) {
+ block.getPredExceptions().get(0).removeSuccessorException(block);
+ }
+
+ last.removePredecessor(block);
+
+ blocks.removeWithKey(block.id);
+
+ for (int i = exceptions.size() - 1; i >= 0; i--) {
+ ExceptionRangeCFG range = exceptions.get(i);
+ if (range.getHandler() == block) {
+ exceptions.remove(i);
+ }
+ else {
+ List<BasicBlock> lstRange = range.getProtectedRange();
+ lstRange.remove(block);
+
+ if (lstRange.isEmpty()) {
+ exceptions.remove(i);
+ }
+ }
+ }
+
+ Iterator<Entry<BasicBlock, BasicBlock>> it = subroutines.entrySet().iterator();
+ while (it.hasNext()) {
+ Entry<BasicBlock, BasicBlock> ent = it.next();
+ if (ent.getKey() == block || ent.getValue() == block) {
+ it.remove();
+ }
+ }
+ }
+
+ public ExceptionRangeCFG getExceptionRange(BasicBlock handler, BasicBlock block) {
+
+ //List<ExceptionRangeCFG> ranges = new ArrayList<ExceptionRangeCFG>();
+
+ for (int i = exceptions.size() - 1; i >= 0; i--) {
+ ExceptionRangeCFG range = exceptions.get(i);
+ if (range.getHandler() == handler && range.getProtectedRange().contains(block)) {
+ return range;
+ //ranges.add(range);
+ }
+ }
+
+ return null;
+ //return ranges.isEmpty() ? null : ranges;
+ }
+
+ // public String getExceptionsUniqueString(BasicBlock handler, BasicBlock block) {
+ //
+ // List<ExceptionRangeCFG> ranges = getExceptionRange(handler, block);
+ //
+ // if(ranges == null) {
+ // return null;
+ // } else {
+ // Set<String> setExceptionStrings = new HashSet<String>();
+ // for(ExceptionRangeCFG range : ranges) {
+ // setExceptionStrings.add(range.getExceptionType());
+ // }
+ //
+ // String ret = "";
+ // for(String exception : setExceptionStrings) {
+ // ret += exception;
+ // }
+ //
+ // return ret;
+ // }
+ // }
+
+
+ // *****************************************************************************
+ // private methods
+ // *****************************************************************************
+
+ private void buildBlocks(InstructionSequence instrseq) {
+
+ short[] states = findStartInstructions(instrseq);
+
+ Map<Integer, BasicBlock> mapInstrBlocks = new HashMap<Integer, BasicBlock>();
+ VBStyleCollection<BasicBlock, Integer> colBlocks = createBasicBlocks(states, instrseq, mapInstrBlocks);
+
+ blocks = colBlocks;
+
+ connectBlocks(colBlocks, mapInstrBlocks);
+
+ setExceptionEdges(instrseq, mapInstrBlocks);
+
+ setSubroutineEdges();
+
+ setFirstAndLastBlocks();
+ }
+
+ private static short[] findStartInstructions(InstructionSequence seq) {
+
+ int len = seq.length();
+ short[] inststates = new short[len];
+
+ Set<Integer> excSet = new HashSet<Integer>();
+
+ for (ExceptionHandler handler : seq.getExceptionTable().getHandlers()) {
+ excSet.add(handler.from_instr);
+ excSet.add(handler.to_instr);
+ excSet.add(handler.handler_instr);
+ }
+
+
+ for (int i = 0; i < len; i++) {
+
+ // exception blocks
+ if (excSet.contains(new Integer(i))) {
+ inststates[i] = 1;
+ }
+
+ Instruction instr = seq.getInstr(i);
+ switch (instr.group) {
+ case GROUP_JUMP:
+ inststates[((JumpInstruction)instr).destination] = 1;
+ case GROUP_RETURN:
+ if (i + 1 < len) {
+ inststates[i + 1] = 1;
+ }
+ break;
+ case GROUP_SWITCH:
+ SwitchInstruction swinstr = (SwitchInstruction)instr;
+ int[] dests = swinstr.getDestinations();
+ for (int j = dests.length - 1; j >= 0; j--) {
+ inststates[dests[j]] = 1;
+ }
+ inststates[swinstr.getDefaultdest()] = 1;
+ if (i + 1 < len) {
+ inststates[i + 1] = 1;
+ }
+ }
+ }
+
+ // first instruction
+ inststates[0] = 1;
+
+ return inststates;
+ }
+
+
+ private VBStyleCollection<BasicBlock, Integer> createBasicBlocks(short[] startblock,
+ InstructionSequence instrseq,
+ Map<Integer, BasicBlock> mapInstrBlocks) {
+
+ VBStyleCollection<BasicBlock, Integer> col = new VBStyleCollection<BasicBlock, Integer>();
+
+ InstructionSequence currseq = null;
+ ArrayList<Integer> lstOffs = null;
+
+ int len = startblock.length;
+ short counter = 0;
+ int blockoffset = 0;
+
+ BasicBlock currentBlock = null;
+ for (int i = 0; i < len; i++) {
+
+ if (startblock[i] == 1) {
+ currentBlock = new BasicBlock();
+ currentBlock.id = ++counter;
+
+ currseq = new SimpleInstructionSequence();
+ lstOffs = new ArrayList<Integer>();
+
+ currentBlock.setSeq(currseq);
+ currentBlock.setInstrOldOffsets(lstOffs);
+ col.addWithKey(currentBlock, currentBlock.id);
+
+ blockoffset = instrseq.getOffset(i);
+ }
+
+ startblock[i] = counter;
+ mapInstrBlocks.put(i, currentBlock);
+
+ currseq.addInstruction(instrseq.getInstr(i), instrseq.getOffset(i) - blockoffset);
+ lstOffs.add(instrseq.getOffset(i));
+ }
+
+ last_id = counter;
+
+ return col;
+ }
+
+
+ private static void connectBlocks(List<BasicBlock> lstbb, Map<Integer, BasicBlock> mapInstrBlocks) {
+
+ for (int i = 0; i < lstbb.size(); i++) {
+
+ BasicBlock block = lstbb.get(i);
+ Instruction instr = block.getLastInstruction();
+
+ boolean fallthrough = instr.canFallthrough();
+ BasicBlock bTemp;
+
+ switch (instr.group) {
+ case GROUP_JUMP:
+ int dest = ((JumpInstruction)instr).destination;
+ bTemp = mapInstrBlocks.get(dest);
+ block.addSuccessor(bTemp);
+
+ break;
+ case GROUP_SWITCH:
+ SwitchInstruction sinstr = (SwitchInstruction)instr;
+ int[] dests = sinstr.getDestinations();
+
+ bTemp = mapInstrBlocks.get(((SwitchInstruction)instr).getDefaultdest());
+ block.addSuccessor(bTemp);
+ for (int j = 0; j < dests.length; j++) {
+ bTemp = mapInstrBlocks.get(dests[j]);
+ block.addSuccessor(bTemp);
+ }
+ }
+
+ if (fallthrough && i < lstbb.size() - 1) {
+ BasicBlock defaultBlock = lstbb.get(i + 1);
+ block.addSuccessor(defaultBlock);
+ }
+ }
+ }
+
+ private void setExceptionEdges(InstructionSequence instrseq, Map<Integer, BasicBlock> instrBlocks) {
+
+ exceptions = new ArrayList<ExceptionRangeCFG>();
+
+ Map<String, ExceptionRangeCFG> mapRanges = new HashMap<String, ExceptionRangeCFG>();
+
+ for (ExceptionHandler handler : instrseq.getExceptionTable().getHandlers()) {
+
+ BasicBlock from = instrBlocks.get(handler.from_instr);
+ BasicBlock to = instrBlocks.get(handler.to_instr);
+ BasicBlock handle = instrBlocks.get(handler.handler_instr);
+
+ String key = from.id + ":" + to.id + ":" + handle.id;
+
+ if (mapRanges.containsKey(key)) {
+ ExceptionRangeCFG range = mapRanges.get(key);
+ range.addExceptionType(handler.exceptionClass);
+ }
+ else {
+
+ List<BasicBlock> protectedRange = new ArrayList<BasicBlock>();
+ for (int j = from.id; j < to.id; j++) {
+ BasicBlock block = blocks.getWithKey(j);
+ protectedRange.add(block);
+ block.addSuccessorException(handle);
+ }
+
+ ExceptionRangeCFG range = new ExceptionRangeCFG(protectedRange, handle, handler.exceptionClass == null
+ ? null
+ : Arrays.asList(handler.exceptionClass));
+ mapRanges.put(key, range);
+
+ exceptions.add(range);
+ }
+ }
+ }
+
+ private void setSubroutineEdges() {
+
+ final Map<BasicBlock, BasicBlock> subroutines = new HashMap<BasicBlock, BasicBlock>();
+
+ for (BasicBlock block : blocks) {
+
+ if (block.getSeq().getLastInstr().opcode == CodeConstants.opc_jsr) {
+
+ LinkedList<BasicBlock> stack = new LinkedList<BasicBlock>();
+ LinkedList<LinkedList<BasicBlock>> stackJsrStacks = new LinkedList<LinkedList<BasicBlock>>();
+
+ Set<BasicBlock> setVisited = new HashSet<BasicBlock>();
+
+ stack.add(block);
+ stackJsrStacks.add(new LinkedList<BasicBlock>());
+
+ while (!stack.isEmpty()) {
+
+ BasicBlock node = stack.removeFirst();
+ LinkedList<BasicBlock> jsrstack = stackJsrStacks.removeFirst();
+
+ setVisited.add(node);
+
+ switch (node.getSeq().getLastInstr().opcode) {
+ case CodeConstants.opc_jsr:
+ jsrstack.add(node);
+ break;
+ case CodeConstants.opc_ret:
+ BasicBlock enter = jsrstack.getLast();
+ BasicBlock exit = blocks.getWithKey(enter.id + 1); // FIXME: find successor in a better way
+
+ if (exit != null) {
+ if (!node.isSuccessor(exit)) {
+ node.addSuccessor(exit);
+ }
+ jsrstack.removeLast();
+ subroutines.put(enter, exit);
+ }
+ else {
+ throw new RuntimeException("ERROR: last instruction jsr");
+ }
+ }
+
+ if (!jsrstack.isEmpty()) {
+ for (BasicBlock succ : node.getSuccs()) {
+ if (!setVisited.contains(succ)) {
+ stack.add(succ);
+ stackJsrStacks.add(new LinkedList<BasicBlock>(jsrstack));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ this.subroutines = subroutines;
+ }
+
+ private void processJsr() {
+ while (true) {
+ if (processJsrRanges() == 0) break;
+ }
+ }
+
+ private static class JsrRecord {
+ private final BasicBlock jsr;
+ private final Set<BasicBlock> range;
+ private final BasicBlock ret;
+
+ private JsrRecord(BasicBlock jsr, Set<BasicBlock> range, BasicBlock ret) {
+ this.jsr = jsr;
+ this.range = range;
+ this.ret = ret;
+ }
+ }
+
+ private int processJsrRanges() {
+
+ List<JsrRecord> lstJsrAll = new ArrayList<JsrRecord>();
+
+ // get all jsr ranges
+ for (Entry<BasicBlock, BasicBlock> ent : subroutines.entrySet()) {
+ BasicBlock jsr = ent.getKey();
+ BasicBlock ret = ent.getValue();
+
+ lstJsrAll.add(new JsrRecord(jsr, getJsrRange(jsr, ret), ret));
+ }
+
+ // sort ranges
+ // FIXME: better sort order
+ List<JsrRecord> lstJsr = new ArrayList<JsrRecord>();
+ for (JsrRecord arr : lstJsrAll) {
+ int i = 0;
+ for (; i < lstJsr.size(); i++) {
+ JsrRecord arrJsr = lstJsr.get(i);
+ if (arrJsr.range.contains(arr.jsr)) {
+ break;
+ }
+ }
+ lstJsr.add(i, arr);
+ }
+
+ // find the first intersection
+ for (int i = 0; i < lstJsr.size(); i++) {
+ JsrRecord arr = lstJsr.get(i);
+ Set<BasicBlock> set = arr.range;
+
+ for (int j = i + 1; j < lstJsr.size(); j++) {
+ JsrRecord arr1 = lstJsr.get(j);
+ Set<BasicBlock> set1 = arr1.range;
+
+ if (!set.contains(arr1.jsr) && !set1.contains(arr.jsr)) { // rang 0 doesn't contain entry 1 and vice versa
+ Set<BasicBlock> setc = new HashSet<BasicBlock>(set);
+ setc.retainAll(set1);
+
+ if (!setc.isEmpty()) {
+ splitJsrRange(arr.jsr, arr.ret, setc);
+ return 1;
+ }
+ }
+ }
+ }
+
+ return 0;
+ }
+
+ private Set<BasicBlock> getJsrRange(BasicBlock jsr, BasicBlock ret) {
+
+ Set<BasicBlock> blocks = new HashSet<BasicBlock>();
+
+ List<BasicBlock> lstNodes = new LinkedList<BasicBlock>();
+ lstNodes.add(jsr);
+
+ BasicBlock dom = jsr.getSuccs().get(0);
+
+ while (!lstNodes.isEmpty()) {
+
+ BasicBlock node = lstNodes.remove(0);
+
+ for (int j = 0; j < 2; j++) {
+ List<BasicBlock> lst;
+ if (j == 0) {
+ if (node.getLastInstruction().opcode == CodeConstants.opc_ret) {
+ if (node.getSuccs().contains(ret)) {
+ continue;
+ }
+ }
+ lst = node.getSuccs();
+ }
+ else {
+ if (node == jsr) {
+ continue;
+ }
+ lst = node.getSuccExceptions();
+ }
+
+ CHILD:
+ for (int i = lst.size() - 1; i >= 0; i--) {
+
+ BasicBlock child = lst.get(i);
+ if (!blocks.contains(child)) {
+
+ if (node != jsr) {
+ for (int k = 0; k < child.getPreds().size(); k++) {
+ if (!DeadCodeHelper.isDominator(this, child.getPreds().get(k), dom)) {
+ continue CHILD;
+ }
+ }
+
+ for (int k = 0; k < child.getPredExceptions().size(); k++) {
+ if (!DeadCodeHelper.isDominator(this, child.getPredExceptions().get(k), dom)) {
+ continue CHILD;
+ }
+ }
+ }
+
+ // last block is a dummy one
+ if (child != last) {
+ blocks.add(child);
+ }
+
+ lstNodes.add(child);
+ }
+ }
+ }
+ }
+
+ return blocks;
+ }
+
+ private void splitJsrRange(BasicBlock jsr, BasicBlock ret, Set<BasicBlock> common_blocks) {
+
+ List<BasicBlock> lstNodes = new LinkedList<BasicBlock>();
+ Map<Integer, BasicBlock> mapNewNodes = new HashMap<Integer, BasicBlock>();
+
+ lstNodes.add(jsr);
+ mapNewNodes.put(jsr.id, jsr);
+
+ while (!lstNodes.isEmpty()) {
+
+ BasicBlock node = lstNodes.remove(0);
+
+ for (int j = 0; j < 2; j++) {
+ List<BasicBlock> lst;
+ if (j == 0) {
+ if (node.getLastInstruction().opcode == CodeConstants.opc_ret) {
+ if (node.getSuccs().contains(ret)) {
+ continue;
+ }
+ }
+ lst = node.getSuccs();
+ }
+ else {
+ if (node == jsr) {
+ continue;
+ }
+ lst = node.getSuccExceptions();
+ }
+
+
+ for (int i = lst.size() - 1; i >= 0; i--) {
+
+ BasicBlock child = lst.get(i);
+ Integer childid = child.id;
+
+ if (mapNewNodes.containsKey(childid)) {
+ node.replaceSuccessor(child, mapNewNodes.get(childid));
+ }
+ else if (common_blocks.contains(child)) {
+
+ // make a copy of the current block
+ BasicBlock copy = (BasicBlock)child.clone();
+ copy.id = ++last_id;
+ // copy all successors
+ if (copy.getLastInstruction().opcode == CodeConstants.opc_ret &&
+ child.getSuccs().contains(ret)) {
+ copy.addSuccessor(ret);
+ child.removeSuccessor(ret);
+ }
+ else {
+ for (int k = 0; k < child.getSuccs().size(); k++) {
+ copy.addSuccessor(child.getSuccs().get(k));
+ }
+ }
+ for (int k = 0; k < child.getSuccExceptions().size(); k++) {
+ copy.addSuccessorException(child.getSuccExceptions().get(k));
+ }
+
+ lstNodes.add(copy);
+ mapNewNodes.put(childid, copy);
+
+ if (last.getPreds().contains(child)) {
+ last.addPredecessor(copy);
+ }
+
+ node.replaceSuccessor(child, copy);
+ blocks.addWithKey(copy, copy.id);
+ }
+ else {
+ // stop at the first fixed node
+ //lstNodes.add(child);
+ mapNewNodes.put(childid, child);
+ }
+ }
+ }
+ }
+
+ // note: subroutines won't be copied!
+ splitJsrExceptionRanges(common_blocks, mapNewNodes);
+ }
+
+ private void splitJsrExceptionRanges(Set<BasicBlock> common_blocks, Map<Integer, BasicBlock> mapNewNodes) {
+
+ for (int i = exceptions.size() - 1; i >= 0; i--) {
+
+ ExceptionRangeCFG range = exceptions.get(i);
+ List<BasicBlock> lstRange = range.getProtectedRange();
+
+ HashSet<BasicBlock> setBoth = new HashSet<BasicBlock>(common_blocks);
+ setBoth.retainAll(lstRange);
+
+ if (setBoth.size() > 0) {
+ List<BasicBlock> lstNewRange;
+
+ if (setBoth.size() == lstRange.size()) {
+ lstNewRange = new ArrayList<BasicBlock>();
+ ExceptionRangeCFG newRange = new ExceptionRangeCFG(lstNewRange,
+ mapNewNodes.get(range.getHandler().id), range.getExceptionTypes());
+ exceptions.add(newRange);
+ }
+ else {
+ lstNewRange = lstRange;
+ }
+
+ for (BasicBlock block : setBoth) {
+ lstNewRange.add(mapNewNodes.get(block.id));
+ }
+ }
+ }
+ }
+
+ private void removeJsr(StructMethod mt) {
+ removeJsrInstructions(mt.getClassStruct().getPool(), first, DataPoint.getInitialDataPoint(mt));
+ }
+
+ private static void removeJsrInstructions(ConstantPool pool, BasicBlock block, DataPoint data) {
+
+ ListStack<VarType> stack = data.getStack();
+
+ InstructionSequence seq = block.getSeq();
+ for (int i = 0; i < seq.length(); i++) {
+ Instruction instr = seq.getInstr(i);
+
+ VarType var = null;
+ if (instr.opcode == CodeConstants.opc_astore || instr.opcode == CodeConstants.opc_pop) {
+ var = stack.getByOffset(-1);
+ }
+
+ InstructionImpact.stepTypes(data, instr, pool);
+
+ switch (instr.opcode) {
+ case CodeConstants.opc_jsr:
+ case CodeConstants.opc_ret:
+ seq.removeInstruction(i);
+ i--;
+ break;
+ case CodeConstants.opc_astore:
+ case CodeConstants.opc_pop:
+ if (var.type == CodeConstants.TYPE_ADDRESS) {
+ seq.removeInstruction(i);
+ i--;
+ }
+ }
+ }
+
+ block.mark = 1;
+
+ for (int i = 0; i < block.getSuccs().size(); i++) {
+ BasicBlock suc = block.getSuccs().get(i);
+ if (suc.mark != 1) {
+ removeJsrInstructions(pool, suc, data.copy());
+ }
+ }
+
+ for (int i = 0; i < block.getSuccExceptions().size(); i++) {
+ BasicBlock suc = block.getSuccExceptions().get(i);
+ if (suc.mark != 1) {
+
+ DataPoint point = new DataPoint();
+ point.setLocalVariables(new ArrayList<VarType>(data.getLocalVariables()));
+ point.getStack().push(new VarType(CodeConstants.TYPE_OBJECT, 0, null));
+
+ removeJsrInstructions(pool, suc, point);
+ }
+ }
+ }
+
+ private void setFirstAndLastBlocks() {
+
+ first = blocks.get(0);
+
+ last = new BasicBlock();
+ last.id = ++last_id;
+ last.setSeq(new SimpleInstructionSequence());
+
+ for (BasicBlock block : blocks) {
+ if (block.getSuccs().isEmpty()) {
+ last.addPredecessor(block);
+ }
+ }
+ }
+
+ public List<BasicBlock> getReversePostOrder() {
+
+ List<BasicBlock> res = new LinkedList<BasicBlock>();
+ addToReversePostOrderListIterative(first, res);
+
+ return res;
+ }
+
+ private static void addToReversePostOrderListIterative(BasicBlock root, List<BasicBlock> lst) {
+
+ LinkedList<BasicBlock> stackNode = new LinkedList<BasicBlock>();
+ LinkedList<Integer> stackIndex = new LinkedList<Integer>();
+
+ Set<BasicBlock> setVisited = new HashSet<BasicBlock>();
+
+ stackNode.add(root);
+ stackIndex.add(0);
+
+ while (!stackNode.isEmpty()) {
+
+ BasicBlock node = stackNode.getLast();
+ int index = stackIndex.removeLast();
+
+ setVisited.add(node);
+
+ List<BasicBlock> lstSuccs = new ArrayList<BasicBlock>(node.getSuccs());
+ lstSuccs.addAll(node.getSuccExceptions());
+
+ for (; index < lstSuccs.size(); index++) {
+ BasicBlock succ = lstSuccs.get(index);
+
+ if (!setVisited.contains(succ)) {
+ stackIndex.add(index + 1);
+
+ stackNode.add(succ);
+ stackIndex.add(0);
+
+ break;
+ }
+ }
+
+ if (index == lstSuccs.size()) {
+ lst.add(0, node);
+
+ stackNode.removeLast();
+ }
+ }
+ }
+
+
+ // *****************************************************************************
+ // getter and setter methods
+ // *****************************************************************************
+
+ public VBStyleCollection<BasicBlock, Integer> getBlocks() {
+ return blocks;
+ }
+
+ public void setBlocks(VBStyleCollection<BasicBlock, Integer> blocks) {
+ this.blocks = blocks;
+ }
+
+ public BasicBlock getFirst() {
+ return first;
+ }
+
+ public void setFirst(BasicBlock first) {
+ this.first = first;
+ }
+
+ public List<BasicBlock> getEndBlocks() {
+ return last.getPreds();
+ }
+
+ public List<ExceptionRangeCFG> getExceptions() {
+ return exceptions;
+ }
+
+ public void setExceptions(List<ExceptionRangeCFG> exceptions) {
+ this.exceptions = exceptions;
+ }
+
+ public BasicBlock getLast() {
+ return last;
+ }
+
+ public void setLast(BasicBlock last) {
+ this.last = last;
+ }
+
+ public Map<BasicBlock, BasicBlock> getSubroutines() {
+ return subroutines;
+ }
+
+ public void setSubroutines(Map<BasicBlock, BasicBlock> subroutines) {
+ this.subroutines = subroutines;
+ }
+
+ public Set<BasicBlock> getFinallyExits() {
+ return finallyExits;
+ }
+
+ public void setFinallyExits(HashSet<BasicBlock> finallyExits) {
+ this.finallyExits = finallyExits;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/cfg/ExceptionRangeCFG.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/cfg/ExceptionRangeCFG.java
new file mode 100644
index 000000000000..47e0e211424f
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/cfg/ExceptionRangeCFG.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.cfg;
+
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class ExceptionRangeCFG {
+
+ private List<BasicBlock> protectedRange = new ArrayList<BasicBlock>(); // FIXME: replace with set
+
+ private BasicBlock handler;
+
+ private List<String> exceptionTypes;
+
+ public ExceptionRangeCFG(List<BasicBlock> protectedRange, BasicBlock handler, List<String> exceptionType) {
+ this.protectedRange = protectedRange;
+ this.handler = handler;
+
+ if (exceptionType != null) {
+ this.exceptionTypes = new ArrayList<String>(exceptionType);
+ }
+ }
+
+ public boolean isCircular() {
+ return protectedRange.contains(handler);
+ }
+
+ public String toString() {
+
+ String new_line_separator = DecompilerContext.getNewLineSeparator();
+
+ StringBuilder buf = new StringBuilder();
+
+ buf.append("exceptionType:");
+ for (String exception_type : exceptionTypes) {
+ buf.append(" ").append(exception_type);
+ }
+ buf.append(new_line_separator);
+
+ buf.append("handler: ").append(handler.id).append(new_line_separator);
+ buf.append("range: ");
+ for (int i = 0; i < protectedRange.size(); i++) {
+ buf.append(protectedRange.get(i).id).append(" ");
+ }
+ buf.append(new_line_separator);
+
+ return buf.toString();
+ }
+
+ public BasicBlock getHandler() {
+ return handler;
+ }
+
+ public void setHandler(BasicBlock handler) {
+ this.handler = handler;
+ }
+
+ public List<BasicBlock> getProtectedRange() {
+ return protectedRange;
+ }
+
+ public void setProtectedRange(List<BasicBlock> protectedRange) {
+ this.protectedRange = protectedRange;
+ }
+
+ public List<String> getExceptionTypes() {
+ return this.exceptionTypes;
+ }
+
+ public void addExceptionType(String exceptionType) {
+
+ if (this.exceptionTypes == null) {
+ return;
+ }
+
+ if (exceptionType == null) {
+ this.exceptionTypes = null;
+ }
+ else {
+ this.exceptionTypes.add(exceptionType);
+ }
+ }
+
+ public String getUniqueExceptionsString() {
+
+ if (exceptionTypes == null) {
+ return null;
+ }
+
+ Set<String> setExceptionStrings = new HashSet<String>();
+
+ for (String exceptionType : exceptionTypes) { // normalize order
+ setExceptionStrings.add(exceptionType);
+ }
+
+ String ret = "";
+ for (String exception : setExceptionStrings) {
+ if (!ret.isEmpty()) {
+ ret += ":";
+ }
+ ret += exception;
+ }
+
+ return ret;
+ }
+
+
+ // public void setExceptionType(String exceptionType) {
+ // this.exceptionType = exceptionType;
+ // }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/interpreter/InstructionImpact.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/interpreter/InstructionImpact.java
new file mode 100644
index 000000000000..1af23a4cdb27
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/interpreter/InstructionImpact.java
@@ -0,0 +1,527 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.interpreter;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.code.Instruction;
+import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
+import org.jetbrains.java.decompiler.struct.consts.LinkConstant;
+import org.jetbrains.java.decompiler.struct.consts.PrimitiveConstant;
+import org.jetbrains.java.decompiler.struct.gen.DataPoint;
+import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+import org.jetbrains.java.decompiler.util.ListStack;
+
+public class InstructionImpact {
+
+ // {read, write}
+ private static final int[][][] stack_impact = {
+
+ {null, null}, // public final static int opc_nop = 0;
+ null, // public final static int opc_aconst_null = 1;
+ null, // public final static int opc_iconst_m1 = 2;
+ null, // public final static int opc_iconst_0 = 3;
+ null, // public final static int opc_iconst_1 = 4;
+ null, // public final static int opc_iconst_2 = 5;
+ null, // public final static int opc_iconst_3 = 6;
+ null, // public final static int opc_iconst_4 = 7;
+ null, // public final static int opc_iconst_5 = 8;
+ {null, {CodeConstants.TYPE_LONG}}, // public final static int opc_lconst_0 = 9;
+ {null, {CodeConstants.TYPE_LONG}}, // public final static int opc_lconst_1 = 10;
+ {null, {CodeConstants.TYPE_FLOAT}}, // public final static int opc_fconst_0 = 11;
+ {null, {CodeConstants.TYPE_FLOAT}}, // public final static int opc_fconst_1 = 12;
+ {null, {CodeConstants.TYPE_FLOAT}}, // public final static int opc_fconst_2 = 13;
+ {null, {CodeConstants.TYPE_DOUBLE}}, // public final static int opc_dconst_0 = 14;
+ {null, {CodeConstants.TYPE_DOUBLE}}, // public final static int opc_dconst_1 = 15;
+ {null, {CodeConstants.TYPE_INT}}, // public final static int opc_bipush = 16;
+ {null, {CodeConstants.TYPE_INT}}, // public final static int opc_sipush = 17;
+ null, // public final static int opc_ldc = 18;
+ null, // public final static int opc_ldc_w = 19;
+ null, // public final static int opc_ldc2_w = 20;
+ {null, {CodeConstants.TYPE_INT}}, // public final static int opc_iload = 21;
+ {null, {CodeConstants.TYPE_LONG}}, // public final static int opc_lload = 22;
+ {null, {CodeConstants.TYPE_FLOAT}}, // public final static int opc_fload = 23;
+ {null, {CodeConstants.TYPE_DOUBLE}}, // public final static int opc_dload = 24;
+ null, // public final static int opc_aload = 25;
+ null, // public final static int opc_iload_0 = 26;
+ null, // public final static int opc_iload_1 = 27;
+ null, // public final static int opc_iload_2 = 28;
+ null, // public final static int opc_iload_3 = 29;
+ null, // public final static int opc_lload_0 = 30;
+ null, // public final static int opc_lload_1 = 31;
+ null, // public final static int opc_lload_2 = 32;
+ null, // public final static int opc_lload_3 = 33;
+ null, // public final static int opc_fload_0 = 34;
+ null, // public final static int opc_fload_1 = 35;
+ null, // public final static int opc_fload_2 = 36;
+ null, // public final static int opc_fload_3 = 37;
+ null, // public final static int opc_dload_0 = 38;
+ null, // public final static int opc_dload_1 = 39;
+ null, // public final static int opc_dload_2 = 40;
+ null, // public final static int opc_dload_3 = 41;
+ null, // public final static int opc_aload_0 = 42;
+ null, // public final static int opc_aload_1 = 43;
+ null, // public final static int opc_aload_2 = 44;
+ null, // public final static int opc_aload_3 = 45;
+ {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_iaload = 46;
+ {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_LONG}},
+ // public final static int opc_laload = 47;
+ {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_FLOAT}},
+ // public final static int opc_faload = 48;
+ {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_DOUBLE}},
+ // public final static int opc_daload = 49;
+ null, // public final static int opc_aaload = 50;
+ {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_baload = 51;
+ {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_caload = 52;
+ {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_saload = 53;
+ {{CodeConstants.TYPE_INT}, null}, // public final static int opc_istore = 54;
+ {{CodeConstants.TYPE_LONG}, null}, // public final static int opc_lstore = 55;
+ {{CodeConstants.TYPE_FLOAT}, null}, // public final static int opc_fstore = 56;
+ {{CodeConstants.TYPE_DOUBLE}, null}, // public final static int opc_dstore = 57;
+ null, // public final static int opc_astore = 58;
+ null, // public final static int opc_istore_0 = 59;
+ null, // public final static int opc_istore_1 = 60;
+ null, // public final static int opc_istore_2 = 61;
+ null, // public final static int opc_istore_3 = 62;
+ null, // public final static int opc_lstore_0 = 63;
+ null, // public final static int opc_lstore_1 = 64;
+ null, // public final static int opc_lstore_2 = 65;
+ null, // public final static int opc_lstore_3 = 66;
+ null, // public final static int opc_fstore_0 = 67;
+ null, // public final static int opc_fstore_1 = 68;
+ null, // public final static int opc_fstore_2 = 69;
+ null, // public final static int opc_fstore_3 = 70;
+ null, // public final static int opc_dstore_0 = 71;
+ null, // public final static int opc_dstore_1 = 72;
+ null, // public final static int opc_dstore_2 = 73;
+ null, // public final static int opc_dstore_3 = 74;
+ null, // public final static int opc_astore_0 = 75;
+ null, // public final static int opc_astore_1 = 76;
+ null, // public final static int opc_astore_2 = 77;
+ null, // public final static int opc_astore_3 = 78;
+ {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, null},
+ // public final static int opc_iastore = 79;
+ {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT, CodeConstants.TYPE_LONG}, null},
+ // public final static int opc_lastore = 80;
+ {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT, CodeConstants.TYPE_FLOAT}, null},
+ // public final static int opc_fastore = 81;
+ {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT, CodeConstants.TYPE_DOUBLE}, null},
+ // public final static int opc_dastore = 82;
+ {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT, CodeConstants.TYPE_OBJECT}, null},
+ // public final static int opc_aastore = 83;
+ {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, null},
+ // public final static int opc_bastore = 84;
+ {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, null},
+ // public final static int opc_castore = 85;
+ {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, null},
+ // public final static int opc_sastore = 86;
+ {{CodeConstants.TYPE_ANY}, null}, // public final static int opc_pop = 87;
+ {{CodeConstants.TYPE_ANY, CodeConstants.TYPE_ANY}, null}, // public final static int opc_pop2 = 88;
+ null, // public final static int opc_dup = 89;
+ null, // public final static int opc_dup_x1 = 90;
+ null, // public final static int opc_dup_x2 = 91;
+ null, // public final static int opc_dup2 = 92;
+ null, // public final static int opc_dup2_x1 = 93;
+ null, // public final static int opc_dup2_x2 = 94;
+ null, // public final static int opc_swap = 95;
+ {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_iadd = 96;
+ {{CodeConstants.TYPE_LONG, CodeConstants.TYPE_LONG}, {CodeConstants.TYPE_LONG}},
+ // public final static int opc_ladd = 97;
+ {{CodeConstants.TYPE_FLOAT, CodeConstants.TYPE_FLOAT}, {CodeConstants.TYPE_FLOAT}},
+ // public final static int opc_fadd = 98;
+ {{CodeConstants.TYPE_DOUBLE, CodeConstants.TYPE_DOUBLE}, {CodeConstants.TYPE_DOUBLE}},
+ // public final static int opc_dadd = 99;
+ {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_isub = 100;
+ {{CodeConstants.TYPE_LONG, CodeConstants.TYPE_LONG}, {CodeConstants.TYPE_LONG}},
+ // public final static int opc_lsub = 101;
+ {{CodeConstants.TYPE_FLOAT, CodeConstants.TYPE_FLOAT}, {CodeConstants.TYPE_FLOAT}},
+ // public final static int opc_fsub = 102;
+ {{CodeConstants.TYPE_DOUBLE, CodeConstants.TYPE_DOUBLE}, {CodeConstants.TYPE_DOUBLE}},
+ // public final static int opc_dsub = 103;
+ {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_imul = 104;
+ {{CodeConstants.TYPE_LONG, CodeConstants.TYPE_LONG}, {CodeConstants.TYPE_LONG}},
+ // public final static int opc_lmul = 105;
+ {{CodeConstants.TYPE_FLOAT, CodeConstants.TYPE_FLOAT}, {CodeConstants.TYPE_FLOAT}},
+ // public final static int opc_fmul = 106;
+ {{CodeConstants.TYPE_DOUBLE, CodeConstants.TYPE_DOUBLE}, {CodeConstants.TYPE_DOUBLE}},
+ // public final static int opc_dmul = 107;
+ {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_idiv = 108;
+ {{CodeConstants.TYPE_LONG, CodeConstants.TYPE_LONG}, {CodeConstants.TYPE_LONG}},
+ // public final static int opc_ldiv = 109;
+ {{CodeConstants.TYPE_FLOAT, CodeConstants.TYPE_FLOAT}, {CodeConstants.TYPE_FLOAT}},
+ // public final static int opc_fdiv = 110;
+ {{CodeConstants.TYPE_DOUBLE, CodeConstants.TYPE_DOUBLE}, {CodeConstants.TYPE_DOUBLE}},
+ // public final static int opc_ddiv = 111;
+ {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_irem = 112;
+ {{CodeConstants.TYPE_LONG, CodeConstants.TYPE_LONG}, {CodeConstants.TYPE_LONG}},
+ // public final static int opc_lrem = 113;
+ {{CodeConstants.TYPE_FLOAT, CodeConstants.TYPE_FLOAT}, {CodeConstants.TYPE_FLOAT}},
+ // public final static int opc_frem = 114;
+ {{CodeConstants.TYPE_DOUBLE, CodeConstants.TYPE_DOUBLE}, {CodeConstants.TYPE_DOUBLE}},
+ // public final static int opc_drem = 115;
+ {{CodeConstants.TYPE_INT}, {CodeConstants.TYPE_INT}}, // public final static int opc_ineg = 116;
+ {{CodeConstants.TYPE_LONG}, {CodeConstants.TYPE_LONG}}, // public final static int opc_lneg = 117;
+ {{CodeConstants.TYPE_FLOAT}, {CodeConstants.TYPE_FLOAT}}, // public final static int opc_fneg = 118;
+ {{CodeConstants.TYPE_DOUBLE}, {CodeConstants.TYPE_DOUBLE}}, // public final static int opc_dneg = 119;
+ {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_ishl = 120;
+ {{CodeConstants.TYPE_LONG, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_LONG}},
+ // public final static int opc_lshl = 121;
+ {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_ishr = 122;
+ {{CodeConstants.TYPE_LONG, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_LONG}},
+ // public final static int opc_lshr = 123;
+ {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_iushr = 124;
+ {{CodeConstants.TYPE_LONG, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_LONG}},
+ // public final static int opc_lushr = 125;
+ {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_iand = 126;
+ {{CodeConstants.TYPE_LONG, CodeConstants.TYPE_LONG}, {CodeConstants.TYPE_LONG}},
+ // public final static int opc_land = 127;
+ {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_ior = 128;
+ {{CodeConstants.TYPE_LONG, CodeConstants.TYPE_LONG}, {CodeConstants.TYPE_LONG}},
+ // public final static int opc_lor = 129;
+ {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_ixor = 130;
+ {{CodeConstants.TYPE_LONG, CodeConstants.TYPE_LONG}, {CodeConstants.TYPE_LONG}},
+ // public final static int opc_lxor = 131;
+ {null, null}, // public final static int opc_iinc = 132;
+ {{CodeConstants.TYPE_INT}, {CodeConstants.TYPE_LONG}}, // public final static int opc_i2l = 133;
+ {{CodeConstants.TYPE_INT}, {CodeConstants.TYPE_FLOAT}}, // public final static int opc_i2f = 134;
+ {{CodeConstants.TYPE_INT}, {CodeConstants.TYPE_DOUBLE}}, // public final static int opc_i2d = 135;
+ {{CodeConstants.TYPE_LONG}, {CodeConstants.TYPE_INT}}, // public final static int opc_l2i = 136;
+ {{CodeConstants.TYPE_LONG}, {CodeConstants.TYPE_FLOAT}}, // public final static int opc_l2f = 137;
+ {{CodeConstants.TYPE_LONG}, {CodeConstants.TYPE_DOUBLE}}, // public final static int opc_l2d = 138;
+ {{CodeConstants.TYPE_FLOAT}, {CodeConstants.TYPE_INT}}, // public final static int opc_f2i = 139;
+ {{CodeConstants.TYPE_FLOAT}, {CodeConstants.TYPE_LONG}}, // public final static int opc_f2l = 140;
+ {{CodeConstants.TYPE_FLOAT}, {CodeConstants.TYPE_DOUBLE}}, // public final static int opc_f2d = 141;
+ {{CodeConstants.TYPE_DOUBLE}, {CodeConstants.TYPE_INT}}, // public final static int opc_d2i = 142;
+ {{CodeConstants.TYPE_DOUBLE}, {CodeConstants.TYPE_LONG}}, // public final static int opc_d2l = 143;
+ {{CodeConstants.TYPE_DOUBLE}, {CodeConstants.TYPE_FLOAT}}, // public final static int opc_d2f = 144;
+ {{CodeConstants.TYPE_INT}, {CodeConstants.TYPE_INT}}, // public final static int opc_i2b = 145;
+ {{CodeConstants.TYPE_INT}, {CodeConstants.TYPE_INT}}, // public final static int opc_i2c = 146;
+ {{CodeConstants.TYPE_INT}, {CodeConstants.TYPE_INT}}, // public final static int opc_i2s = 147;
+ {{CodeConstants.TYPE_LONG, CodeConstants.TYPE_LONG}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_lcmp = 148;
+ {{CodeConstants.TYPE_FLOAT, CodeConstants.TYPE_FLOAT}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_fcmpl = 149;
+ {{CodeConstants.TYPE_FLOAT, CodeConstants.TYPE_FLOAT}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_fcmpg = 150;
+ {{CodeConstants.TYPE_DOUBLE, CodeConstants.TYPE_DOUBLE}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_dcmpl = 151;
+ {{CodeConstants.TYPE_DOUBLE, CodeConstants.TYPE_DOUBLE}, {CodeConstants.TYPE_INT}},
+ // public final static int opc_dcmpg = 152;
+ {{CodeConstants.TYPE_INT}, null}, // public final static int opc_ifeq = 153;
+ {{CodeConstants.TYPE_INT}, null}, // public final static int opc_ifne = 154;
+ {{CodeConstants.TYPE_INT}, null}, // public final static int opc_iflt = 155;
+ {{CodeConstants.TYPE_INT}, null}, // public final static int opc_ifge = 156;
+ {{CodeConstants.TYPE_INT}, null}, // public final static int opc_ifgt = 157;
+ {{CodeConstants.TYPE_INT}, null}, // public final static int opc_ifle = 158;
+ {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, null}, // public final static int opc_if_icmpeq = 159;
+ {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, null}, // public final static int opc_if_icmpne = 160;
+ {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, null}, // public final static int opc_if_icmplt = 161;
+ {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, null}, // public final static int opc_if_icmpge = 162;
+ {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, null}, // public final static int opc_if_icmpgt = 163;
+ {{CodeConstants.TYPE_INT, CodeConstants.TYPE_INT}, null}, // public final static int opc_if_icmple = 164;
+ {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_OBJECT}, null},
+ // public final static int opc_if_acmpeq = 165;
+ {{CodeConstants.TYPE_OBJECT, CodeConstants.TYPE_OBJECT}, null},
+ // public final static int opc_if_acmpne = 166;
+ {null, null}, // public final static int opc_goto = 167;
+ {null, {CodeConstants.TYPE_ADDRESS}}, // public final static int opc_jsr = 168;
+ {null, null}, // public final static int opc_ret = 169;
+ {{CodeConstants.TYPE_INT}, null}, // public final static int opc_tableswitch = 170;
+ {{CodeConstants.TYPE_INT}, null}, // public final static int opc_lookupswitch = 171;
+ {{CodeConstants.TYPE_INT}, null}, // public final static int opc_ireturn = 172;
+ {{CodeConstants.TYPE_LONG}, null}, // public final static int opc_lreturn = 173;
+ {{CodeConstants.TYPE_FLOAT}, null}, // public final static int opc_freturn = 174;
+ {{CodeConstants.TYPE_DOUBLE}, null}, // public final static int opc_dreturn = 175;
+ {{CodeConstants.TYPE_OBJECT}, null}, // public final static int opc_areturn = 176;
+ {null, null}, // public final static int opc_return = 177;
+ null, // public final static int opc_getstatic = 178;
+ null, // public final static int opc_putstatic = 179;
+ null, // public final static int opc_getfield = 180;
+ null, // public final static int opc_putfield = 181;
+ null, // public final static int opc_invokevirtual = 182;
+ null, // public final static int opc_invokespecial = 183;
+ null, // public final static int opc_invokestatic = 184;
+ null, // public final static int opc_invokeinterface = 185;
+ null, // public final static int opc_xxxunusedxxx = 186;
+ null, // public final static int opc_new = 187;
+ null, // public final static int opc_newarray = 188;
+ null, // public final static int opc_anewarray = 189;
+ {{CodeConstants.TYPE_OBJECT}, {CodeConstants.TYPE_INT}}, // public final static int opc_arraylength = 190;
+ null,
+ // public final static int opc_athrow = 191;
+ null,
+ // public final static int opc_checkcast = 192;
+ null,
+ // public final static int opc_instanceof = 193;
+ {{CodeConstants.TYPE_OBJECT}, null}, // public final static int opc_monitorenter = 194;
+ {{CodeConstants.TYPE_OBJECT}, null}, // public final static int opc_monitorexit = 195;
+ null,
+ // public final static int opc_wide = 196;
+ null,
+ // public final static int opc_multianewarray = 197;
+ {{CodeConstants.TYPE_OBJECT}, null}, // public final static int opc_ifnull = 198;
+ {{CodeConstants.TYPE_OBJECT}, null}, // public final static int opc_ifnonnull = 199;
+ {null, null}, // public final static int opc_goto_w = 200;
+ {null, {CodeConstants.TYPE_ADDRESS}}, // public final static int opc_jsr_w = 201;
+ };
+
+ private static final int[] arr_type = new int[]{
+ CodeConstants.TYPE_BOOLEAN,
+ CodeConstants.TYPE_CHAR,
+ CodeConstants.TYPE_FLOAT,
+ CodeConstants.TYPE_DOUBLE,
+ CodeConstants.TYPE_BYTE,
+ CodeConstants.TYPE_SHORT,
+ CodeConstants.TYPE_INT,
+ CodeConstants.TYPE_LONG
+ };
+
+
+ // Sonderbehandlung
+ // null, // public final static int opc_aconst_null = 1;
+ // null, // public final static int opc_ldc = 18;
+ // null, // public final static int opc_ldc_w = 19;
+ // null, // public final static int opc_ldc2_w = 20;
+ // null, // public final static int opc_aload = 25;
+ // null, // public final static int opc_aaload = 50;
+ // null, // public final static int opc_astore = 58;
+ // null, // public final static int opc_dup = 89;
+ // null, // public final static int opc_dup_x1 = 90;
+ // null, // public final static int opc_dup_x2 = 91;
+ // null, // public final static int opc_dup2 = 92;
+ // null, // public final static int opc_dup2_x1 = 93;
+ // null, // public final static int opc_dup2_x2 = 94;
+ // null, // public final static int opc_swap = 95;
+ // null, // public final static int opc_getstatic = 178;
+ // null, // public final static int opc_putstatic = 179;
+ // null, // public final static int opc_getfield = 180;
+ // null, // public final static int opc_putfield = 181;
+ // null, // public final static int opc_invokevirtual = 182;
+ // null, // public final static int opc_invokespecial = 183;
+ // null, // public final static int opc_invokestatic = 184;
+ // null, // public final static int opc_invokeinterface = 185;
+ // null, // public final static int opc_new = 187;
+ // null, // public final static int opc_newarray = 188;
+ // null, // public final static int opc_anewarray = 189;
+ // null, // public final static int opc_athrow = 191;
+ // null, // public final static int opc_checkcast = 192;
+ // null, // public final static int opc_instanceof = 193;
+ // null, // public final static int opc_multianewarray = 197;
+
+
+ public static void stepTypes(DataPoint data, Instruction instr, ConstantPool pool) {
+
+ ListStack<VarType> stack = data.getStack();
+ int[][] arr = stack_impact[instr.opcode];
+
+ if (arr != null) {
+ // simple types only
+
+ int[] read = arr[0];
+ int[] write = arr[1];
+
+ if (read != null) {
+ int depth = 0;
+ for (int i = 0; i < read.length; i++) {
+ int type = read[i];
+ depth++;
+ if (type == CodeConstants.TYPE_LONG ||
+ type == CodeConstants.TYPE_DOUBLE) {
+ depth++;
+ }
+ }
+
+ stack.removeMultiple(depth);
+ }
+
+ if (write != null) {
+ for (int i = 0; i < write.length; i++) {
+ int type = write[i];
+ stack.push(new VarType(type));
+ if (type == CodeConstants.TYPE_LONG ||
+ type == CodeConstants.TYPE_DOUBLE) {
+ stack.push(new VarType(CodeConstants.TYPE_GROUP2EMPTY));
+ }
+ }
+ }
+ }
+ else {
+ // Sonderbehandlung
+ processSpecialInstructions(data, instr, pool);
+ }
+ }
+
+ private static void processSpecialInstructions(DataPoint data, Instruction instr, ConstantPool pool) {
+
+ VarType var1;
+ PrimitiveConstant cn;
+ LinkConstant ck;
+
+ ListStack<VarType> stack = data.getStack();
+
+ switch (instr.opcode) {
+ case CodeConstants.opc_aconst_null:
+ stack.push(new VarType(CodeConstants.TYPE_NULL, 0, null));
+ break;
+ case CodeConstants.opc_ldc:
+ case CodeConstants.opc_ldc_w:
+ case CodeConstants.opc_ldc2_w:
+ cn = pool.getPrimitiveConstant(instr.getOperand(0));
+ switch (cn.type) {
+ case CodeConstants.CONSTANT_Integer:
+ stack.push(new VarType(CodeConstants.TYPE_INT));
+ break;
+ case CodeConstants.CONSTANT_Float:
+ stack.push(new VarType(CodeConstants.TYPE_FLOAT));
+ break;
+ case CodeConstants.CONSTANT_Long:
+ stack.push(new VarType(CodeConstants.TYPE_LONG));
+ stack.push(new VarType(CodeConstants.TYPE_GROUP2EMPTY));
+ break;
+ case CodeConstants.CONSTANT_Double:
+ stack.push(new VarType(CodeConstants.TYPE_DOUBLE));
+ stack.push(new VarType(CodeConstants.TYPE_GROUP2EMPTY));
+ break;
+ case CodeConstants.CONSTANT_String:
+ stack.push(new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/String"));
+ break;
+ case CodeConstants.CONSTANT_Class:
+ stack.push(new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/Class"));
+ break;
+ }
+ break;
+ case CodeConstants.opc_aload:
+ var1 = data.getVariable(instr.getOperand(0));
+ if (var1 != null) {
+ stack.push(var1);
+ }
+ else {
+ stack.push(new VarType(CodeConstants.TYPE_OBJECT, 0, null));
+ }
+ break;
+ case CodeConstants.opc_aaload:
+ var1 = stack.pop(2);
+ stack.push(new VarType(var1.type, var1.arraydim - 1, var1.value));
+ break;
+ case CodeConstants.opc_astore:
+ data.setVariable(instr.getOperand(0), stack.pop());
+ break;
+ case CodeConstants.opc_dup:
+ case CodeConstants.opc_dup_x1:
+ case CodeConstants.opc_dup_x2:
+ int depth1 = 88 - instr.opcode;
+ stack.insertByOffset(depth1, stack.getByOffset(-1).copy());
+ break;
+ case CodeConstants.opc_dup2:
+ case CodeConstants.opc_dup2_x1:
+ case CodeConstants.opc_dup2_x2:
+ int depth2 = 90 - instr.opcode;
+ stack.insertByOffset(depth2, stack.getByOffset(-2).copy());
+ stack.insertByOffset(depth2, stack.getByOffset(-1).copy());
+ break;
+ case CodeConstants.opc_swap:
+ var1 = stack.pop();
+ stack.insertByOffset(-1, var1);
+ break;
+ case CodeConstants.opc_getfield:
+ stack.pop();
+ case CodeConstants.opc_getstatic:
+ ck = pool.getLinkConstant(instr.getOperand(0));
+ var1 = new VarType(ck.descriptor);
+ stack.push(var1);
+ if (var1.stack_size == 2) {
+ stack.push(new VarType(CodeConstants.TYPE_GROUP2EMPTY));
+ }
+ break;
+ case CodeConstants.opc_putfield:
+ stack.pop();
+ case CodeConstants.opc_putstatic:
+ ck = pool.getLinkConstant(instr.getOperand(0));
+ var1 = new VarType(ck.descriptor);
+ stack.pop(var1.stack_size);
+ break;
+ case CodeConstants.opc_invokevirtual:
+ case CodeConstants.opc_invokespecial:
+ case CodeConstants.opc_invokeinterface:
+ stack.pop();
+ case CodeConstants.opc_invokestatic:
+ case CodeConstants.opc_invokedynamic:
+ if (instr.opcode != CodeConstants.opc_invokedynamic || instr.bytecode_version >= CodeConstants.BYTECODE_JAVA_7) {
+ ck = pool.getLinkConstant(instr.getOperand(0));
+ MethodDescriptor md = MethodDescriptor.parseDescriptor(ck.descriptor);
+ for (int i = 0; i < md.params.length; i++) {
+ stack.pop(md.params[i].stack_size);
+ }
+ if (md.ret.type != CodeConstants.TYPE_VOID) {
+ stack.push(md.ret);
+ if (md.ret.stack_size == 2) {
+ stack.push(new VarType(CodeConstants.TYPE_GROUP2EMPTY));
+ }
+ }
+ }
+ break;
+ case CodeConstants.opc_new:
+ cn = pool.getPrimitiveConstant(instr.getOperand(0));
+ stack.push(new VarType(CodeConstants.TYPE_OBJECT, 0, cn.getString()));
+ break;
+ case CodeConstants.opc_newarray:
+ stack.pop();
+ var1 = new VarType(arr_type[instr.getOperand(0) - 4]);
+ var1.arraydim = 1;
+ stack.push(var1);
+ break;
+ case CodeConstants.opc_athrow:
+ var1 = stack.pop();
+ stack.clear();
+ stack.push(var1);
+ break;
+ case CodeConstants.opc_checkcast:
+ case CodeConstants.opc_instanceof:
+ stack.pop();
+ cn = pool.getPrimitiveConstant(instr.getOperand(0));
+ stack.push(new VarType(CodeConstants.TYPE_OBJECT, 0, cn.getString()));
+ break;
+ case CodeConstants.opc_anewarray:
+ case CodeConstants.opc_multianewarray:
+ int dimensions = (instr.opcode == CodeConstants.opc_anewarray) ? 1 : instr.getOperand(1);
+ stack.pop(dimensions);
+ cn = pool.getPrimitiveConstant(instr.getOperand(0));
+ if (cn.isArray) {
+ var1 = new VarType(CodeConstants.TYPE_OBJECT, 0, cn.getString());
+ var1.arraydim += dimensions;
+ stack.push(var1);
+ }
+ else {
+ stack.push(new VarType(CodeConstants.TYPE_OBJECT, dimensions, cn.getString()));
+ }
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/interpreter/Util.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/interpreter/Util.java
new file mode 100644
index 000000000000..bf1e5eb8d9d4
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/interpreter/Util.java
@@ -0,0 +1,286 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.interpreter;
+
+import org.jetbrains.java.decompiler.code.Instruction;
+import org.jetbrains.java.decompiler.struct.StructClass;
+import org.jetbrains.java.decompiler.struct.StructContext;
+
+
+// FIXME: move to StructContext
+public class Util {
+
+ private static final String[][] runtime_exceptions = {
+
+ null, // public final static int opc_nop = 0;
+ null, // public final static int opc_aconst_null = 1;
+ null, // public final static int opc_iconst_m1 = 2;
+ null, // public final static int opc_iconst_0 = 3;
+ null, // public final static int opc_iconst_1 = 4;
+ null, // public final static int opc_iconst_2 = 5;
+ null, // public final static int opc_iconst_3 = 6;
+ null, // public final static int opc_iconst_4 = 7;
+ null, // public final static int opc_iconst_5 = 8;
+ null, // public final static int opc_lconst_0 = 9;
+ null, // public final static int opc_lconst_1 = 10;
+ null, // public final static int opc_fconst_0 = 11;
+ null, // public final static int opc_fconst_1 = 12;
+ null, // public final static int opc_fconst_2 = 13;
+ null, // public final static int opc_dconst_0 = 14;
+ null, // public final static int opc_dconst_1 = 15;
+ null, // public final static int opc_bipush = 16;
+ null, // public final static int opc_sipush = 17;
+ null, // public final static int opc_ldc = 18;
+ null, // public final static int opc_ldc_w = 19;
+ null, // public final static int opc_ldc2_w = 20;
+ null, // public final static int opc_iload = 21;
+ null, // public final static int opc_lload = 22;
+ null, // public final static int opc_fload = 23;
+ null, // public final static int opc_dload = 24;
+ null, // public final static int opc_aload = 25;
+ null, // public final static int opc_iload_0 = 26;
+ null, // public final static int opc_iload_1 = 27;
+ null, // public final static int opc_iload_2 = 28;
+ null, // public final static int opc_iload_3 = 29;
+ null, // public final static int opc_lload_0 = 30;
+ null, // public final static int opc_lload_1 = 31;
+ null, // public final static int opc_lload_2 = 32;
+ null, // public final static int opc_lload_3 = 33;
+ null, // public final static int opc_fload_0 = 34;
+ null, // public final static int opc_fload_1 = 35;
+ null, // public final static int opc_fload_2 = 36;
+ null, // public final static int opc_fload_3 = 37;
+ null, // public final static int opc_dload_0 = 38;
+ null, // public final static int opc_dload_1 = 39;
+ null, // public final static int opc_dload_2 = 40;
+ null, // public final static int opc_dload_3 = 41;
+ null, // public final static int opc_aload_0 = 42;
+ null, // public final static int opc_aload_1 = 43;
+ null, // public final static int opc_aload_2 = 44;
+ null, // public final static int opc_aload_3 = 45;
+ {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
+ // public final static int opc_iaload = 46;
+ {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
+ // public final static int opc_laload = 47;
+ {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
+ // public final static int opc_faload = 48;
+ {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
+ // public final static int opc_daload = 49;
+ {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
+ // public final static int opc_aaload = 50;
+ {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
+ // public final static int opc_baload = 51;
+ {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
+ // public final static int opc_caload = 52;
+ {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
+ // public final static int opc_saload = 53;
+ null, // public final static int opc_istore = 54;
+ null, // public final static int opc_lstore = 55;
+ null, // public final static int opc_fstore = 56;
+ null, // public final static int opc_dstore = 57;
+ null, // public final static int opc_astore = 58;
+ null, // public final static int opc_istore_0 = 59;
+ null, // public final static int opc_istore_1 = 60;
+ null, // public final static int opc_istore_2 = 61;
+ null, // public final static int opc_istore_3 = 62;
+ null, // public final static int opc_lstore_0 = 63;
+ null, // public final static int opc_lstore_1 = 64;
+ null, // public final static int opc_lstore_2 = 65;
+ null, // public final static int opc_lstore_3 = 66;
+ null, // public final static int opc_fstore_0 = 67;
+ null, // public final static int opc_fstore_1 = 68;
+ null, // public final static int opc_fstore_2 = 69;
+ null, // public final static int opc_fstore_3 = 70;
+ null, // public final static int opc_dstore_0 = 71;
+ null, // public final static int opc_dstore_1 = 72;
+ null, // public final static int opc_dstore_2 = 73;
+ null, // public final static int opc_dstore_3 = 74;
+ null, // public final static int opc_astore_0 = 75;
+ null, // public final static int opc_astore_1 = 76;
+ null, // public final static int opc_astore_2 = 77;
+ null, // public final static int opc_astore_3 = 78;
+ {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
+ // public final static int opc_iastore = 79;
+ {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
+ // public final static int opc_lastore = 80;
+ {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
+ // public final static int opc_fastore = 81;
+ {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
+ // public final static int opc_dastore = 82;
+ {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException", "java/lang/ArrayStoreException"},
+ // public final static int opc_aastore = 83;
+ {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
+ // public final static int opc_bastore = 84;
+ {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
+ // public final static int opc_castore = 85;
+ {"java/lang/NullPointerException", "java/lang/ArrayIndexOutOfBoundsException"},
+ // public final static int opc_sastore = 86;
+ null, // public final static int opc_pop = 87;
+ null, // public final static int opc_pop2 = 88;
+ null, // public final static int opc_dup = 89;
+ null, // public final static int opc_dup_x1 = 90;
+ null, // public final static int opc_dup_x2 = 91;
+ null, // public final static int opc_dup2 = 92;
+ null, // public final static int opc_dup2_x1 = 93;
+ null, // public final static int opc_dup2_x2 = 94;
+ null, // public final static int opc_swap = 95;
+ null, // public final static int opc_iadd = 96;
+ null, // public final static int opc_ladd = 97;
+ null, // public final static int opc_fadd = 98;
+ null, // public final static int opc_dadd = 99;
+ null, // public final static int opc_isub = 100;
+ null, // public final static int opc_lsub = 101;
+ null, // public final static int opc_fsub = 102;
+ null, // public final static int opc_dsub = 103;
+ null, // public final static int opc_imul = 104;
+ null, // public final static int opc_lmul = 105;
+ null, // public final static int opc_fmul = 106;
+ null, // public final static int opc_dmul = 107;
+ {"java/lang/ArithmeticException"}, // public final static int opc_idiv = 108;
+ {"java/lang/ArithmeticException"}, // public final static int opc_ldiv = 109;
+ null, // public final static int opc_fdiv = 110;
+ null, // public final static int opc_ddiv = 111;
+ {"java/lang/ArithmeticException"}, // public final static int opc_irem = 112;
+ {"java/lang/ArithmeticException"}, // public final static int opc_lrem = 113;
+ null, // public final static int opc_frem = 114;
+ null, // public final static int opc_drem = 115;
+ null, // public final static int opc_ineg = 116;
+ null, // public final static int opc_lneg = 117;
+ null, // public final static int opc_fneg = 118;
+ null, // public final static int opc_dneg = 119;
+ null, // public final static int opc_ishl = 120;
+ null, // public final static int opc_lshl = 121;
+ null, // public final static int opc_ishr = 122;
+ null, // public final static int opc_lshr = 123;
+ null, // public final static int opc_iushr = 124;
+ null, // public final static int opc_lushr = 125;
+ null, // public final static int opc_iand = 126;
+ null, // public final static int opc_land = 127;
+ null, // public final static int opc_ior = 128;
+ null, // public final static int opc_lor = 129;
+ null, // public final static int opc_ixor = 130;
+ null, // public final static int opc_lxor = 131;
+ null, // public final static int opc_iinc = 132;
+ null, // public final static int opc_i2l = 133;
+ null, // public final static int opc_i2f = 134;
+ null, // public final static int opc_i2d = 135;
+ null, // public final static int opc_l2i = 136;
+ null, // public final static int opc_l2f = 137;
+ null, // public final static int opc_l2d = 138;
+ null, // public final static int opc_f2i = 139;
+ null, // public final static int opc_f2l = 140;
+ null, // public final static int opc_f2d = 141;
+ null, // public final static int opc_d2i = 142;
+ null, // public final static int opc_d2l = 143;
+ null, // public final static int opc_d2f = 144;
+ null, // public final static int opc_i2b = 145;
+ null, // public final static int opc_i2c = 146;
+ null, // public final static int opc_i2s = 147;
+ null, // public final static int opc_lcmp = 148;
+ null, // public final static int opc_fcmpl = 149;
+ null, // public final static int opc_fcmpg = 150;
+ null, // public final static int opc_dcmpl = 151;
+ null, // public final static int opc_dcmpg = 152;
+ null, // public final static int opc_ifeq = 153;
+ null, // public final static int opc_ifne = 154;
+ null, // public final static int opc_iflt = 155;
+ null, // public final static int opc_ifge = 156;
+ null, // public final static int opc_ifgt = 157;
+ null, // public final static int opc_ifle = 158;
+ null, // public final static int opc_if_icmpeq = 159;
+ null, // public final static int opc_if_icmpne = 160;
+ null, // public final static int opc_if_icmplt = 161;
+ null, // public final static int opc_if_icmpge = 162;
+ null, // public final static int opc_if_icmpgt = 163;
+ null, // public final static int opc_if_icmple = 164;
+ null, // public final static int opc_if_acmpeq = 165;
+ null, // public final static int opc_if_acmpne = 166;
+ null, // public final static int opc_goto = 167;
+ null, // public final static int opc_jsr = 168;
+ null, // public final static int opc_ret = 169;
+ null, // public final static int opc_tableswitch = 170;
+ null, // public final static int opc_lookupswitch = 171;
+ {"java/lang/IllegalMonitorStateException"}, // public final static int opc_ireturn = 172;
+ {"java/lang/IllegalMonitorStateException"}, // public final static int opc_lreturn = 173;
+ {"java/lang/IllegalMonitorStateException"}, // public final static int opc_freturn = 174;
+ {"java/lang/IllegalMonitorStateException"}, // public final static int opc_dreturn = 175;
+ {"java/lang/IllegalMonitorStateException"}, // public final static int opc_areturn = 176;
+ {"java/lang/IllegalMonitorStateException"}, // public final static int opc_return = 177;
+ null, // public final static int opc_getstatic = 178;
+ null, // public final static int opc_putstatic = 179;
+ {"java/lang/NullPointerException"}, // public final static int opc_getfield = 180;
+ {"java/lang/NullPointerException"}, // public final static int opc_putfield = 181;
+ {"java/lang/NullPointerException", "java/lang/AbstractMethodError", "java/lang/UnsatisfiedLinkError"},
+ // public final static int opc_invokevirtual = 182;
+ {"java/lang/NullPointerException", "java/lang/UnsatisfiedLinkError"},
+ // public final static int opc_invokespecial = 183;
+ {"java/lang/UnsatisfiedLinkError"}, // public final static int opc_invokestatic = 184;
+ {"java/lang/NullPointerException", "java/lang/IncompatibleClassChangeError", "java/lang/IllegalAccessError",
+ "java/lang/java/lang/AbstractMethodError", "java/lang/UnsatisfiedLinkError"},
+ // public final static int opc_invokeinterface = 185;
+ null, // public final static int opc_xxxunusedxxx = 186;
+ null, // public final static int opc_new = 187;
+ {"java/lang/NegativeArraySizeException"}, // public final static int opc_newarray = 188;
+ {"java/lang/NegativeArraySizeException"}, // public final static int opc_anewarray = 189;
+ {"java/lang/NullPointerException"}, // public final static int opc_arraylength = 190;
+ {"java/lang/NullPointerException", "java/lang/IllegalMonitorStateException"},
+ // public final static int opc_athrow = 191;
+ {"java/lang/ClassCastException"}, // public final static int opc_checkcast = 192;
+ null, // public final static int opc_instanceof = 193;
+ {"java/lang/NullPointerException"}, // public final static int opc_monitorenter = 194;
+ {"java/lang/NullPointerException", "java/lang/IllegalMonitorStateException"},
+ // public final static int opc_monitorexit = 195;
+ null, // public final static int opc_wide = 196;
+ {"java/lang/NegativeArraySizeException"}, // public final static int opc_multianewarray = 197;
+ null, // public final static int opc_ifnull = 198;
+ null, // public final static int opc_ifnonnull = 199;
+ null, // public final static int opc_goto_w = 200;
+ null, // public final static int opc_jsr_w = 201;
+ };
+
+
+ public static boolean instanceOf(StructContext context, String valclass, String refclass) {
+
+ if (valclass.equals(refclass)) {
+ return true;
+ }
+
+ StructClass cl = context.getClass(valclass);
+ if (cl == null) {
+ return false;
+ }
+
+ if (cl.superClass != null && instanceOf(context, cl.superClass.getString(), refclass)) {
+ return true;
+ }
+
+ int[] interfaces = cl.getInterfaces();
+ for (int i = 0; i < interfaces.length; i++) {
+ String intfc = cl.getPool().getPrimitiveConstant(interfaces[i]).getString();
+
+ if (instanceOf(context, intfc, refclass)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ public static String[] getRuntimeExceptions(Instruction instr) {
+ return runtime_exceptions[instr.opcode];
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/ALOAD.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/ALOAD.java
new file mode 100644
index 000000000000..788795e6fe7d
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/ALOAD.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.optinstructions;
+
+import org.jetbrains.java.decompiler.code.Instruction;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class ALOAD extends Instruction {
+
+ private static int[] opcodes = new int[]{opc_aload_0, opc_aload_1, opc_aload_2, opc_aload_3};
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ out.writeByte(opc_wide);
+ }
+ out.writeByte(opc_aload);
+ if (wide) {
+ out.writeShort(index);
+ }
+ else {
+ out.writeByte(index);
+ }
+ }
+ else {
+ out.writeByte(opcodes[index]);
+ }
+ }
+
+ public int length() {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ return 4;
+ }
+ else {
+ return 2;
+ }
+ }
+ else {
+ return 1;
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/ANEWARRAY.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/ANEWARRAY.java
new file mode 100644
index 000000000000..d514ffe9f772
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/ANEWARRAY.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.optinstructions;
+
+import org.jetbrains.java.decompiler.code.Instruction;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class ANEWARRAY extends Instruction {
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_anewarray);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/ASTORE.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/ASTORE.java
new file mode 100644
index 000000000000..40336f483edf
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/ASTORE.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.optinstructions;
+
+import org.jetbrains.java.decompiler.code.Instruction;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class ASTORE extends Instruction {
+
+ private static int[] opcodes = new int[]{opc_astore_0, opc_astore_1, opc_astore_2, opc_astore_3};
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ out.writeByte(opc_wide);
+ }
+ out.writeByte(opc_astore);
+ if (wide) {
+ out.writeShort(index);
+ }
+ else {
+ out.writeByte(index);
+ }
+ }
+ else {
+ out.writeByte(opcodes[index]);
+ }
+ }
+
+ public int length() {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ return 4;
+ }
+ else {
+ return 2;
+ }
+ }
+ else {
+ return 1;
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/BIPUSH.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/BIPUSH.java
new file mode 100644
index 000000000000..4686051cfe18
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/BIPUSH.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.optinstructions;
+
+import org.jetbrains.java.decompiler.code.Instruction;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class BIPUSH extends Instruction {
+
+ private static int[] opcodes =
+ new int[]{opc_iconst_m1, opc_iconst_0, opc_iconst_1, opc_iconst_2, opc_iconst_3, opc_iconst_4, opc_iconst_5};
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ int value = getOperand(0);
+ if (value < -1 || value > 5) {
+ out.writeByte(opc_bipush);
+ out.writeByte(value);
+ }
+ else {
+ out.writeByte(opcodes[value + 1]);
+ }
+ }
+
+ public int length() {
+ int value = getOperand(0);
+ if (value < -1 || value > 5) {
+ return 2;
+ }
+ else {
+ return 1;
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/CHECKCAST.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/CHECKCAST.java
new file mode 100644
index 000000000000..9a42f656ed00
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/CHECKCAST.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.optinstructions;
+
+import org.jetbrains.java.decompiler.code.Instruction;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class CHECKCAST extends Instruction {
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_checkcast);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
+}
+
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/DLOAD.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/DLOAD.java
new file mode 100644
index 000000000000..7630185b45bc
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/DLOAD.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.optinstructions;
+
+import org.jetbrains.java.decompiler.code.Instruction;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class DLOAD extends Instruction {
+
+ private static int[] opcodes = new int[]{opc_dload_0, opc_dload_1, opc_dload_2, opc_dload_3};
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ out.writeByte(opc_wide);
+ }
+ out.writeByte(opc_dload);
+ if (wide) {
+ out.writeShort(index);
+ }
+ else {
+ out.writeByte(index);
+ }
+ }
+ else {
+ out.writeByte(opcodes[index]);
+ }
+ }
+
+ public int length() {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ return 4;
+ }
+ else {
+ return 2;
+ }
+ }
+ else {
+ return 1;
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/DSTORE.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/DSTORE.java
new file mode 100644
index 000000000000..2bdb74911305
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/DSTORE.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.optinstructions;
+
+import org.jetbrains.java.decompiler.code.Instruction;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class DSTORE extends Instruction {
+
+ private static int[] opcodes = new int[]{opc_dstore_0, opc_dstore_1, opc_dstore_2, opc_dstore_3};
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ out.writeByte(opc_wide);
+ }
+ out.writeByte(opc_dstore);
+ if (wide) {
+ out.writeShort(index);
+ }
+ else {
+ out.writeByte(index);
+ }
+ }
+ else {
+ out.writeByte(opcodes[index]);
+ }
+ }
+
+ public int length() {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ return 4;
+ }
+ else {
+ return 2;
+ }
+ }
+ else {
+ return 1;
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/FLOAD.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/FLOAD.java
new file mode 100644
index 000000000000..8a89dfff66fc
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/FLOAD.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.optinstructions;
+
+import org.jetbrains.java.decompiler.code.Instruction;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class FLOAD extends Instruction {
+
+ private static int[] opcodes = new int[]{opc_fload_0, opc_fload_1, opc_fload_2, opc_fload_3};
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ out.writeByte(opc_wide);
+ }
+ out.writeByte(opc_fload);
+ if (wide) {
+ out.writeShort(index);
+ }
+ else {
+ out.writeByte(index);
+ }
+ }
+ else {
+ out.writeByte(opcodes[index]);
+ }
+ }
+
+ public int length() {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ return 4;
+ }
+ else {
+ return 2;
+ }
+ }
+ else {
+ return 1;
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/FSTORE.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/FSTORE.java
new file mode 100644
index 000000000000..9061913c0032
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/FSTORE.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.optinstructions;
+
+import org.jetbrains.java.decompiler.code.Instruction;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class FSTORE extends Instruction {
+
+ private static int[] opcodes = new int[]{opc_fstore_0, opc_fstore_1, opc_fstore_2, opc_fstore_3};
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ out.writeByte(opc_wide);
+ }
+ out.writeByte(opc_fstore);
+ if (wide) {
+ out.writeShort(index);
+ }
+ else {
+ out.writeByte(index);
+ }
+ }
+ else {
+ out.writeByte(opcodes[index]);
+ }
+ }
+
+ public int length() {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ return 4;
+ }
+ else {
+ return 2;
+ }
+ }
+ else {
+ return 1;
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/GETFIELD.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/GETFIELD.java
new file mode 100644
index 000000000000..6b95aaf91668
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/GETFIELD.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.optinstructions;
+
+import org.jetbrains.java.decompiler.code.Instruction;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class GETFIELD extends Instruction {
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_getfield);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/GETSTATIC.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/GETSTATIC.java
new file mode 100644
index 000000000000..c1401a6128c8
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/GETSTATIC.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.optinstructions;
+
+import org.jetbrains.java.decompiler.code.Instruction;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class GETSTATIC extends Instruction {
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_getstatic);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/GOTO.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/GOTO.java
new file mode 100644
index 000000000000..97374c081cb9
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/GOTO.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.optinstructions;
+
+import org.jetbrains.java.decompiler.code.JumpInstruction;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class GOTO extends JumpInstruction {
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ int operand = getOperand(0);
+ if (operand < -32768 || operand > 32767) {
+ out.writeByte(opc_goto_w);
+ out.writeInt(operand);
+ }
+ else {
+ out.writeByte(opc_goto);
+ out.writeShort(operand);
+ }
+ }
+
+ public int length() {
+ int operand = getOperand(0);
+ if (operand < -32768 || operand > 32767) {
+ return 5;
+ }
+ else {
+ return 3;
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/GOTO_W.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/GOTO_W.java
new file mode 100644
index 000000000000..56ba9e8d59fb
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/GOTO_W.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.optinstructions;
+
+import org.jetbrains.java.decompiler.code.JumpInstruction;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class GOTO_W extends JumpInstruction {
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_goto_w);
+ out.writeInt(getOperand(0));
+ }
+
+ public int length() {
+ return 5;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/IINC.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/IINC.java
new file mode 100644
index 000000000000..05b446c861c9
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/IINC.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.optinstructions;
+
+import org.jetbrains.java.decompiler.code.Instruction;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class IINC extends Instruction {
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ if (wide) {
+ out.writeByte(opc_wide);
+ }
+ out.writeByte(opc_iinc);
+ if (wide) {
+ out.writeShort(getOperand(0));
+ out.writeShort(getOperand(1));
+ }
+ else {
+ out.writeByte(getOperand(0));
+ out.writeByte(getOperand(1));
+ }
+ }
+
+ public int length() {
+ return wide ? 6 : 3;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/ILOAD.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/ILOAD.java
new file mode 100644
index 000000000000..24b95ffbea8d
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/ILOAD.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.optinstructions;
+
+import org.jetbrains.java.decompiler.code.Instruction;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class ILOAD extends Instruction {
+
+ private static int[] opcodes = new int[]{opc_iload_0, opc_iload_1, opc_iload_2, opc_iload_3};
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ out.writeByte(opc_wide);
+ }
+ out.writeByte(opc_iload);
+ if (wide) {
+ out.writeShort(index);
+ }
+ else {
+ out.writeByte(index);
+ }
+ }
+ else {
+ out.writeByte(opcodes[index]);
+ }
+ }
+
+ public int length() {
+ int index = getOperand(0);
+ if (index > 3) {
+ return wide ? 4 : 2;
+ }
+ else {
+ return 1;
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/INSTANCEOF.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/INSTANCEOF.java
new file mode 100644
index 000000000000..f93d5b892105
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/INSTANCEOF.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.optinstructions;
+
+import org.jetbrains.java.decompiler.code.Instruction;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class INSTANCEOF extends Instruction {
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_instanceof);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKEDYNAMIC.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKEDYNAMIC.java
new file mode 100644
index 000000000000..917c5bde038d
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKEDYNAMIC.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.optinstructions;
+
+import org.jetbrains.java.decompiler.code.Instruction;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class INVOKEDYNAMIC extends Instruction {
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_invokedynamic);
+ out.writeShort(getOperand(0));
+ out.writeByte(0);
+ out.writeByte(0);
+ }
+
+ public int length() {
+ return 5;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKEINTERFACE.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKEINTERFACE.java
new file mode 100644
index 000000000000..51259ff03eb5
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKEINTERFACE.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.optinstructions;
+
+import org.jetbrains.java.decompiler.code.Instruction;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class INVOKEINTERFACE extends Instruction {
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_invokeinterface);
+ out.writeShort(getOperand(0));
+ out.writeByte(getOperand(1));
+ out.writeByte(0);
+ }
+
+ public int length() {
+ return 5;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKESPECIAL.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKESPECIAL.java
new file mode 100644
index 000000000000..2436803541fd
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKESPECIAL.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.optinstructions;
+
+import org.jetbrains.java.decompiler.code.Instruction;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class INVOKESPECIAL extends Instruction {
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_invokespecial);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKESTATIC.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKESTATIC.java
new file mode 100644
index 000000000000..f036a1d90d79
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKESTATIC.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.optinstructions;
+
+import org.jetbrains.java.decompiler.code.Instruction;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class INVOKESTATIC extends Instruction {
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_invokestatic);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKEVIRTUAL.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKEVIRTUAL.java
new file mode 100644
index 000000000000..ca3bcd3809ec
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/INVOKEVIRTUAL.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.optinstructions;
+
+import org.jetbrains.java.decompiler.code.Instruction;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class INVOKEVIRTUAL extends Instruction {
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_invokevirtual);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/ISTORE.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/ISTORE.java
new file mode 100644
index 000000000000..5907538389b5
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/ISTORE.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.optinstructions;
+
+import org.jetbrains.java.decompiler.code.Instruction;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class ISTORE extends Instruction {
+
+ private static int[] opcodes = new int[]{opc_istore_0, opc_istore_1, opc_istore_2, opc_istore_3};
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ out.writeByte(opc_wide);
+ }
+ out.writeByte(opc_istore);
+ if (wide) {
+ out.writeShort(index);
+ }
+ else {
+ out.writeByte(index);
+ }
+ }
+ else {
+ out.writeByte(opcodes[index]);
+ }
+ }
+
+ public int length() {
+ int index = getOperand(0);
+ if (index > 3) {
+ return wide ? 4 : 2;
+ }
+ else {
+ return 1;
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/JSR.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/JSR.java
new file mode 100644
index 000000000000..bb000a7ad08a
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/JSR.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.optinstructions;
+
+import org.jetbrains.java.decompiler.code.JumpInstruction;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class JSR extends JumpInstruction {
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ int operand = getOperand(0);
+ if (operand < -32768 || operand > 32767) {
+ out.writeByte(opc_jsr_w);
+ out.writeInt(operand);
+ }
+ else {
+ out.writeByte(opc_jsr);
+ out.writeShort(operand);
+ }
+ }
+
+ public int length() {
+ int operand = getOperand(0);
+ if (operand < -32768 || operand > 32767) {
+ return 5;
+ }
+ else {
+ return 3;
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/JSR_W.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/JSR_W.java
new file mode 100644
index 000000000000..fb04ed97e913
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/JSR_W.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.optinstructions;
+
+import org.jetbrains.java.decompiler.code.JumpInstruction;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class JSR_W extends JumpInstruction {
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_jsr_w);
+ out.writeInt(getOperand(0));
+ }
+
+ public int length() {
+ return 5;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/LDC.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/LDC.java
new file mode 100644
index 000000000000..ae7b3c6b8802
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/LDC.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.optinstructions;
+
+import org.jetbrains.java.decompiler.code.Instruction;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class LDC extends Instruction {
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_ldc);
+ out.writeByte(getOperand(0));
+ }
+
+ public int length() {
+ return 2;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/LDC2_W.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/LDC2_W.java
new file mode 100644
index 000000000000..6ba19649bdaf
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/LDC2_W.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.optinstructions;
+
+import org.jetbrains.java.decompiler.code.Instruction;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class LDC2_W extends Instruction {
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_ldc2_w);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/LDC_W.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/LDC_W.java
new file mode 100644
index 000000000000..71e5fe021bbd
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/LDC_W.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.optinstructions;
+
+import org.jetbrains.java.decompiler.code.Instruction;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class LDC_W extends Instruction {
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_ldc_w);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/LLOAD.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/LLOAD.java
new file mode 100644
index 000000000000..6e506593197f
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/LLOAD.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.optinstructions;
+
+import org.jetbrains.java.decompiler.code.Instruction;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class LLOAD extends Instruction {
+
+ private static int[] opcodes = new int[]{opc_lload_0, opc_lload_1, opc_lload_2, opc_lload_3};
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ out.writeByte(opc_wide);
+ }
+ out.writeByte(opc_lload);
+ if (wide) {
+ out.writeShort(index);
+ }
+ else {
+ out.writeByte(index);
+ }
+ }
+ else {
+ out.writeByte(opcodes[index]);
+ }
+ }
+
+ public int length() {
+ int index = getOperand(0);
+ if (index > 3) {
+ return wide ? 4 : 2;
+ }
+ else {
+ return 1;
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/LOOKUPSWITCH.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/LOOKUPSWITCH.java
new file mode 100644
index 000000000000..418316886d29
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/LOOKUPSWITCH.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.optinstructions;
+
+import org.jetbrains.java.decompiler.code.SwitchInstruction;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class LOOKUPSWITCH extends SwitchInstruction {
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+
+ out.writeByte(opc_lookupswitch);
+
+ int padding = 3 - (offset % 4);
+ for (int i = 0; i < padding; i++) {
+ out.writeByte(0);
+ }
+
+ for (int i = 0; i < operandsCount(); i++) {
+ out.writeInt(getOperand(i));
+ }
+ }
+
+ public int length() {
+ return 1 + operandsCount() * 4;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/LSTORE.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/LSTORE.java
new file mode 100644
index 000000000000..9095f04ea883
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/LSTORE.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.optinstructions;
+
+import org.jetbrains.java.decompiler.code.Instruction;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class LSTORE extends Instruction {
+
+ private static int[] opcodes = new int[]{opc_lstore_0, opc_lstore_1, opc_lstore_2, opc_lstore_3};
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ int index = getOperand(0);
+ if (index > 3) {
+ if (wide) {
+ out.writeByte(opc_wide);
+ }
+ out.writeByte(opc_lstore);
+ if (wide) {
+ out.writeShort(index);
+ }
+ else {
+ out.writeByte(index);
+ }
+ }
+ else {
+ out.writeByte(opcodes[index]);
+ }
+ }
+
+ public int length() {
+ int index = getOperand(0);
+ if (index > 3) {
+ return wide ? 4 : 2;
+ }
+ else {
+ return 1;
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/MULTIANEWARRAY.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/MULTIANEWARRAY.java
new file mode 100644
index 000000000000..b6835e80c761
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/MULTIANEWARRAY.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.optinstructions;
+
+import org.jetbrains.java.decompiler.code.Instruction;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class MULTIANEWARRAY extends Instruction {
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_multianewarray);
+ out.writeShort(getOperand(0));
+ out.writeByte(getOperand(1));
+ }
+
+ public int length() {
+ return 4;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/NEW.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/NEW.java
new file mode 100644
index 000000000000..2e8854f30877
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/NEW.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.optinstructions;
+
+import org.jetbrains.java.decompiler.code.Instruction;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class NEW extends Instruction {
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_new);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/NEWARRAY.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/NEWARRAY.java
new file mode 100644
index 000000000000..f2f8e4d5a433
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/NEWARRAY.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.optinstructions;
+
+import org.jetbrains.java.decompiler.code.Instruction;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class NEWARRAY extends Instruction {
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_newarray);
+ out.writeByte(getOperand(0));
+ }
+
+ public int length() {
+ return 2;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/PUTFIELD.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/PUTFIELD.java
new file mode 100644
index 000000000000..c1e3e9241985
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/PUTFIELD.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.optinstructions;
+
+import org.jetbrains.java.decompiler.code.Instruction;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class PUTFIELD extends Instruction {
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_putfield);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/PUTSTATIC.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/PUTSTATIC.java
new file mode 100644
index 000000000000..0fe0240242ed
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/PUTSTATIC.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.optinstructions;
+
+import org.jetbrains.java.decompiler.code.Instruction;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class PUTSTATIC extends Instruction {
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_putstatic);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/RET.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/RET.java
new file mode 100644
index 000000000000..93f62ff1bced
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/RET.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.optinstructions;
+
+import org.jetbrains.java.decompiler.code.Instruction;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class RET extends Instruction {
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ if (wide) {
+ out.writeByte(opc_wide);
+ }
+ out.writeByte(opc_ret);
+ if (wide) {
+ out.writeShort(getOperand(0));
+ }
+ else {
+ out.writeByte(getOperand(0));
+ }
+ }
+
+ public int length() {
+ return wide ? 4 : 2;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/SIPUSH.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/SIPUSH.java
new file mode 100644
index 000000000000..08b10a51725e
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/SIPUSH.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.optinstructions;
+
+import org.jetbrains.java.decompiler.code.Instruction;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class SIPUSH extends Instruction {
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+ out.writeByte(opc_sipush);
+ out.writeShort(getOperand(0));
+ }
+
+ public int length() {
+ return 3;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/TABLESWITCH.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/TABLESWITCH.java
new file mode 100644
index 000000000000..0b41ecf232fe
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/code/optinstructions/TABLESWITCH.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.code.optinstructions;
+
+import org.jetbrains.java.decompiler.code.SwitchInstruction;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+public class TABLESWITCH extends SwitchInstruction {
+
+ public void writeToStream(DataOutputStream out, int offset) throws IOException {
+
+ out.writeByte(opc_tableswitch);
+
+ int padding = 3 - (offset % 4);
+ for (int i = 0; i < padding; i++) {
+ out.writeByte(0);
+ }
+
+ for (int i = 0; i < operandsCount(); i++) {
+ out.writeInt(getOperand(i));
+ }
+ }
+
+ public int length() {
+ return 1 + operandsCount() * 4;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/AssertProcessor.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/AssertProcessor.java
new file mode 100644
index 000000000000..a58b68903563
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/AssertProcessor.java
@@ -0,0 +1,310 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.main;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.code.cfg.BasicBlock;
+import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
+import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
+import org.jetbrains.java.decompiler.main.rels.ClassWrapper;
+import org.jetbrains.java.decompiler.main.rels.MethodWrapper;
+import org.jetbrains.java.decompiler.modules.decompiler.SecondaryFunctionsHelper;
+import org.jetbrains.java.decompiler.modules.decompiler.StatEdge;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.*;
+import org.jetbrains.java.decompiler.struct.StructField;
+import org.jetbrains.java.decompiler.struct.gen.FieldDescriptor;
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class AssertProcessor {
+
+ private static final VarType CLASS_ASSERTION_ERROR = new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/AssertionError");
+
+ public static void buildAssertions(ClassNode node) {
+
+ ClassWrapper wrapper = node.wrapper;
+
+ StructField field = findAssertionField(node);
+
+ if (field != null) {
+
+ String key = InterpreterUtil.makeUniqueKey(field.getName(), field.getDescriptor());
+
+ boolean res = false;
+
+ for (MethodWrapper meth : wrapper.getMethods()) {
+ RootStatement root = meth.root;
+ if (root != null) {
+ res |= replaceAssertions(root, wrapper.getClassStruct().qualifiedName, key);
+ }
+ }
+
+ if (res) {
+ // hide the helper field
+ wrapper.getHiddenMembers().add(key);
+ }
+ }
+ }
+
+ private static StructField findAssertionField(ClassNode node) {
+
+ ClassWrapper wrapper = node.wrapper;
+
+ boolean noSynthFlag = DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET);
+
+ for (StructField fd : wrapper.getClassStruct().getFields()) {
+
+ String keyField = InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor());
+
+ // initializer exists
+ if (wrapper.getStaticFieldInitializers().containsKey(keyField)) {
+
+ // access flags set
+ if (fd.hasModifier(CodeConstants.ACC_STATIC) && fd.hasModifier(CodeConstants.ACC_FINAL) && (noSynthFlag || fd.isSynthetic())) {
+
+ // field type boolean
+ FieldDescriptor fdescr = FieldDescriptor.parseDescriptor(fd.getDescriptor());
+ if (VarType.VARTYPE_BOOLEAN.equals(fdescr.type)) {
+
+ Exprent initializer = wrapper.getStaticFieldInitializers().getWithKey(keyField);
+ if (initializer.type == Exprent.EXPRENT_FUNCTION) {
+ FunctionExprent fexpr = (FunctionExprent)initializer;
+
+ if (fexpr.getFunctype() == FunctionExprent.FUNCTION_BOOLNOT &&
+ fexpr.getLstOperands().get(0).type == Exprent.EXPRENT_INVOCATION) {
+
+ InvocationExprent invexpr = (InvocationExprent)fexpr.getLstOperands().get(0);
+
+ if (invexpr.getInstance() != null &&
+ invexpr.getInstance().type == Exprent.EXPRENT_CONST &&
+ "desiredAssertionStatus".equals(invexpr.getName()) &&
+ "java/lang/Class".equals(invexpr.getClassname()) &&
+ invexpr.getLstParameters().isEmpty()) {
+
+ ConstExprent cexpr = (ConstExprent)invexpr.getInstance();
+ if (VarType.VARTYPE_CLASS.equals(cexpr.getConsttype())) {
+
+ ClassNode nd = node;
+ while (nd != null) {
+ if (nd.wrapper.getClassStruct().qualifiedName.equals(cexpr.getValue())) {
+ break;
+ }
+ nd = nd.parent;
+ }
+
+ if (nd != null) { // found enclosing class with the same name
+ return fd;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ return null;
+ }
+
+
+ private static boolean replaceAssertions(Statement statement, String classname, String key) {
+
+ boolean res = false;
+
+ for (Statement st : statement.getStats()) {
+ res |= replaceAssertions(st, classname, key);
+ }
+
+ boolean replaced = true;
+ while (replaced) {
+ replaced = false;
+
+ for (Statement st : statement.getStats()) {
+ if (st.type == Statement.TYPE_IF) {
+ if (replaceAssertion(statement, (IfStatement)st, classname, key)) {
+ replaced = true;
+ break;
+ }
+ }
+ }
+
+ res |= replaced;
+ }
+
+ return res;
+ }
+
+ private static boolean replaceAssertion(Statement parent, IfStatement stat, String classname, String key) {
+
+ Statement ifstat = stat.getIfstat();
+ InvocationExprent throwError = isAssertionError(ifstat);
+
+ if (throwError == null) {
+ return false;
+ }
+
+ Object[] exprres = getAssertionExprent(stat.getHeadexprent().getCondition().copy(), classname, key);
+ if (!(Boolean)exprres[1]) {
+ return false;
+ }
+
+ List<Exprent> lstParams = new ArrayList<Exprent>();
+
+ Exprent ascond = null, retcond = null;
+ if (exprres[0] != null) {
+ ascond = new FunctionExprent(FunctionExprent.FUNCTION_BOOLNOT,
+ Arrays.asList(new Exprent[]{(Exprent)exprres[0]}));
+ retcond = SecondaryFunctionsHelper.propagateBoolNot(ascond);
+ }
+
+ lstParams.add(retcond == null ? ascond : retcond);
+ if (!throwError.getLstParameters().isEmpty()) {
+ lstParams.add(throwError.getLstParameters().get(0));
+ }
+
+ AssertExprent asexpr = new AssertExprent(lstParams);
+
+ Statement newstat = new BasicBlockStatement(new BasicBlock(
+ DecompilerContext.getCounterContainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER)));
+ newstat.setExprents(Arrays.asList(new Exprent[]{asexpr}));
+
+ Statement first = stat.getFirst();
+
+ if (stat.iftype == IfStatement.IFTYPE_IFELSE || (first.getExprents() != null &&
+ !first.getExprents().isEmpty())) {
+
+ first.removeSuccessor(stat.getIfEdge());
+ first.removeSuccessor(stat.getElseEdge());
+
+ List<Statement> lstStatements = new ArrayList<Statement>();
+ if (first.getExprents() != null && !first.getExprents().isEmpty()) {
+ lstStatements.add(first);
+ }
+ lstStatements.add(newstat);
+ if (stat.iftype == IfStatement.IFTYPE_IFELSE) {
+ lstStatements.add(stat.getElsestat());
+ }
+
+ SequenceStatement sequence = new SequenceStatement(lstStatements);
+ sequence.setAllParent();
+
+ for (int i = 0; i < sequence.getStats().size() - 1; i++) {
+ sequence.getStats().get(i).addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR,
+ sequence.getStats().get(i), sequence.getStats().get(i + 1)));
+ }
+
+ if (stat.iftype == IfStatement.IFTYPE_IFELSE) {
+ Statement ifelse = stat.getElsestat();
+
+ List<StatEdge> lstSuccs = ifelse.getAllSuccessorEdges();
+ if (!lstSuccs.isEmpty()) {
+ StatEdge endedge = lstSuccs.get(0);
+ if (endedge.closure == stat) {
+ sequence.addLabeledEdge(endedge);
+ }
+ }
+ }
+
+ newstat = sequence;
+ }
+
+ newstat.getVarDefinitions().addAll(stat.getVarDefinitions());
+ parent.replaceStatement(stat, newstat);
+
+ return true;
+ }
+
+ private static InvocationExprent isAssertionError(Statement stat) {
+
+ if (stat == null || stat.getExprents() == null || stat.getExprents().size() != 1) {
+ return null;
+ }
+
+ Exprent expr = stat.getExprents().get(0);
+
+ if (expr.type == Exprent.EXPRENT_EXIT) {
+ ExitExprent exexpr = (ExitExprent)expr;
+ if (exexpr.getExittype() == ExitExprent.EXIT_THROW && exexpr.getValue().type == Exprent.EXPRENT_NEW) {
+ NewExprent nexpr = (NewExprent)exexpr.getValue();
+ if (CLASS_ASSERTION_ERROR.equals(nexpr.getNewtype()) && nexpr.getConstructor() != null) {
+ return nexpr.getConstructor();
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private static Object[] getAssertionExprent(Exprent exprent, String classname, String key) {
+
+ if (exprent.type == Exprent.EXPRENT_FUNCTION) {
+ FunctionExprent fexpr = (FunctionExprent)exprent;
+ if (fexpr.getFunctype() == FunctionExprent.FUNCTION_CADD) {
+
+ for (int i = 0; i < 2; i++) {
+ Exprent param = fexpr.getLstOperands().get(i);
+
+ if (isAssertionField(param, classname, key)) {
+ return new Object[]{fexpr.getLstOperands().get(1 - i), true};
+ }
+ }
+
+ for (int i = 0; i < 2; i++) {
+ Exprent param = fexpr.getLstOperands().get(i);
+
+ Object[] res = getAssertionExprent(param, classname, key);
+ if ((Boolean)res[1]) {
+ if (param != res[0]) {
+ fexpr.getLstOperands().set(i, (Exprent)res[0]);
+ }
+ return new Object[]{fexpr, true};
+ }
+ }
+ }
+ else if (isAssertionField(fexpr, classname, key)) {
+ // assert false;
+ return new Object[]{null, true};
+ }
+ }
+
+ return new Object[]{exprent, false};
+ }
+
+ private static boolean isAssertionField(Exprent exprent, String classname, String key) {
+
+ if (exprent.type == Exprent.EXPRENT_FUNCTION) {
+ FunctionExprent fparam = (FunctionExprent)exprent;
+ if (fparam.getFunctype() == FunctionExprent.FUNCTION_BOOLNOT &&
+ fparam.getLstOperands().get(0).type == Exprent.EXPRENT_FIELD) {
+ FieldExprent fdparam = (FieldExprent)fparam.getLstOperands().get(0);
+ if (classname.equals(fdparam.getClassname())
+ && key.equals(InterpreterUtil.makeUniqueKey(fdparam.getName(), fdparam.getDescriptor().descriptorString))) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/ClassReference14Processor.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/ClassReference14Processor.java
new file mode 100644
index 000000000000..3807d2e80a27
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/ClassReference14Processor.java
@@ -0,0 +1,296 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.main;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
+import org.jetbrains.java.decompiler.main.rels.ClassWrapper;
+import org.jetbrains.java.decompiler.main.rels.MethodWrapper;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
+import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectGraph;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.BasicBlockStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.CatchStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+import org.jetbrains.java.decompiler.struct.StructField;
+import org.jetbrains.java.decompiler.struct.StructMethod;
+import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import org.jetbrains.java.decompiler.util.VBStyleCollection;
+
+import java.util.*;
+import java.util.Map.Entry;
+
+public class ClassReference14Processor {
+
+ public ExitExprent bodyexprent;
+
+ public ExitExprent handlerexprent;
+
+
+ public ClassReference14Processor() {
+
+ InvocationExprent invfor = new InvocationExprent();
+ invfor.setName("forName");
+ invfor.setClassname("java/lang/Class");
+ invfor.setStringDescriptor("(Ljava/lang/String;)Ljava/lang/Class;");
+ invfor.setDescriptor(MethodDescriptor.parseDescriptor("(Ljava/lang/String;)Ljava/lang/Class;"));
+ invfor.setStatic(true);
+ invfor.setLstParameters(Arrays.asList(new Exprent[]{new VarExprent(0, VarType.VARTYPE_STRING, null)}));
+
+ bodyexprent = new ExitExprent(ExitExprent.EXIT_RETURN,
+ invfor,
+ VarType.VARTYPE_CLASS);
+
+ InvocationExprent constr = new InvocationExprent();
+ constr.setName("<init>");
+ constr.setClassname("java/lang/NoClassDefFoundError");
+ constr.setStringDescriptor("()V");
+ constr.setFunctype(InvocationExprent.TYP_INIT);
+ constr.setDescriptor(MethodDescriptor.parseDescriptor("()V"));
+
+ NewExprent newexpr =
+ new NewExprent(new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/NoClassDefFoundError"), new ArrayList<Exprent>());
+ newexpr.setConstructor(constr);
+
+ InvocationExprent invcause = new InvocationExprent();
+ invcause.setName("initCause");
+ invcause.setClassname("java/lang/NoClassDefFoundError");
+ invcause.setStringDescriptor("(Ljava/lang/Throwable;)Ljava/lang/Throwable;");
+ invcause.setDescriptor(MethodDescriptor.parseDescriptor("(Ljava/lang/Throwable;)Ljava/lang/Throwable;"));
+ invcause.setInstance(newexpr);
+ invcause.setLstParameters(
+ Arrays.asList(new Exprent[]{new VarExprent(2, new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/ClassNotFoundException"), null)}));
+
+ handlerexprent = new ExitExprent(ExitExprent.EXIT_THROW,
+ invcause,
+ null);
+ }
+
+
+ public void processClassReferences(ClassNode node) {
+
+ ClassWrapper wrapper = node.wrapper;
+
+ // int major_version = wrapper.getClassStruct().major_version;
+ // int minor_version = wrapper.getClassStruct().minor_version;
+ //
+ // if(major_version > 48 || (major_version == 48 && minor_version > 0)) {
+ // // version 1.5 or above
+ // return;
+ // }
+
+ if (wrapper.getClassStruct().isVersionGE_1_5()) {
+ // version 1.5 or above
+ return;
+ }
+
+ // find the synthetic method Class class$(String) if present
+ HashMap<ClassWrapper, MethodWrapper> mapClassMeths = new HashMap<ClassWrapper, MethodWrapper>();
+ mapClassMethods(node, mapClassMeths);
+
+ if (mapClassMeths.isEmpty()) {
+ return;
+ }
+
+ HashSet<ClassWrapper> setFound = new HashSet<ClassWrapper>();
+ processClassRec(node, mapClassMeths, setFound);
+
+ if (!setFound.isEmpty()) {
+ for (ClassWrapper wrp : setFound) {
+ StructMethod mt = mapClassMeths.get(wrp).methodStruct;
+ wrp.getHiddenMembers().add(InterpreterUtil.makeUniqueKey(mt.getName(), mt.getDescriptor()));
+ }
+ }
+ }
+
+ private static void processClassRec(ClassNode node,
+ final HashMap<ClassWrapper, MethodWrapper> mapClassMeths,
+ final HashSet<ClassWrapper> setFound) {
+
+ final ClassWrapper wrapper = node.wrapper;
+
+ // search code
+ for (MethodWrapper meth : wrapper.getMethods()) {
+
+ RootStatement root = meth.root;
+ if (root != null) {
+
+ DirectGraph graph = meth.getOrBuildGraph();
+
+ graph.iterateExprents(new DirectGraph.ExprentIterator() {
+ public int processExprent(Exprent exprent) {
+ for (Entry<ClassWrapper, MethodWrapper> ent : mapClassMeths.entrySet()) {
+ if (replaceInvocations(exprent, ent.getKey(), ent.getValue())) {
+ setFound.add(ent.getKey());
+ }
+ }
+ return 0;
+ }
+ });
+ }
+ }
+
+ // search initializers
+ for (int j = 0; j < 2; j++) {
+ VBStyleCollection<Exprent, String> initializers =
+ j == 0 ? wrapper.getStaticFieldInitializers() : wrapper.getDynamicFieldInitializers();
+
+ for (int i = 0; i < initializers.size(); i++) {
+ for (Entry<ClassWrapper, MethodWrapper> ent : mapClassMeths.entrySet()) {
+ Exprent exprent = initializers.get(i);
+ if (replaceInvocations(exprent, ent.getKey(), ent.getValue())) {
+ setFound.add(ent.getKey());
+ }
+
+ String cl = isClass14Invocation(exprent, ent.getKey(), ent.getValue());
+ if (cl != null) {
+ initializers.set(i, new ConstExprent(VarType.VARTYPE_CLASS, cl.replace('.', '/')));
+ setFound.add(ent.getKey());
+ }
+ }
+ }
+ }
+
+ // iterate nested classes
+ for (ClassNode nd : node.nested) {
+ processClassRec(nd, mapClassMeths, setFound);
+ }
+ }
+
+ private void mapClassMethods(ClassNode node, Map<ClassWrapper, MethodWrapper> map) {
+ boolean noSynthFlag = DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET);
+
+ ClassWrapper wrapper = node.wrapper;
+
+ for (MethodWrapper method : wrapper.getMethods()) {
+ StructMethod mt = method.methodStruct;
+
+ if ((noSynthFlag || mt.isSynthetic()) &&
+ mt.getDescriptor().equals("(Ljava/lang/String;)Ljava/lang/Class;") &&
+ mt.hasModifier(CodeConstants.ACC_STATIC)) {
+
+ RootStatement root = method.root;
+ if (root != null && root.getFirst().type == Statement.TYPE_TRYCATCH) {
+ CatchStatement cst = (CatchStatement)root.getFirst();
+ if (cst.getStats().size() == 2 && cst.getFirst().type == Statement.TYPE_BASICBLOCK &&
+ cst.getStats().get(1).type == Statement.TYPE_BASICBLOCK &&
+ cst.getVars().get(0).getVartype().equals(new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/ClassNotFoundException"))) {
+
+ BasicBlockStatement body = (BasicBlockStatement)cst.getFirst();
+ BasicBlockStatement handler = (BasicBlockStatement)cst.getStats().get(1);
+
+ if (body.getExprents().size() == 1 && handler.getExprents().size() == 1) {
+ if (bodyexprent.equals(body.getExprents().get(0)) &&
+ handlerexprent.equals(handler.getExprents().get(0))) {
+ map.put(wrapper, method);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // iterate nested classes
+ for (ClassNode nd : node.nested) {
+ mapClassMethods(nd, map);
+ }
+ }
+
+
+ private static boolean replaceInvocations(Exprent exprent, ClassWrapper wrapper, MethodWrapper meth) {
+
+ boolean res = false;
+
+ while (true) {
+
+ boolean found = false;
+
+ for (Exprent expr : exprent.getAllExprents()) {
+ String cl = isClass14Invocation(expr, wrapper, meth);
+ if (cl != null) {
+ exprent.replaceExprent(expr, new ConstExprent(VarType.VARTYPE_CLASS, cl.replace('.', '/')));
+ found = true;
+ res = true;
+ break;
+ }
+
+ res |= replaceInvocations(expr, wrapper, meth);
+ }
+
+ if (!found) {
+ break;
+ }
+ }
+
+ return res;
+ }
+
+
+ private static String isClass14Invocation(Exprent exprent, ClassWrapper wrapper, MethodWrapper meth) {
+
+ if (exprent.type == Exprent.EXPRENT_FUNCTION) {
+ FunctionExprent fexpr = (FunctionExprent)exprent;
+ if (fexpr.getFunctype() == FunctionExprent.FUNCTION_IIF) {
+ if (fexpr.getLstOperands().get(0).type == Exprent.EXPRENT_FUNCTION) {
+ FunctionExprent headexpr = (FunctionExprent)fexpr.getLstOperands().get(0);
+ if (headexpr.getFunctype() == FunctionExprent.FUNCTION_EQ) {
+ if (headexpr.getLstOperands().get(0).type == Exprent.EXPRENT_FIELD &&
+ headexpr.getLstOperands().get(1).type == Exprent.EXPRENT_CONST &&
+ ((ConstExprent)headexpr.getLstOperands().get(1)).getConsttype().equals(VarType.VARTYPE_NULL)) {
+
+ FieldExprent field = (FieldExprent)headexpr.getLstOperands().get(0);
+ ClassNode fieldnode = DecompilerContext.getClassProcessor().getMapRootClasses().get(field.getClassname());
+
+ if (fieldnode != null && fieldnode.classStruct.qualifiedName.equals(wrapper.getClassStruct().qualifiedName)) { // source class
+ StructField fd =
+ wrapper.getClassStruct().getField(field.getName(), field.getDescriptor().descriptorString); // FIXME: can be null! why??
+
+ if (fd != null && fd.hasModifier(CodeConstants.ACC_STATIC) &&
+ (fd.isSynthetic() || DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET))) {
+
+ if (fexpr.getLstOperands().get(1).type == Exprent.EXPRENT_ASSIGNMENT && fexpr.getLstOperands().get(2).equals(field)) {
+ AssignmentExprent asexpr = (AssignmentExprent)fexpr.getLstOperands().get(1);
+
+ if (asexpr.getLeft().equals(field) && asexpr.getRight().type == Exprent.EXPRENT_INVOCATION) {
+ InvocationExprent invexpr = (InvocationExprent)asexpr.getRight();
+
+ if (invexpr.getClassname().equals(wrapper.getClassStruct().qualifiedName) &&
+ invexpr.getName().equals(meth.methodStruct.getName()) &&
+ invexpr.getStringDescriptor().equals(meth.methodStruct.getDescriptor())) {
+
+ if (invexpr.getLstParameters().get(0).type == Exprent.EXPRENT_CONST) {
+ wrapper.getHiddenMembers()
+ .add(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor())); // hide synthetic field
+ return ((ConstExprent)invexpr.getLstParameters().get(0)).getValue().toString();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/ClassWriter.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/ClassWriter.java
new file mode 100644
index 000000000000..856ad225d0e1
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/ClassWriter.java
@@ -0,0 +1,987 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.main;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
+import org.jetbrains.java.decompiler.main.rels.ClassWrapper;
+import org.jetbrains.java.decompiler.main.rels.MethodWrapper;
+import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.AnnotationExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.ConstExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.NewExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarTypeProcessor;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar;
+import org.jetbrains.java.decompiler.modules.renamer.PoolInterceptor;
+import org.jetbrains.java.decompiler.struct.StructClass;
+import org.jetbrains.java.decompiler.struct.StructField;
+import org.jetbrains.java.decompiler.struct.StructMember;
+import org.jetbrains.java.decompiler.struct.StructMethod;
+import org.jetbrains.java.decompiler.struct.attr.*;
+import org.jetbrains.java.decompiler.struct.consts.PrimitiveConstant;
+import org.jetbrains.java.decompiler.struct.gen.FieldDescriptor;
+import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+import org.jetbrains.java.decompiler.struct.gen.generics.*;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+public class ClassWriter {
+
+ private ClassReference14Processor ref14processor;
+ private PoolInterceptor interceptor;
+
+ public ClassWriter() {
+ ref14processor = new ClassReference14Processor();
+ interceptor = DecompilerContext.getPoolInterceptor();
+ }
+
+ private void invokeProcessors(ClassNode node) {
+ ClassWrapper wrapper = node.wrapper;
+ StructClass cl = wrapper.getClassStruct();
+
+ InitializerProcessor.extractInitializers(wrapper);
+
+ if (node.type == ClassNode.CLASS_ROOT && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_CLASS_1_4)) {
+ ref14processor.processClassReferences(node);
+ }
+
+ if (cl.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM)) {
+ EnumProcessor.clearEnum(wrapper);
+ }
+
+ if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ASSERTIONS)) {
+ AssertProcessor.buildAssertions(node);
+ }
+ }
+
+ public void classLambdaToJava(ClassNode node, StringBuilder buffer, Exprent method_object, int indent) {
+ // get the class node with the content method
+ ClassNode classNode = node;
+ while (classNode != null && classNode.type == ClassNode.CLASS_LAMBDA) {
+ classNode = classNode.parent;
+ }
+ if (classNode == null) {
+ return;
+ }
+
+ boolean lambdaToAnonymous = DecompilerContext.getOption(IFernflowerPreferences.LAMBDA_TO_ANONYMOUS_CLASS);
+
+ ClassNode outerNode = (ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_NODE);
+ DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS_NODE, node);
+
+ try {
+ ClassWrapper wrapper = classNode.wrapper;
+ StructClass cl = wrapper.getClassStruct();
+
+ DecompilerContext.getLogger().startWriteClass(node.simpleName);
+
+ if (node.lambda_information.is_method_reference) {
+ if (!node.lambda_information.is_content_method_static && method_object != null) {
+ // reference to a virtual method
+ buffer.append(method_object.toJava(indent));
+ }
+ else {
+ // reference to a static method
+ buffer.append(ExprProcessor.getCastTypeName(new VarType(node.lambda_information.content_class_name, false)));
+ }
+
+ buffer.append("::");
+ buffer.append(node.lambda_information.content_method_name);
+ }
+ else {
+ // lambda method
+ StructMethod mt = cl.getMethod(node.lambda_information.content_method_key);
+ MethodWrapper methodWrapper = wrapper.getMethodWrapper(mt.getName(), mt.getDescriptor());
+ MethodDescriptor md_content = MethodDescriptor.parseDescriptor(node.lambda_information.content_method_descriptor);
+ MethodDescriptor md_lambda = MethodDescriptor.parseDescriptor(node.lambda_information.method_descriptor);
+
+ if (!lambdaToAnonymous) {
+ buffer.append('(');
+
+ boolean firstParameter = true;
+ int index = node.lambda_information.is_content_method_static ? 0 : 1;
+ int start_index = md_content.params.length - md_lambda.params.length;
+
+ for (int i = 0; i < md_content.params.length; i++) {
+ if (i >= start_index) {
+ if (!firstParameter) {
+ buffer.append(", ");
+ }
+
+ String parameterName = methodWrapper.varproc.getVarName(new VarVersionPaar(index, 0));
+ buffer.append(parameterName == null ? "param" + index : parameterName); // null iff decompiled with errors
+
+ firstParameter = false;
+ }
+
+ index += md_content.params[i].stack_size;
+ }
+
+ buffer.append(") ->");
+ }
+
+ buffer.append(" {");
+ buffer.append(DecompilerContext.getNewLineSeparator());
+
+ methodLambdaToJava(node, classNode, mt, buffer, indent + 1, !lambdaToAnonymous);
+
+ InterpreterUtil.appendIndent(buffer, indent);
+ buffer.append("}");
+ }
+ }
+ finally {
+ DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS_NODE, outerNode);
+ }
+
+ DecompilerContext.getLogger().endWriteClass();
+ }
+
+ public void classToJava(ClassNode node, StringBuilder buffer, int indent) {
+ ClassNode outerNode = (ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_NODE);
+ DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS_NODE, node);
+
+ try {
+ // last minute processing
+ invokeProcessors(node);
+
+ ClassWrapper wrapper = node.wrapper;
+ StructClass cl = wrapper.getClassStruct();
+
+ DecompilerContext.getLogger().startWriteClass(cl.qualifiedName);
+
+ String lineSeparator = DecompilerContext.getNewLineSeparator();
+
+ writeClassDefinition(node, buffer, indent);
+
+ boolean hasContent = false;
+
+ // fields
+ boolean enumFields = false;
+
+ for (StructField fd : cl.getFields()) {
+ boolean hide = fd.isSynthetic() && DecompilerContext.getOption(IFernflowerPreferences.REMOVE_SYNTHETIC) ||
+ wrapper.getHiddenMembers().contains(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor()));
+ if (hide) continue;
+
+ boolean isEnum = fd.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM);
+ if (isEnum) {
+ if (enumFields) {
+ buffer.append(',');
+ buffer.append(lineSeparator);
+ }
+ enumFields = true;
+ }
+ else if (enumFields) {
+ buffer.append(';');
+ buffer.append(lineSeparator);
+ buffer.append(lineSeparator);
+ enumFields = false;
+ }
+
+ fieldToJava(wrapper, cl, fd, buffer, indent + 1);
+
+ hasContent = true;
+ }
+
+ if (enumFields) {
+ buffer.append(';');
+ buffer.append(lineSeparator);
+ }
+
+ // methods
+ for (StructMethod mt : cl.getMethods()) {
+ boolean hide = mt.isSynthetic() && DecompilerContext.getOption(IFernflowerPreferences.REMOVE_SYNTHETIC) ||
+ mt.hasModifier(CodeConstants.ACC_BRIDGE) && DecompilerContext.getOption(IFernflowerPreferences.REMOVE_BRIDGE) ||
+ wrapper.getHiddenMembers().contains(InterpreterUtil.makeUniqueKey(mt.getName(), mt.getDescriptor()));
+ if (hide) continue;
+
+ int position = buffer.length();
+ if (hasContent) {
+ buffer.append(lineSeparator);
+ }
+ boolean methodSkipped = !methodToJava(node, mt, buffer, indent + 1);
+ if (!methodSkipped) {
+ hasContent = true;
+ }
+ else {
+ buffer.setLength(position);
+ }
+ }
+
+ // member classes
+ for (ClassNode inner : node.nested) {
+ if (inner.type == ClassNode.CLASS_MEMBER) {
+ StructClass innerCl = inner.classStruct;
+ boolean isSynthetic = (inner.access & CodeConstants.ACC_SYNTHETIC) != 0 || innerCl.isSynthetic();
+ boolean hide = isSynthetic && DecompilerContext.getOption(IFernflowerPreferences.REMOVE_SYNTHETIC) ||
+ wrapper.getHiddenMembers().contains(innerCl.qualifiedName);
+ if (hide) continue;
+
+ if (hasContent) {
+ buffer.append(lineSeparator);
+ }
+ classToJava(inner, buffer, indent + 1);
+
+ hasContent = true;
+ }
+ }
+
+ InterpreterUtil.appendIndent(buffer, indent);
+ buffer.append('}');
+
+ if (node.type != ClassNode.CLASS_ANONYMOUS) {
+ buffer.append(lineSeparator);
+ }
+ }
+ finally {
+ DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS_NODE, outerNode);
+ }
+
+ DecompilerContext.getLogger().endWriteClass();
+ }
+
+ private void writeClassDefinition(ClassNode node, StringBuilder buffer, int indent) {
+ String lineSeparator = DecompilerContext.getNewLineSeparator();
+ String indentString = InterpreterUtil.getIndentString(indent);
+
+ if (node.type == ClassNode.CLASS_ANONYMOUS) {
+ buffer.append(" {");
+ buffer.append(lineSeparator);
+ return;
+ }
+
+ ClassWrapper wrapper = node.wrapper;
+ StructClass cl = wrapper.getClassStruct();
+
+ int flags = node.type == ClassNode.CLASS_ROOT ? cl.getAccessFlags() : node.access;
+ boolean isDeprecated = cl.getAttributes().containsKey("Deprecated");
+ boolean isSynthetic = (flags & CodeConstants.ACC_SYNTHETIC) != 0 || cl.getAttributes().containsKey("Synthetic");
+ boolean isEnum = DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM) && (flags & CodeConstants.ACC_ENUM) != 0;
+ boolean isInterface = (flags & CodeConstants.ACC_INTERFACE) != 0;
+ boolean isAnnotation = (flags & CodeConstants.ACC_ANNOTATION) != 0;
+
+ if (isDeprecated) {
+ appendDeprecation(buffer, indentString, lineSeparator);
+ }
+
+ if (interceptor != null) {
+ String oldName = interceptor.getOldName(cl.qualifiedName);
+ appendRenameComment(buffer, oldName, MType.CLASS, indent, lineSeparator);
+ }
+
+ if (isSynthetic) {
+ appendComment(buffer, "synthetic class", indentString, lineSeparator);
+ }
+
+ appendAnnotations(buffer, cl, indent, lineSeparator);
+
+ buffer.append(indentString);
+
+ if (isEnum) {
+ // remove abstract and final flags (JLS 8.9 Enums)
+ flags &= ~CodeConstants.ACC_ABSTRACT;
+ flags &= ~CodeConstants.ACC_FINAL;
+ }
+
+ appendModifiers(buffer, flags, CLASS_ALLOWED, isInterface, CLASS_EXCLUDED);
+
+ if (isEnum) {
+ buffer.append("enum ");
+ }
+ else if (isInterface) {
+ if (isAnnotation) {
+ buffer.append('@');
+ }
+ buffer.append("interface ");
+ }
+ else {
+ buffer.append("class ");
+ }
+
+ GenericClassDescriptor descriptor = null;
+ if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) {
+ StructGenericSignatureAttribute attr = (StructGenericSignatureAttribute)cl.getAttributes().getWithKey("Signature");
+ if (attr != null) {
+ descriptor = GenericMain.parseClassSignature(attr.getSignature());
+ }
+ }
+
+ buffer.append(node.simpleName);
+
+ if (descriptor != null && !descriptor.fparameters.isEmpty()) {
+ appendTypeParameters(buffer, descriptor.fparameters, descriptor.fbounds);
+ }
+
+ buffer.append(' ');
+
+ if (!isEnum && !isInterface && cl.superClass != null) {
+ VarType supertype = new VarType(cl.superClass.getString(), true);
+ if (!VarType.VARTYPE_OBJECT.equals(supertype)) {
+ buffer.append("extends ");
+ if (descriptor != null) {
+ buffer.append(GenericMain.getGenericCastTypeName(descriptor.superclass));
+ }
+ else {
+ buffer.append(ExprProcessor.getCastTypeName(supertype));
+ }
+ buffer.append(' ');
+ }
+ }
+
+ if (!isAnnotation) {
+ int[] interfaces = cl.getInterfaces();
+ if (interfaces.length > 0) {
+ buffer.append(isInterface ? "extends " : "implements ");
+ for (int i = 0; i < interfaces.length; i++) {
+ if (i > 0) {
+ buffer.append(", ");
+ }
+ if (descriptor != null) {
+ buffer.append(GenericMain.getGenericCastTypeName(descriptor.superinterfaces.get(i)));
+ }
+ else {
+ buffer.append(ExprProcessor.getCastTypeName(new VarType(cl.getInterface(i), true)));
+ }
+ }
+ buffer.append(' ');
+ }
+ }
+
+ buffer.append('{');
+ buffer.append(lineSeparator);
+ }
+
+ private void fieldToJava(ClassWrapper wrapper, StructClass cl, StructField fd, StringBuilder buffer, int indent) {
+ String indentString = InterpreterUtil.getIndentString(indent);
+ String lineSeparator = DecompilerContext.getNewLineSeparator();
+
+ boolean isInterface = cl.hasModifier(CodeConstants.ACC_INTERFACE);
+ boolean isDeprecated = fd.getAttributes().containsKey("Deprecated");
+ boolean isEnum = fd.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM);
+
+ if (isDeprecated) {
+ appendDeprecation(buffer, indentString, lineSeparator);
+ }
+
+ if (interceptor != null) {
+ String oldName = interceptor.getOldName(cl.qualifiedName + " " + fd.getName() + " " + fd.getDescriptor());
+ appendRenameComment(buffer, oldName, MType.FIELD, indent, lineSeparator);
+ }
+
+ if (fd.isSynthetic()) {
+ appendComment(buffer, "synthetic field", indentString, lineSeparator);
+ }
+
+ appendAnnotations(buffer, fd, indent, lineSeparator);
+
+ buffer.append(indentString);
+
+ if (!isEnum) {
+ appendModifiers(buffer, fd.getAccessFlags(), FIELD_ALLOWED, isInterface, FIELD_EXCLUDED);
+ }
+
+ VarType fieldType = new VarType(fd.getDescriptor(), false);
+
+ GenericFieldDescriptor descriptor = null;
+ if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) {
+ StructGenericSignatureAttribute attr = (StructGenericSignatureAttribute)fd.getAttributes().getWithKey("Signature");
+ if (attr != null) {
+ descriptor = GenericMain.parseFieldSignature(attr.getSignature());
+ }
+ }
+
+ if (!isEnum) {
+ if (descriptor != null) {
+ buffer.append(GenericMain.getGenericCastTypeName(descriptor.type));
+ }
+ else {
+ buffer.append(ExprProcessor.getCastTypeName(fieldType));
+ }
+ buffer.append(' ');
+ }
+
+ buffer.append(fd.getName());
+
+ Exprent initializer;
+ if (fd.hasModifier(CodeConstants.ACC_STATIC)) {
+ initializer = wrapper.getStaticFieldInitializers().getWithKey(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor()));
+ }
+ else {
+ initializer = wrapper.getDynamicFieldInitializers().getWithKey(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor()));
+ }
+ if (initializer != null) {
+ if (isEnum && initializer.type == Exprent.EXPRENT_NEW) {
+ NewExprent nexpr = (NewExprent)initializer;
+ nexpr.setEnumconst(true);
+ buffer.append(nexpr.toJava(indent));
+ }
+ else {
+ buffer.append(" = ");
+ buffer.append(initializer.toJava(indent));
+ }
+ }
+ else if (fd.hasModifier(CodeConstants.ACC_FINAL) && fd.hasModifier(CodeConstants.ACC_STATIC)) {
+ StructConstantValueAttribute attr =
+ (StructConstantValueAttribute)fd.getAttributes().getWithKey(StructGeneralAttribute.ATTRIBUTE_CONSTANT_VALUE);
+ if (attr != null) {
+ PrimitiveConstant constant = cl.getPool().getPrimitiveConstant(attr.getIndex());
+ buffer.append(" = ");
+ buffer.append(new ConstExprent(fieldType, constant.value).toJava(indent));
+ }
+ }
+
+ if (!isEnum) {
+ buffer.append(";");
+ buffer.append(lineSeparator);
+ }
+ }
+
+ private static void methodLambdaToJava(ClassNode lambdaNode,
+ ClassNode classNode,
+ StructMethod mt,
+ StringBuilder buffer,
+ int indent,
+ boolean codeOnly) {
+ ClassWrapper classWrapper = classNode.wrapper;
+ MethodWrapper methodWrapper = classWrapper.getMethodWrapper(mt.getName(), mt.getDescriptor());
+
+ MethodWrapper outerWrapper = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER);
+ DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, methodWrapper);
+
+ try {
+ String method_name = lambdaNode.lambda_information.method_name;
+ MethodDescriptor md_content = MethodDescriptor.parseDescriptor(lambdaNode.lambda_information.content_method_descriptor);
+ MethodDescriptor md_lambda = MethodDescriptor.parseDescriptor(lambdaNode.lambda_information.method_descriptor);
+
+ if (!codeOnly) {
+ InterpreterUtil.appendIndent(buffer, indent);
+ buffer.append("public ");
+ buffer.append(method_name);
+ buffer.append("(");
+
+ boolean firstParameter = true;
+ int index = lambdaNode.lambda_information.is_content_method_static ? 0 : 1;
+ int start_index = md_content.params.length - md_lambda.params.length;
+
+ for (int i = 0; i < md_content.params.length; i++) {
+ if (i >= start_index) {
+ if (!firstParameter) {
+ buffer.append(", ");
+ }
+
+ String typeName = ExprProcessor.getCastTypeName(md_content.params[i].copy());
+ if (ExprProcessor.UNDEFINED_TYPE_STRING.equals(typeName) &&
+ DecompilerContext.getOption(IFernflowerPreferences.UNDEFINED_PARAM_TYPE_OBJECT)) {
+ typeName = ExprProcessor.getCastTypeName(VarType.VARTYPE_OBJECT);
+ }
+
+ buffer.append(typeName);
+ buffer.append(" ");
+
+ String parameterName = methodWrapper.varproc.getVarName(new VarVersionPaar(index, 0));
+ buffer.append(parameterName == null ? "param" + index : parameterName); // null iff decompiled with errors
+
+ firstParameter = false;
+ }
+
+ index += md_content.params[i].stack_size;
+ }
+
+ buffer.append(") {");
+ buffer.append(DecompilerContext.getNewLineSeparator());
+
+ indent += 1;
+ }
+
+ if (!methodWrapper.decompiledWithErrors) {
+ RootStatement root = classWrapper.getMethodWrapper(mt.getName(), mt.getDescriptor()).root;
+ if (root != null) { // check for existence
+ try {
+ buffer.append(root.toJava(indent));
+ }
+ catch (Throwable ex) {
+ DecompilerContext.getLogger().writeMessage("Method " + mt.getName() + " " + mt.getDescriptor() + " couldn't be written.", ex);
+ methodWrapper.decompiledWithErrors = true;
+ }
+ }
+ }
+
+ if (methodWrapper.decompiledWithErrors) {
+ InterpreterUtil.appendIndent(buffer, indent);
+ buffer.append("// $FF: Couldn't be decompiled");
+ buffer.append(DecompilerContext.getNewLineSeparator());
+ }
+
+ if (!codeOnly) {
+ indent -= 1;
+
+ InterpreterUtil.appendIndent(buffer, indent);
+ buffer.append('}');
+ buffer.append(DecompilerContext.getNewLineSeparator());
+ }
+ }
+ finally {
+ DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, outerWrapper);
+ }
+ }
+
+ private boolean methodToJava(ClassNode node, StructMethod mt, StringBuilder buffer, int indent) {
+ ClassWrapper wrapper = node.wrapper;
+ StructClass cl = wrapper.getClassStruct();
+ MethodWrapper methodWrapper = wrapper.getMethodWrapper(mt.getName(), mt.getDescriptor());
+
+ boolean hideMethod = false;
+
+ MethodWrapper outerWrapper = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER);
+ DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, methodWrapper);
+
+ try {
+ boolean isInterface = cl.hasModifier(CodeConstants.ACC_INTERFACE);
+ boolean isAnnotation = cl.hasModifier(CodeConstants.ACC_ANNOTATION);
+ boolean isEnum = cl.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM);
+ boolean isDeprecated = mt.getAttributes().containsKey("Deprecated");
+ boolean clinit = false, init = false, dinit = false;
+
+ String indentString = InterpreterUtil.getIndentString(indent);
+ String lineSeparator = DecompilerContext.getNewLineSeparator();
+
+ MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
+
+ int flags = mt.getAccessFlags();
+ if ((flags & CodeConstants.ACC_NATIVE) != 0) {
+ flags &= ~CodeConstants.ACC_STRICT; // compiler bug: a strictfp class sets all methods to strictfp
+ }
+ if ("<clinit>".equals(mt.getName())) {
+ flags &= CodeConstants.ACC_STATIC; // ignore all modifiers except 'static' in a static initializer
+ }
+
+ if (isDeprecated) {
+ appendDeprecation(buffer, indentString, lineSeparator);
+ }
+
+ if (interceptor != null) {
+ String oldName = interceptor.getOldName(cl.qualifiedName + " " + mt.getName() + " " + mt.getDescriptor());
+ appendRenameComment(buffer, oldName, MType.METHOD, indent, lineSeparator);
+ }
+
+ boolean isSynthetic = (flags & CodeConstants.ACC_SYNTHETIC) != 0 || mt.getAttributes().containsKey("Synthetic");
+ boolean isBridge = (flags & CodeConstants.ACC_BRIDGE) != 0;
+ if (isSynthetic) {
+ appendComment(buffer, "synthetic method", indentString, lineSeparator);
+ }
+ if (isBridge) {
+ appendComment(buffer, "bridge method", indentString, lineSeparator);
+ }
+
+ appendAnnotations(buffer, mt, indent, lineSeparator);
+
+ buffer.append(indentString);
+
+ appendModifiers(buffer, flags, METHOD_ALLOWED, isInterface, METHOD_EXCLUDED);
+
+ if (isInterface && mt.containsCode()) {
+ // 'default' modifier (Java 8)
+ buffer.append("default ");
+ }
+
+ String name = mt.getName();
+ if ("<init>".equals(name)) {
+ if (node.type == ClassNode.CLASS_ANONYMOUS) {
+ name = "";
+ dinit = true;
+ }
+ else {
+ name = node.simpleName;
+ init = true;
+ }
+ }
+ else if ("<clinit>".equals(name)) {
+ name = "";
+ clinit = true;
+ }
+
+ GenericMethodDescriptor descriptor = null;
+ if (DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES)) {
+ StructGenericSignatureAttribute attr = (StructGenericSignatureAttribute)mt.getAttributes().getWithKey("Signature");
+ if (attr != null) {
+ descriptor = GenericMain.parseMethodSignature(attr.getSignature());
+ if (descriptor != null) {
+ int actualParams = md.params.length;
+ if (isEnum && init) actualParams -= 2;
+ if (actualParams != descriptor.params.size()) {
+ String message = "Inconsistent generic signature in method " + mt.getName() + " " + mt.getDescriptor();
+ DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.WARN);
+ descriptor = null;
+ }
+ }
+ }
+ }
+
+ boolean throwsExceptions = false;
+ int paramCount = 0;
+
+ if (!clinit && !dinit) {
+ boolean thisVar = !mt.hasModifier(CodeConstants.ACC_STATIC);
+
+ if (descriptor != null && !descriptor.fparameters.isEmpty()) {
+ appendTypeParameters(buffer, descriptor.fparameters, descriptor.fbounds);
+ buffer.append(' ');
+ }
+
+ if (!init) {
+ if (descriptor != null) {
+ buffer.append(GenericMain.getGenericCastTypeName(descriptor.ret));
+ }
+ else {
+ buffer.append(ExprProcessor.getCastTypeName(md.ret));
+ }
+ buffer.append(' ');
+ }
+
+ buffer.append(name);
+ buffer.append('(');
+
+ // parameters
+ List<VarVersionPaar> signFields = methodWrapper.signatureFields;
+
+ int lastVisibleParameterIndex = -1;
+ for (int i = 0; i < md.params.length; i++) {
+ if (signFields == null || signFields.get(i) == null) {
+ lastVisibleParameterIndex = i;
+ }
+ }
+
+ boolean firstParameter = true;
+ int index = isEnum && init ? 3 : thisVar ? 1 : 0;
+ int start = isEnum && init && descriptor == null ? 2 : 0;
+ int params = descriptor == null ? md.params.length : descriptor.params.size();
+ for (int i = start; i < params; i++) {
+ if (signFields == null || signFields.get(i) == null) {
+ if (!firstParameter) {
+ buffer.append(", ");
+ }
+
+ appendParameterAnnotations(buffer, mt, paramCount);
+
+ if (methodWrapper.varproc.getVarFinal(new VarVersionPaar(index, 0)) == VarTypeProcessor.VAR_FINALEXPLICIT) {
+ buffer.append("final ");
+ }
+
+ if (descriptor != null) {
+ GenericType parameterType = descriptor.params.get(i);
+
+ boolean isVarArg = (i == lastVisibleParameterIndex && mt.hasModifier(CodeConstants.ACC_VARARGS) && parameterType.arraydim > 0);
+ if (isVarArg) {
+ parameterType.arraydim--;
+ }
+
+ String typeName = GenericMain.getGenericCastTypeName(parameterType);
+ if (ExprProcessor.UNDEFINED_TYPE_STRING.equals(typeName) &&
+ DecompilerContext.getOption(IFernflowerPreferences.UNDEFINED_PARAM_TYPE_OBJECT)) {
+ typeName = ExprProcessor.getCastTypeName(VarType.VARTYPE_OBJECT);
+ }
+
+ buffer.append(typeName);
+
+ if (isVarArg) {
+ buffer.append("...");
+ }
+ }
+ else {
+ VarType parameterType = md.params[i].copy();
+
+ boolean isVarArg = (i == lastVisibleParameterIndex && mt.hasModifier(CodeConstants.ACC_VARARGS) && parameterType.arraydim > 0);
+ if (isVarArg) {
+ parameterType.decArrayDim();
+ }
+
+ String typeName = ExprProcessor.getCastTypeName(parameterType);
+ if (ExprProcessor.UNDEFINED_TYPE_STRING.equals(typeName) &&
+ DecompilerContext.getOption(IFernflowerPreferences.UNDEFINED_PARAM_TYPE_OBJECT)) {
+ typeName = ExprProcessor.getCastTypeName(VarType.VARTYPE_OBJECT);
+ }
+
+ buffer.append(typeName);
+
+ if (isVarArg) {
+ buffer.append("...");
+ }
+ }
+
+ buffer.append(' ');
+ String parameterName = methodWrapper.varproc.getVarName(new VarVersionPaar(index, 0));
+ buffer.append(parameterName == null ? "param" + index : parameterName); // null iff decompiled with errors
+
+ firstParameter = false;
+ paramCount++;
+ }
+
+ index += md.params[i].stack_size;
+ }
+
+ buffer.append(')');
+
+ StructExceptionsAttribute attr = (StructExceptionsAttribute)mt.getAttributes().getWithKey("Exceptions");
+ if ((descriptor != null && !descriptor.exceptions.isEmpty()) || attr != null) {
+ throwsExceptions = true;
+ buffer.append(" throws ");
+
+ for (int i = 0; i < attr.getThrowsExceptions().size(); i++) {
+ if (i > 0) {
+ buffer.append(", ");
+ }
+ if (descriptor != null && !descriptor.exceptions.isEmpty()) {
+ GenericType type = descriptor.exceptions.get(i);
+ buffer.append(GenericMain.getGenericCastTypeName(type));
+ }
+ else {
+ VarType type = new VarType(attr.getExcClassname(i, cl.getPool()), true);
+ buffer.append(ExprProcessor.getCastTypeName(type));
+ }
+ }
+ }
+ }
+
+ if ((flags & (CodeConstants.ACC_ABSTRACT | CodeConstants.ACC_NATIVE)) != 0) { // native or abstract method (explicit or interface)
+ if (isAnnotation) {
+ StructAnnDefaultAttribute attr = (StructAnnDefaultAttribute)mt.getAttributes().getWithKey("AnnotationDefault");
+ if (attr != null) {
+ buffer.append(" default ");
+ buffer.append(attr.getDefaultValue().toJava(indent + 1));
+ }
+ }
+
+ buffer.append(';');
+ buffer.append(lineSeparator);
+ }
+ else {
+ if (!clinit && !dinit) {
+ buffer.append(' ');
+ }
+
+ buffer.append('{');
+ buffer.append(lineSeparator);
+
+ RootStatement root = wrapper.getMethodWrapper(mt.getName(), mt.getDescriptor()).root;
+
+ if (root != null && !methodWrapper.decompiledWithErrors) { // check for existence
+ try {
+ String code = root.toJava(indent + 1);
+
+ hideMethod = (clinit || dinit || hideConstructor(wrapper, init, throwsExceptions, paramCount)) && code.length() == 0;
+
+ buffer.append(code);
+ }
+ catch (Throwable ex) {
+ DecompilerContext.getLogger().writeMessage("Method " + mt.getName() + " " + mt.getDescriptor() + " couldn't be written.", ex);
+ methodWrapper.decompiledWithErrors = true;
+ }
+ }
+
+ if (methodWrapper.decompiledWithErrors) {
+ buffer.append(InterpreterUtil.getIndentString(indent + 1));
+ buffer.append("// $FF: Couldn't be decompiled");
+ buffer.append(lineSeparator);
+ }
+
+ buffer.append(indentString);
+ buffer.append('}');
+ buffer.append(lineSeparator);
+ }
+ }
+ finally {
+ DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_WRAPPER, outerWrapper);
+ }
+
+ return !hideMethod;
+ }
+
+ private static boolean hideConstructor(ClassWrapper wrapper, boolean init, boolean throwsExceptions, int paramCount) {
+ if (!init || throwsExceptions || paramCount > 0 || !DecompilerContext.getOption(IFernflowerPreferences.HIDE_DEFAULT_CONSTRUCTOR)) {
+ return false;
+ }
+
+ int count = 0;
+ for (StructMethod mt : wrapper.getClassStruct().getMethods()) {
+ if ("<init>".equals(mt.getName())) {
+ if (++count > 1) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ private static void appendDeprecation(StringBuilder buffer, String indentString, String lineSeparator) {
+ buffer.append(indentString).append("/** @deprecated */").append(lineSeparator);
+ }
+
+ private enum MType {CLASS, FIELD, METHOD}
+
+ private static void appendRenameComment(StringBuilder buffer, String oldName, MType type, int indent, String lineSeparator) {
+ if (oldName == null) return;
+
+ InterpreterUtil.appendIndent(buffer, indent);
+ buffer.append("// $FF: renamed from: ");
+
+ switch (type) {
+ case CLASS:
+ buffer.append(ExprProcessor.buildJavaClassName(oldName));
+ break;
+
+ case FIELD:
+ String[] fParts = oldName.split(" ");
+ FieldDescriptor fd = FieldDescriptor.parseDescriptor(fParts[2]);
+ buffer.append(fParts[1]);
+ buffer.append(' ');
+ buffer.append(getTypePrintOut(fd.type));
+ break;
+
+ default:
+ String[] mParts = oldName.split(" ");
+ MethodDescriptor md = MethodDescriptor.parseDescriptor(mParts[2]);
+ buffer.append(mParts[1]);
+ buffer.append(" (");
+ boolean first = true;
+ for (VarType paramType : md.params) {
+ if (!first) {
+ buffer.append(", ");
+ }
+ first = false;
+ buffer.append(getTypePrintOut(paramType));
+ }
+ buffer.append(") ");
+ buffer.append(getTypePrintOut(md.ret));
+ }
+
+ buffer.append(lineSeparator);
+ }
+
+ private static String getTypePrintOut(VarType type) {
+ String typeText = ExprProcessor.getCastTypeName(type, false);
+ if (ExprProcessor.UNDEFINED_TYPE_STRING.equals(typeText) &&
+ DecompilerContext.getOption(IFernflowerPreferences.UNDEFINED_PARAM_TYPE_OBJECT)) {
+ typeText = ExprProcessor.getCastTypeName(VarType.VARTYPE_OBJECT, false);
+ }
+ return typeText;
+ }
+
+ private static void appendComment(StringBuilder buffer, String comment, String indentString, String lineSeparator) {
+ buffer.append(indentString).append("// $FF: ").append(comment).append(lineSeparator);
+ }
+
+ private static final String[] ANNOTATION_ATTRIBUTES = {
+ StructGeneralAttribute.ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS, StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS};
+
+ private static void appendAnnotations(StringBuilder buffer, StructMember mb, int indent, String lineSeparator) {
+ for (String name : ANNOTATION_ATTRIBUTES) {
+ StructAnnotationAttribute attribute = (StructAnnotationAttribute)mb.getAttributes().getWithKey(name);
+ if (attribute != null) {
+ for (AnnotationExprent annotation : attribute.getAnnotations()) {
+ buffer.append(annotation.toJava(indent)).append(lineSeparator);
+ }
+ }
+ }
+ }
+
+ private static final String[] PARAMETER_ANNOTATION_ATTRIBUTES = {
+ StructGeneralAttribute.ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS, StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS};
+
+ private static void appendParameterAnnotations(StringBuilder buffer, StructMethod mt, int param) {
+ for (String name : PARAMETER_ANNOTATION_ATTRIBUTES) {
+ StructAnnotationParameterAttribute attribute = (StructAnnotationParameterAttribute)mt.getAttributes().getWithKey(name);
+ if (attribute != null) {
+ List<List<AnnotationExprent>> annotations = attribute.getParamAnnotations();
+ if (param < annotations.size()) {
+ for (AnnotationExprent annotation : annotations.get(param)) {
+ buffer.append(annotation.toJava(0)).append(' ');
+ }
+ }
+ }
+ }
+ }
+
+ private static final Map<Integer, String> MODIFIERS = new LinkedHashMap<Integer, String>() {{
+ put(CodeConstants.ACC_PUBLIC, "public");
+ put(CodeConstants.ACC_PROTECTED, "protected");
+ put(CodeConstants.ACC_PRIVATE, "private");
+ put(CodeConstants.ACC_ABSTRACT, "abstract");
+ put(CodeConstants.ACC_STATIC, "static");
+ put(CodeConstants.ACC_FINAL, "final");
+ put(CodeConstants.ACC_STRICT, "strictfp");
+ put(CodeConstants.ACC_TRANSIENT, "transient");
+ put(CodeConstants.ACC_VOLATILE, "volatile");
+ put(CodeConstants.ACC_SYNCHRONIZED, "synchronized");
+ put(CodeConstants.ACC_NATIVE, "native");
+ }};
+
+ private static final int CLASS_ALLOWED =
+ CodeConstants.ACC_PUBLIC | CodeConstants.ACC_PROTECTED | CodeConstants.ACC_PRIVATE | CodeConstants.ACC_ABSTRACT |
+ CodeConstants.ACC_STATIC | CodeConstants.ACC_FINAL | CodeConstants.ACC_STRICT;
+ private static final int FIELD_ALLOWED =
+ CodeConstants.ACC_PUBLIC | CodeConstants.ACC_PROTECTED | CodeConstants.ACC_PRIVATE | CodeConstants.ACC_STATIC |
+ CodeConstants.ACC_FINAL | CodeConstants.ACC_TRANSIENT | CodeConstants.ACC_VOLATILE;
+ private static final int METHOD_ALLOWED =
+ CodeConstants.ACC_PUBLIC | CodeConstants.ACC_PROTECTED | CodeConstants.ACC_PRIVATE | CodeConstants.ACC_ABSTRACT |
+ CodeConstants.ACC_STATIC | CodeConstants.ACC_FINAL | CodeConstants.ACC_SYNCHRONIZED | CodeConstants.ACC_NATIVE | CodeConstants.ACC_STRICT;
+
+ private static final int CLASS_EXCLUDED = CodeConstants.ACC_ABSTRACT | CodeConstants.ACC_STATIC;
+ private static final int FIELD_EXCLUDED = CodeConstants.ACC_PUBLIC | CodeConstants.ACC_STATIC | CodeConstants.ACC_FINAL;
+ private static final int METHOD_EXCLUDED = CodeConstants.ACC_PUBLIC | CodeConstants.ACC_ABSTRACT;
+
+ private static void appendModifiers(StringBuilder buffer, int flags, int allowed, boolean isInterface, int excluded) {
+ flags &= allowed;
+ if (!isInterface) excluded = 0;
+ for (int modifier : MODIFIERS.keySet()) {
+ if ((flags & modifier) == modifier && (modifier & excluded) == 0) {
+ buffer.append(MODIFIERS.get(modifier)).append(' ');
+ }
+ }
+ }
+
+ private static void appendTypeParameters(StringBuilder buffer, List<String> parameters, List<List<GenericType>> bounds) {
+ buffer.append('<');
+
+ for (int i = 0; i < parameters.size(); i++) {
+ if (i > 0) {
+ buffer.append(", ");
+ }
+
+ buffer.append(parameters.get(i));
+
+ List<GenericType> parameterBounds = bounds.get(i);
+ if (parameterBounds.size() > 1 || !"java/lang/Object".equals(parameterBounds.get(0).value)) {
+ buffer.append(" extends ");
+ buffer.append(GenericMain.getGenericCastTypeName(parameterBounds.get(0)));
+ for (int j = 1; j < parameterBounds.size(); j++) {
+ buffer.append(" & ");
+ buffer.append(GenericMain.getGenericCastTypeName(parameterBounds.get(j)));
+ }
+ }
+ }
+
+ buffer.append('>');
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java
new file mode 100644
index 000000000000..6faad08ae09e
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/ClassesProcessor.java
@@ -0,0 +1,431 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.main;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
+import org.jetbrains.java.decompiler.main.collectors.ImportCollector;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
+import org.jetbrains.java.decompiler.main.extern.IIdentifierRenamer;
+import org.jetbrains.java.decompiler.main.rels.ClassWrapper;
+import org.jetbrains.java.decompiler.main.rels.LambdaProcessor;
+import org.jetbrains.java.decompiler.main.rels.NestedClassProcessor;
+import org.jetbrains.java.decompiler.main.rels.NestedMemberAccess;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.InvocationExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar;
+import org.jetbrains.java.decompiler.struct.StructClass;
+import org.jetbrains.java.decompiler.struct.StructContext;
+import org.jetbrains.java.decompiler.struct.StructMethod;
+import org.jetbrains.java.decompiler.struct.attr.StructInnerClassesAttribute;
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+
+import java.io.IOException;
+import java.util.*;
+import java.util.Map.Entry;
+
+public class ClassesProcessor {
+
+ private Map<String, ClassNode> mapRootClasses = new HashMap<String, ClassNode>();
+
+ public ClassesProcessor(StructContext context) {
+
+ HashMap<String, Object[]> mapInnerClasses = new HashMap<String, Object[]>();
+
+ HashMap<String, HashSet<String>> mapNestedClassReferences = new HashMap<String, HashSet<String>>();
+ HashMap<String, HashSet<String>> mapEnclosingClassReferences = new HashMap<String, HashSet<String>>();
+
+ HashMap<String, String> mapNewSimpleNames = new HashMap<String, String>();
+
+ boolean bDecompileInner = DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_INNER);
+
+ // create class nodes
+ for (StructClass cl : context.getClasses().values()) {
+ if (cl.isOwn() && !mapRootClasses.containsKey(cl.qualifiedName)) {
+
+ if (bDecompileInner) {
+ StructInnerClassesAttribute inner = (StructInnerClassesAttribute)cl.getAttributes().getWithKey("InnerClasses");
+ if (inner != null) {
+
+ for (int i = 0; i < inner.getClassEntries().size(); i++) {
+
+ int[] entry = inner.getClassEntries().get(i);
+ String[] strentry = inner.getStringEntries().get(i);
+
+ Object[] arr = new Object[4]; // arr[0] not used
+
+ String innername = strentry[0];
+
+ // nested class type
+ arr[2] = entry[1] == 0 ? (entry[2] == 0 ? ClassNode.CLASS_ANONYMOUS : ClassNode.CLASS_LOCAL) : ClassNode.CLASS_MEMBER;
+
+ // original simple name
+ String simpleName = strentry[2];
+ String savedName = mapNewSimpleNames.get(innername);
+
+ if (savedName != null) {
+ simpleName = savedName;
+ }
+ else if (simpleName != null && DecompilerContext.getOption(IFernflowerPreferences.RENAME_ENTITIES)) {
+ IIdentifierRenamer renamer = DecompilerContext.getPoolInterceptor().getHelper();
+ if (renamer.toBeRenamed(IIdentifierRenamer.ELEMENT_CLASS, simpleName, null, null)) {
+ simpleName = renamer.getNextClassname(innername, simpleName);
+ mapNewSimpleNames.put(innername, simpleName);
+ }
+ }
+
+ arr[1] = simpleName;
+
+ // original access flags
+ arr[3] = entry[3];
+
+ // enclosing class
+ String enclClassName;
+ if (entry[1] != 0) {
+ enclClassName = strentry[1];
+ }
+ else {
+ enclClassName = cl.qualifiedName;
+ }
+
+ if (!innername.equals(enclClassName)) { // self reference
+ StructClass enclosing_class = context.getClasses().get(enclClassName);
+ if (enclosing_class != null && enclosing_class.isOwn()) { // own classes only
+
+ Object[] arrold = mapInnerClasses.get(innername);
+ if (arrold == null) {
+ mapInnerClasses.put(innername, arr);
+ }
+ else {
+ if (!InterpreterUtil.equalObjectArrays(arrold, arr)) {
+ DecompilerContext.getLogger()
+ .writeMessage("Inconsistent inner class entries for " + innername + "!", IFernflowerLogger.Severity.WARN);
+ }
+ }
+
+ // reference to the nested class
+ HashSet<String> set = mapNestedClassReferences.get(enclClassName);
+ if (set == null) {
+ mapNestedClassReferences.put(enclClassName, set = new HashSet<String>());
+ }
+ set.add(innername);
+
+ // reference to the enclosing class
+ set = mapEnclosingClassReferences.get(innername);
+ if (set == null) {
+ mapEnclosingClassReferences.put(innername, set = new HashSet<String>());
+ }
+ set.add(enclClassName);
+ }
+ }
+ }
+ }
+ }
+
+ ClassNode node = new ClassNode(ClassNode.CLASS_ROOT, cl);
+ node.access = cl.getAccessFlags();
+ mapRootClasses.put(cl.qualifiedName, node);
+ }
+ }
+
+ if (bDecompileInner) {
+
+ // connect nested classes
+ for (Entry<String, ClassNode> ent : mapRootClasses.entrySet()) {
+ // root class?
+ if (!mapInnerClasses.containsKey(ent.getKey())) {
+
+ HashSet<String> setVisited = new HashSet<String>();
+ LinkedList<String> stack = new LinkedList<String>();
+
+ stack.add(ent.getKey());
+ setVisited.add(ent.getKey());
+
+ while (!stack.isEmpty()) {
+
+ String superClass = stack.removeFirst();
+ ClassNode supernode = mapRootClasses.get(superClass);
+
+ HashSet<String> setNestedClasses = mapNestedClassReferences.get(superClass);
+ if (setNestedClasses != null) {
+
+ StructClass scl = supernode.classStruct;
+ StructInnerClassesAttribute inner = (StructInnerClassesAttribute)scl.getAttributes().getWithKey("InnerClasses");
+ for (int i = 0; i < inner.getStringEntries().size(); i++) {
+ String nestedClass = inner.getStringEntries().get(i)[0];
+ if (!setNestedClasses.contains(nestedClass)) {
+ continue;
+ }
+
+ if (setVisited.contains(nestedClass)) {
+ continue;
+ }
+ setVisited.add(nestedClass);
+
+ ClassNode nestednode = mapRootClasses.get(nestedClass);
+ if (nestednode == null) {
+ DecompilerContext.getLogger().writeMessage("Nested class " + nestedClass + " missing!",
+ IFernflowerLogger.Severity.WARN);
+ continue;
+ }
+
+ Object[] arr = mapInnerClasses.get(nestedClass);
+
+ //if ((Integer)arr[2] == ClassNode.CLASS_MEMBER) {
+ // FIXME: check for consistent naming
+ //}
+
+ nestednode.type = (Integer)arr[2];
+ nestednode.simpleName = (String)arr[1];
+ nestednode.access = (Integer)arr[3];
+
+ if (nestednode.type == ClassNode.CLASS_ANONYMOUS) {
+ StructClass cl = nestednode.classStruct;
+
+ // remove static if anonymous class
+ // a common compiler bug
+ nestednode.access &= ~CodeConstants.ACC_STATIC;
+
+ int[] interfaces = cl.getInterfaces();
+
+ if (interfaces.length > 0) {
+ if (interfaces.length > 1) {
+ DecompilerContext.getLogger()
+ .writeMessage("Inconsistent anonymous class definition: " + cl.qualifiedName, IFernflowerLogger.Severity.WARN);
+ }
+ nestednode.anonimousClassType = new VarType(cl.getInterface(0), true);
+ }
+ else {
+ nestednode.anonimousClassType = new VarType(cl.superClass.getString(), true);
+ }
+ }
+ else if (nestednode.type == ClassNode.CLASS_LOCAL) {
+ // only abstract and final are permitted
+ // a common compiler bug
+ nestednode.access &= (CodeConstants.ACC_ABSTRACT | CodeConstants.ACC_FINAL);
+ }
+
+ supernode.nested.add(nestednode);
+ nestednode.parent = supernode;
+
+ nestednode.enclosingClasses.addAll(mapEnclosingClassReferences.get(nestedClass));
+
+ stack.add(nestedClass);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public void writeClass(StructClass cl, StringBuilder buffer) throws IOException {
+ ClassNode root = mapRootClasses.get(cl.qualifiedName);
+ if (root.type != ClassNode.CLASS_ROOT) {
+ return;
+ }
+
+ try {
+ ImportCollector importCollector = new ImportCollector(root);
+ DecompilerContext.setImportCollector(importCollector);
+ DecompilerContext.setCounterContainer(new CounterContainer());
+
+ new LambdaProcessor().processClass(root);
+
+ // add simple class names to implicit import
+ addClassnameToImport(root, importCollector);
+
+ // build wrappers for all nested classes (that's where actual processing takes place)
+ initWrappers(root);
+
+ new NestedClassProcessor().processClass(root, root);
+
+ new NestedMemberAccess().propagateMemberAccess(root);
+
+ StringBuilder classBuffer = new StringBuilder();
+ new ClassWriter().classToJava(root, classBuffer, 0);
+
+ String lineSeparator = DecompilerContext.getNewLineSeparator();
+
+ int index = cl.qualifiedName.lastIndexOf("/");
+ if (index >= 0) {
+ String packageName = cl.qualifiedName.substring(0, index).replace('/', '.');
+ buffer.append("package ");
+ buffer.append(packageName);
+ buffer.append(";");
+ buffer.append(lineSeparator);
+ buffer.append(lineSeparator);
+ }
+
+ if (importCollector.writeImports(buffer)) {
+ buffer.append(lineSeparator);
+ }
+
+ buffer.append(classBuffer);
+ }
+ finally {
+ destroyWrappers(root);
+ }
+ }
+
+ private static void initWrappers(ClassNode node) throws IOException {
+
+ if (node.type == ClassNode.CLASS_LAMBDA) {
+ return;
+ }
+
+ ClassWrapper wrapper = new ClassWrapper(node.classStruct);
+ wrapper.init();
+
+ node.wrapper = wrapper;
+
+ for (ClassNode nd : node.nested) {
+ initWrappers(nd);
+ }
+ }
+
+ private static void addClassnameToImport(ClassNode node, ImportCollector imp) {
+
+ if (node.simpleName != null && node.simpleName.length() > 0) {
+ imp.getShortName(node.type == ClassNode.CLASS_ROOT ? node.classStruct.qualifiedName : node.simpleName, false);
+ }
+
+ for (ClassNode nd : node.nested) {
+ addClassnameToImport(nd, imp);
+ }
+ }
+
+ private static void destroyWrappers(ClassNode node) {
+
+ node.wrapper = null;
+ node.classStruct.releaseResources();
+
+ for (ClassNode nd : node.nested) {
+ destroyWrappers(nd);
+ }
+ }
+
+ public Map<String, ClassNode> getMapRootClasses() {
+ return mapRootClasses;
+ }
+
+
+ public static class ClassNode {
+
+ public static final int CLASS_ROOT = 0;
+ public static final int CLASS_MEMBER = 1;
+ public static final int CLASS_ANONYMOUS = 2;
+ public static final int CLASS_LOCAL = 4;
+ public static final int CLASS_LAMBDA = 8;
+
+ public int type;
+
+ public int access;
+
+ public String simpleName;
+
+ public StructClass classStruct;
+
+ public ClassWrapper wrapper;
+
+ public String enclosingMethod;
+
+ public InvocationExprent superInvocation;
+
+ public HashMap<String, VarVersionPaar> mapFieldsToVars = new HashMap<String, VarVersionPaar>();
+
+ public VarType anonimousClassType;
+
+ public List<ClassNode> nested = new ArrayList<ClassNode>();
+
+ public Set<String> enclosingClasses = new HashSet<String>();
+
+ public ClassNode parent;
+
+ public LambdaInformation lambda_information;
+
+ public ClassNode(String content_class_name,
+ String content_method_name,
+ String content_method_descriptor,
+ int content_method_invocation_type,
+ String lambda_class_name,
+ String lambda_method_name,
+ String lambda_method_descriptor,
+ StructClass classStruct) { // lambda class constructor
+ this.type = CLASS_LAMBDA;
+ this.classStruct = classStruct; // 'parent' class containing the static function
+
+ lambda_information = new LambdaInformation();
+
+ lambda_information.class_name = lambda_class_name;
+ lambda_information.method_name = lambda_method_name;
+ lambda_information.method_descriptor = lambda_method_descriptor;
+
+ lambda_information.content_class_name = content_class_name;
+ lambda_information.content_method_name = content_method_name;
+ lambda_information.content_method_descriptor = content_method_descriptor;
+ lambda_information.content_method_invocation_type = content_method_invocation_type;
+
+ lambda_information.content_method_key =
+ InterpreterUtil.makeUniqueKey(lambda_information.content_method_name, lambda_information.content_method_descriptor);
+
+ anonimousClassType = new VarType(lambda_class_name, true);
+
+ boolean is_method_reference = (content_class_name != classStruct.qualifiedName);
+ if (!is_method_reference) { // content method in the same class, check synthetic flag
+ StructMethod mt = classStruct.getMethod(content_method_name, content_method_descriptor);
+ is_method_reference = !mt.isSynthetic(); // if not synthetic -> method reference
+ }
+
+ lambda_information.is_method_reference = is_method_reference;
+ lambda_information.is_content_method_static =
+ (lambda_information.content_method_invocation_type == CodeConstants.CONSTANT_MethodHandle_REF_invokeStatic); // FIXME: redundant?
+ }
+
+ public ClassNode(int type, StructClass classStruct) {
+ this.type = type;
+ this.classStruct = classStruct;
+
+ simpleName = classStruct.qualifiedName.substring(classStruct.qualifiedName.lastIndexOf('/') + 1);
+ }
+
+ public ClassNode getClassNode(String qualifiedName) {
+ for (ClassNode node : nested) {
+ if (qualifiedName.equals(node.classStruct.qualifiedName)) {
+ return node;
+ }
+ }
+ return null;
+ }
+
+ public static class LambdaInformation {
+ public String class_name;
+ public String method_name;
+ public String method_descriptor;
+
+ public String content_class_name;
+ public String content_method_name;
+ public String content_method_descriptor;
+ public int content_method_invocation_type; // values from CONSTANT_MethodHandle_REF_*
+
+ public String content_method_key;
+
+ public boolean is_method_reference;
+ public boolean is_content_method_static;
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/DecompilerContext.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/DecompilerContext.java
new file mode 100644
index 000000000000..b600250d0b78
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/DecompilerContext.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.main;
+
+import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
+import org.jetbrains.java.decompiler.main.collectors.ImportCollector;
+import org.jetbrains.java.decompiler.main.collectors.VarNamesCollector;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
+import org.jetbrains.java.decompiler.modules.renamer.PoolInterceptor;
+import org.jetbrains.java.decompiler.struct.StructContext;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+public class DecompilerContext {
+ public static final String CURRENT_CLASS = "CURRENT_CLASS";
+ public static final String CURRENT_CLASS_NODE = "CURRENT_CLASS_NODE";
+ public static final String CURRENT_METHOD = "CURRENT_METHOD";
+ public static final String CURRENT_METHOD_DESCRIPTOR = "CURRENT_METHOD_DESCRIPTOR";
+ public static final String CURRENT_METHOD_WRAPPER = "CURRENT_METHOD_WRAPPER";
+ public static final String CURRENT_VAR_PROCESSOR = "CURRENT_VAR_PROCESSOR";
+
+ private static ThreadLocal<DecompilerContext> currentContext = new ThreadLocal<DecompilerContext>();
+
+ private final Map<String, Object> properties;
+ private StructContext structContext;
+ private ImportCollector importCollector;
+ private VarNamesCollector varNamescollector;
+ private CounterContainer counterContainer;
+ private ClassesProcessor classProcessor;
+ private PoolInterceptor poolInterceptor;
+ private IFernflowerLogger logger;
+
+ private DecompilerContext(Map<String, Object> properties) {
+ this.properties = properties;
+ }
+
+ public static void initContext(Map<String, Object> propertiesCustom) {
+ Map<String, Object> properties = new HashMap<String, Object>(IFernflowerPreferences.DEFAULTS);
+ if (propertiesCustom != null) {
+ properties.putAll(propertiesCustom);
+ }
+ currentContext.set(new DecompilerContext(properties));
+ }
+
+ public static DecompilerContext getCurrentContext() {
+ return currentContext.get();
+ }
+
+ public static void setCurrentContext(DecompilerContext context) {
+ currentContext.set(context);
+ }
+
+ public static Object getProperty(String key) {
+ return getCurrentContext().properties.get(key);
+ }
+
+ public static void setProperty(String key, Object value) {
+ getCurrentContext().properties.put(key, value);
+ }
+
+ public static boolean getOption(String key) {
+ return "1".equals(getCurrentContext().properties.get(key));
+ }
+
+ public static ImportCollector getImportCollector() {
+ return getCurrentContext().importCollector;
+ }
+
+ public static void setImportCollector(ImportCollector importCollector) {
+ getCurrentContext().importCollector = importCollector;
+ }
+
+ public static VarNamesCollector getVarNamesCollector() {
+ return getCurrentContext().varNamescollector;
+ }
+
+ public static void setVarNamesCollector(VarNamesCollector varNamesCollector) {
+ getCurrentContext().varNamescollector = varNamesCollector;
+ }
+
+ public static StructContext getStructContext() {
+ return getCurrentContext().structContext;
+ }
+
+ public static void setStructContext(StructContext structContext) {
+ getCurrentContext().structContext = structContext;
+ }
+
+ public static CounterContainer getCounterContainer() {
+ return getCurrentContext().counterContainer;
+ }
+
+ public static void setCounterContainer(CounterContainer counterContainer) {
+ getCurrentContext().counterContainer = counterContainer;
+ }
+
+ public static ClassesProcessor getClassProcessor() {
+ return getCurrentContext().classProcessor;
+ }
+
+ public static void setClassProcessor(ClassesProcessor classProcessor) {
+ getCurrentContext().classProcessor = classProcessor;
+ }
+
+ public static PoolInterceptor getPoolInterceptor() {
+ return getCurrentContext().poolInterceptor;
+ }
+
+ public static void setPoolInterceptor(PoolInterceptor poolinterceptor) {
+ getCurrentContext().poolInterceptor = poolinterceptor;
+ }
+
+ public static IFernflowerLogger getLogger() {
+ return getCurrentContext().logger;
+ }
+
+ public static void setLogger(IFernflowerLogger logger) {
+ if (logger != null) {
+ String level = (String)getProperty(IFernflowerPreferences.LOG_LEVEL);
+ if (level != null) {
+ try {
+ logger.setSeverity(IFernflowerLogger.Severity.valueOf(level.toUpperCase(Locale.US)));
+ }
+ catch (IllegalArgumentException ignore) { }
+ }
+ }
+ getCurrentContext().logger = logger;
+ }
+
+ public static String getNewLineSeparator() {
+ return getOption(IFernflowerPreferences.NEW_LINE_SEPARATOR) ?
+ IFernflowerPreferences.LINE_SEPARATOR_LIN : IFernflowerPreferences.LINE_SEPARATOR_WIN;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/EnumProcessor.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/EnumProcessor.java
new file mode 100644
index 000000000000..be408e8bbc3b
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/EnumProcessor.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.main;
+
+import org.jetbrains.java.decompiler.main.rels.ClassWrapper;
+import org.jetbrains.java.decompiler.main.rels.MethodWrapper;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.InvocationExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar;
+import org.jetbrains.java.decompiler.struct.StructClass;
+import org.jetbrains.java.decompiler.struct.StructField;
+import org.jetbrains.java.decompiler.struct.StructMethod;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+
+public class EnumProcessor {
+
+ public static void clearEnum(ClassWrapper wrapper) {
+ StructClass cl = wrapper.getClassStruct();
+
+ // hide values/valueOf methods and super() invocations
+ for (MethodWrapper method : wrapper.getMethods()) {
+ StructMethod mt = method.methodStruct;
+ String name = mt.getName();
+ String descriptor = mt.getDescriptor();
+
+ if ("values".equals(name)) {
+ if (descriptor.equals("()[L" + cl.qualifiedName + ";")) {
+ wrapper.getHiddenMembers().add(InterpreterUtil.makeUniqueKey(name, descriptor));
+ }
+ }
+ else if ("valueOf".equals(name)) {
+ if (descriptor.equals("(Ljava/lang/String;)L" + cl.qualifiedName + ";")) {
+ wrapper.getHiddenMembers().add(InterpreterUtil.makeUniqueKey(name, descriptor));
+ }
+ }
+ else if ("<init>".equals(name)) {
+ Statement firstData = findFirstData(method.root);
+ if (firstData != null && !firstData.getExprents().isEmpty()) {
+ Exprent exprent = firstData.getExprents().get(0);
+ if (exprent.type == Exprent.EXPRENT_INVOCATION) {
+ InvocationExprent invexpr = (InvocationExprent)exprent;
+ if (isInvocationSuperConstructor(invexpr, method, wrapper)) {
+ firstData.getExprents().remove(0);
+ }
+ }
+ }
+ }
+ }
+
+ // hide synthetic fields of enum and it's constants
+ for (StructField fd : cl.getFields()) {
+ String descriptor = fd.getDescriptor();
+ if (fd.isSynthetic() && descriptor.equals("[L" + cl.qualifiedName + ";")) {
+ wrapper.getHiddenMembers().add(InterpreterUtil.makeUniqueKey(fd.getName(), descriptor));
+ }
+ }
+ }
+
+ // FIXME: move to a util class (see also InitializerProcessor)
+ private static Statement findFirstData(Statement stat) {
+
+ if (stat.getExprents() != null) {
+ return stat;
+ }
+ else {
+ if (stat.isLabeled()) {
+ return null;
+ }
+
+ switch (stat.type) {
+ case Statement.TYPE_SEQUENCE:
+ case Statement.TYPE_IF:
+ case Statement.TYPE_ROOT:
+ case Statement.TYPE_SWITCH:
+ case Statement.TYPE_SYNCRONIZED:
+ return findFirstData(stat.getFirst());
+ default:
+ return null;
+ }
+ }
+ }
+
+ // FIXME: move to util class (see also InitializerProcessor)
+ private static boolean isInvocationSuperConstructor(InvocationExprent inv, MethodWrapper meth, ClassWrapper wrapper) {
+
+ if (inv.getFunctype() == InvocationExprent.TYP_INIT) {
+ if (inv.getInstance().type == Exprent.EXPRENT_VAR) {
+ VarExprent instvar = (VarExprent)inv.getInstance();
+ VarVersionPaar varpaar = new VarVersionPaar(instvar);
+
+ String classname = meth.varproc.getThisvars().get(varpaar);
+
+ if (classname != null) { // any this instance. TODO: Restrict to current class?
+ if (!wrapper.getClassStruct().qualifiedName.equals(inv.getClassname())) {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/Fernflower.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/Fernflower.java
new file mode 100644
index 000000000000..62b8ee4f61f2
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/Fernflower.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.main;
+
+import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
+import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
+import org.jetbrains.java.decompiler.main.extern.IBytecodeProvider;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
+import org.jetbrains.java.decompiler.main.extern.IResultSaver;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
+import org.jetbrains.java.decompiler.modules.renamer.IdentifierConverter;
+import org.jetbrains.java.decompiler.struct.IDecompiledData;
+import org.jetbrains.java.decompiler.struct.StructClass;
+import org.jetbrains.java.decompiler.struct.StructContext;
+import org.jetbrains.java.decompiler.struct.lazy.LazyLoader;
+
+import java.util.Map;
+
+public class Fernflower implements IDecompiledData {
+
+ private StructContext structContext;
+ private ClassesProcessor classesProcessor;
+
+ public Fernflower(IBytecodeProvider provider, IResultSaver saver, Map<String, Object> options, IFernflowerLogger logger) {
+ structContext = new StructContext(saver, this, new LazyLoader(provider));
+ DecompilerContext.initContext(options);
+ DecompilerContext.setCounterContainer(new CounterContainer());
+ DecompilerContext.setLogger(logger);
+ }
+
+ public void decompileContext() {
+ if (DecompilerContext.getOption(IFernflowerPreferences.RENAME_ENTITIES)) {
+ new IdentifierConverter().rename(structContext);
+ }
+
+ classesProcessor = new ClassesProcessor(structContext);
+
+ DecompilerContext.setClassProcessor(classesProcessor);
+ DecompilerContext.setStructContext(structContext);
+
+ structContext.saveContext();
+ }
+
+ public void clearContext() {
+ DecompilerContext.setCurrentContext(null);
+ }
+
+ public StructContext getStructContext() {
+ return structContext;
+ }
+
+ @Override
+ public String getClassEntryName(StructClass cl, String entryName) {
+ ClassNode node = classesProcessor.getMapRootClasses().get(cl.qualifiedName);
+ if (node.type != ClassNode.CLASS_ROOT) {
+ return null;
+ }
+ else {
+ if (DecompilerContext.getOption(IFernflowerPreferences.RENAME_ENTITIES)) {
+ String simple_classname = cl.qualifiedName.substring(cl.qualifiedName.lastIndexOf('/') + 1);
+ return entryName.substring(0, entryName.lastIndexOf('/') + 1) + simple_classname + ".java";
+ }
+ else {
+ return entryName.substring(0, entryName.lastIndexOf(".class")) + ".java";
+ }
+ }
+ }
+
+ @Override
+ public String getClassContent(StructClass cl) {
+ try {
+ StringBuilder buffer = new StringBuilder();
+ classesProcessor.writeClass(cl, buffer);
+ return buffer.toString();
+ }
+ catch (Throwable ex) {
+ DecompilerContext.getLogger().writeMessage("Class " + cl.qualifiedName + " couldn't be fully decompiled.", ex);
+ return null;
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/InitializerProcessor.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/InitializerProcessor.java
new file mode 100644
index 000000000000..aabea15d1ef2
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/InitializerProcessor.java
@@ -0,0 +1,323 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.main;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
+import org.jetbrains.java.decompiler.main.rels.ClassWrapper;
+import org.jetbrains.java.decompiler.main.rels.MethodWrapper;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar;
+import org.jetbrains.java.decompiler.struct.StructClass;
+import org.jetbrains.java.decompiler.struct.StructField;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class InitializerProcessor {
+
+ public static void extractInitializers(ClassWrapper wrapper) {
+
+ MethodWrapper meth = wrapper.getMethodWrapper("<clinit>", "()V");
+ if (meth != null && meth.root != null) { // successfully decompiled static constructor
+ extractStaticInitializers(wrapper, meth);
+ }
+
+ extractDynamicInitializers(wrapper);
+
+ // required e.g. if anonymous class is being decompiled as a standard one.
+ // This can happen if InnerClasses attributes are erased
+ liftConstructor(wrapper);
+
+ if (DecompilerContext.getOption(IFernflowerPreferences.HIDE_EMPTY_SUPER)) {
+ hideEmptySuper(wrapper);
+ }
+ }
+
+
+ private static void liftConstructor(ClassWrapper wrapper) {
+
+ for (MethodWrapper meth : wrapper.getMethods()) {
+ if ("<init>".equals(meth.methodStruct.getName()) && meth.root != null) {
+ Statement firstdata = findFirstData(meth.root);
+ if (firstdata == null) {
+ return;
+ }
+
+
+ int index = 0;
+ List<Exprent> lstExprents = firstdata.getExprents();
+
+ for (Exprent exprent : lstExprents) {
+
+ int action = 0;
+
+ if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent asexpr = (AssignmentExprent)exprent;
+ if (asexpr.getLeft().type == Exprent.EXPRENT_FIELD && asexpr.getRight().type == Exprent.EXPRENT_VAR) {
+ FieldExprent fexpr = (FieldExprent)asexpr.getLeft();
+ if (fexpr.getClassname().equals(wrapper.getClassStruct().qualifiedName)) {
+ StructField structField = wrapper.getClassStruct().getField(fexpr.getName(), fexpr.getDescriptor().descriptorString);
+ if (structField != null && structField.hasModifier(CodeConstants.ACC_FINAL)) {
+ action = 1;
+ }
+ }
+ }
+ }
+ else if (index > 0 && exprent.type == Exprent.EXPRENT_INVOCATION &&
+ isInvocationInitConstructor((InvocationExprent)exprent, meth, wrapper, true)) {
+ // this() or super()
+ lstExprents.add(0, lstExprents.remove(index));
+ action = 2;
+ }
+
+ if (action != 1) {
+ break;
+ }
+
+ index++;
+ }
+ }
+ }
+ }
+
+
+ private static void hideEmptySuper(ClassWrapper wrapper) {
+
+ for (MethodWrapper meth : wrapper.getMethods()) {
+ if ("<init>".equals(meth.methodStruct.getName()) && meth.root != null) {
+ Statement firstdata = findFirstData(meth.root);
+ if (firstdata == null || firstdata.getExprents().isEmpty()) {
+ return;
+ }
+
+ Exprent exprent = firstdata.getExprents().get(0);
+ if (exprent.type == Exprent.EXPRENT_INVOCATION) {
+ InvocationExprent invexpr = (InvocationExprent)exprent;
+ if (isInvocationInitConstructor(invexpr, meth, wrapper, false) && invexpr.getLstParameters().isEmpty()) {
+ firstdata.getExprents().remove(0);
+ }
+ }
+ }
+ }
+ }
+
+ private static void extractStaticInitializers(ClassWrapper wrapper, MethodWrapper meth) {
+
+ RootStatement root = meth.root;
+ StructClass cl = wrapper.getClassStruct();
+
+ Statement firstdata = findFirstData(root);
+ if (firstdata != null) {
+ while (!firstdata.getExprents().isEmpty()) {
+ Exprent exprent = firstdata.getExprents().get(0);
+
+ boolean found = false;
+
+ if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent asexpr = (AssignmentExprent)exprent;
+ if (asexpr.getLeft().type == Exprent.EXPRENT_FIELD) {
+ FieldExprent fexpr = (FieldExprent)asexpr.getLeft();
+ if (fexpr.isStatic() && fexpr.getClassname().equals(cl.qualifiedName) &&
+ cl.hasField(fexpr.getName(), fexpr.getDescriptor().descriptorString)) {
+
+ if (isExprentIndependent(asexpr.getRight(), meth)) {
+
+ String keyField = InterpreterUtil.makeUniqueKey(fexpr.getName(), fexpr.getDescriptor().descriptorString);
+ if (!wrapper.getStaticFieldInitializers().containsKey(keyField)) {
+ wrapper.getStaticFieldInitializers().addWithKey(asexpr.getRight(), keyField);
+ firstdata.getExprents().remove(0);
+ found = true;
+ }
+ }
+ }
+ }
+ }
+
+ if (!found) {
+ break;
+ }
+ }
+ }
+ }
+
+ private static void extractDynamicInitializers(ClassWrapper wrapper) {
+
+ StructClass cl = wrapper.getClassStruct();
+
+ boolean isAnonymous = DecompilerContext.getClassProcessor().getMapRootClasses().get(cl.qualifiedName).type == ClassNode.CLASS_ANONYMOUS;
+
+ List<List<Exprent>> lstFirst = new ArrayList<List<Exprent>>();
+ List<MethodWrapper> lstMethWrappers = new ArrayList<MethodWrapper>();
+
+ for (MethodWrapper meth : wrapper.getMethods()) {
+ if ("<init>".equals(meth.methodStruct.getName()) && meth.root != null) { // successfully decompiled constructor
+ Statement firstdata = findFirstData(meth.root);
+ if (firstdata == null || firstdata.getExprents().isEmpty()) {
+ return;
+ }
+ lstFirst.add(firstdata.getExprents());
+ lstMethWrappers.add(meth);
+
+ Exprent exprent = firstdata.getExprents().get(0);
+ if (!isAnonymous) { // FIXME: doesn't make sense
+ if (exprent.type != Exprent.EXPRENT_INVOCATION ||
+ !isInvocationInitConstructor((InvocationExprent)exprent, meth, wrapper, false)) {
+ return;
+ }
+ }
+ }
+ }
+
+ if (lstFirst.isEmpty()) {
+ return;
+ }
+
+ while (true) {
+
+ String fieldWithDescr = null;
+ Exprent value = null;
+
+ for (int i = 0; i < lstFirst.size(); i++) {
+
+ List<Exprent> lst = lstFirst.get(i);
+
+ if (lst.size() < (isAnonymous ? 1 : 2)) {
+ return;
+ }
+
+ Exprent exprent = lst.get(isAnonymous ? 0 : 1);
+
+ boolean found = false;
+
+ if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent asexpr = (AssignmentExprent)exprent;
+ if (asexpr.getLeft().type == Exprent.EXPRENT_FIELD) {
+ FieldExprent fexpr = (FieldExprent)asexpr.getLeft();
+ if (!fexpr.isStatic() && fexpr.getClassname().equals(cl.qualifiedName) &&
+ cl.hasField(fexpr.getName(), fexpr
+ .getDescriptor().descriptorString)) { // check for the physical existence of the field. Could be defined in a superclass.
+
+ if (isExprentIndependent(asexpr.getRight(), lstMethWrappers.get(i))) {
+ String fieldKey = InterpreterUtil.makeUniqueKey(fexpr.getName(), fexpr.getDescriptor().descriptorString);
+ if (fieldWithDescr == null) {
+ fieldWithDescr = fieldKey;
+ value = asexpr.getRight();
+ }
+ else {
+ if (!fieldWithDescr.equals(fieldKey) ||
+ !value.equals(asexpr.getRight())) {
+ return;
+ }
+ }
+ found = true;
+ }
+ }
+ }
+ }
+
+ if (!found) {
+ return;
+ }
+ }
+
+ if (!wrapper.getDynamicFieldInitializers().containsKey(fieldWithDescr)) {
+ wrapper.getDynamicFieldInitializers().addWithKey(value, fieldWithDescr);
+
+ for (List<Exprent> lst : lstFirst) {
+ lst.remove(isAnonymous ? 0 : 1);
+ }
+ }
+ else {
+ return;
+ }
+ }
+ }
+
+ private static boolean isExprentIndependent(Exprent exprent, MethodWrapper meth) {
+
+ List<Exprent> lst = exprent.getAllExprents(true);
+ lst.add(exprent);
+
+ for (Exprent expr : lst) {
+ switch (expr.type) {
+ case Exprent.EXPRENT_VAR:
+ VarVersionPaar varpaar = new VarVersionPaar((VarExprent)expr);
+ if (!meth.varproc.getExternvars().contains(varpaar)) {
+ String varname = meth.varproc.getVarName(varpaar);
+
+ if (!varname.equals("this") && !varname.endsWith(".this")) { // FIXME: remove direct comparison with strings
+ return false;
+ }
+ }
+ break;
+ case Exprent.EXPRENT_FIELD:
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+
+ private static Statement findFirstData(Statement stat) {
+
+ if (stat.getExprents() != null) {
+ return stat;
+ }
+ else {
+ if (stat.isLabeled()) { // FIXME: Why??
+ return null;
+ }
+
+ switch (stat.type) {
+ case Statement.TYPE_SEQUENCE:
+ case Statement.TYPE_IF:
+ case Statement.TYPE_ROOT:
+ case Statement.TYPE_SWITCH:
+ case Statement.TYPE_SYNCRONIZED:
+ return findFirstData(stat.getFirst());
+ default:
+ return null;
+ }
+ }
+ }
+
+ private static boolean isInvocationInitConstructor(InvocationExprent inv, MethodWrapper meth, ClassWrapper wrapper, boolean withThis) {
+
+ if (inv.getFunctype() == InvocationExprent.TYP_INIT) {
+ if (inv.getInstance().type == Exprent.EXPRENT_VAR) {
+ VarExprent instvar = (VarExprent)inv.getInstance();
+ VarVersionPaar varpaar = new VarVersionPaar(instvar);
+
+ String classname = meth.varproc.getThisvars().get(varpaar);
+
+ if (classname != null) { // any this instance. TODO: Restrict to current class?
+ if (withThis || !wrapper.getClassStruct().qualifiedName.equals(inv.getClassname())) {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/collectors/CounterContainer.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/collectors/CounterContainer.java
new file mode 100644
index 000000000000..04d50a7512e1
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/collectors/CounterContainer.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.main.collectors;
+
+public class CounterContainer {
+
+ public static final int STATEMENT_COUNTER = 0;
+ public static final int EXPRENT_COUNTER = 1;
+ public static final int VAR_COUNTER = 2;
+
+ private int[] values = new int[]{1, 1, 1};
+
+ public void setCounter(int counter, int value) {
+ values[counter] = value;
+ }
+
+ public int getCounter(int counter) {
+ return values[counter];
+ }
+
+ public int getCounterAndIncrement(int counter) {
+ return values[counter]++;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/collectors/ImportCollector.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/collectors/ImportCollector.java
new file mode 100644
index 000000000000..9b6f7edb0019
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/collectors/ImportCollector.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.main.collectors;
+
+import org.jetbrains.java.decompiler.main.ClassesProcessor;
+import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.struct.StructContext;
+
+import java.util.*;
+import java.util.Map.Entry;
+
+
+public class ImportCollector {
+
+ private static final String JAVA_LANG_PACKAGE = "java.lang";
+
+ private Map<String, String> mapSimpleNames = new HashMap<String, String>();
+ private Set<String> setNotImportedNames = new HashSet<String>();
+ private String currentPackageSlash = "";
+ private String currentPackagePoint = "";
+
+ public ImportCollector(ClassNode root) {
+
+ String clname = root.classStruct.qualifiedName;
+ int index = clname.lastIndexOf("/");
+ if (index >= 0) {
+ currentPackageSlash = clname.substring(0, index);
+ currentPackagePoint = currentPackageSlash.replace('/', '.');
+ currentPackageSlash += "/";
+ }
+ }
+
+ public String getShortName(String fullname) {
+ return getShortName(fullname, true);
+ }
+
+ public String getShortName(String fullname, boolean imported) {
+
+ ClassesProcessor clproc = DecompilerContext.getClassProcessor();
+ ClassNode node = clproc.getMapRootClasses().get(fullname.replace('.', '/'));
+
+ String retname = null;
+
+ if (node != null && node.classStruct.isOwn()) {
+
+ retname = node.simpleName;
+
+ while (node.parent != null && node.type == ClassNode.CLASS_MEMBER) {
+ retname = node.parent.simpleName + "." + retname;
+ node = node.parent;
+ }
+
+ if (node.type == ClassNode.CLASS_ROOT) {
+ fullname = node.classStruct.qualifiedName;
+ fullname = fullname.replace('/', '.');
+ }
+ else {
+ return retname;
+ }
+ }
+ else {
+ fullname = fullname.replace('$', '.');
+ }
+
+ String nshort = fullname;
+ String npackage = "";
+
+ int lastpoint = fullname.lastIndexOf(".");
+
+ if (lastpoint >= 0) {
+ nshort = fullname.substring(lastpoint + 1);
+ npackage = fullname.substring(0, lastpoint);
+ }
+
+ StructContext context = DecompilerContext.getStructContext();
+
+ boolean existsDefaultClass = (context.getClass(currentPackageSlash + nshort) != null
+ && !npackage.equals(currentPackagePoint)) // current package
+ || (context.getClass(nshort) != null); // default package
+
+ if (existsDefaultClass ||
+ (mapSimpleNames.containsKey(nshort) && !npackage.equals(mapSimpleNames.get(nshort)))) {
+ return fullname;
+ }
+ else if (!mapSimpleNames.containsKey(nshort)) {
+ mapSimpleNames.put(nshort, npackage);
+
+ if (!imported) {
+ setNotImportedNames.add(nshort);
+ }
+ }
+
+ return retname == null ? nshort : retname;
+ }
+
+ public boolean writeImports(StringBuilder buffer) {
+ List<String> imports = packImports();
+
+ for (String s : imports) {
+ buffer.append("import ");
+ buffer.append(s);
+ buffer.append(";");
+ buffer.append(DecompilerContext.getNewLineSeparator());
+ }
+
+ return imports.size() > 0;
+ }
+
+ private List<String> packImports() {
+ List<Entry<String, String>> lst = new ArrayList<Entry<String, String>>(mapSimpleNames.entrySet());
+
+ Collections.sort(lst, new Comparator<Entry<String, String>>() {
+ public int compare(Entry<String, String> par0, Entry<String, String> par1) {
+ int res = par0.getValue().compareTo(par1.getValue());
+ if (res == 0) {
+ res = par0.getKey().compareTo(par1.getKey());
+ }
+ return res;
+ }
+ });
+
+ List<String> res = new ArrayList<String>();
+ for (Entry<String, String> ent : lst) {
+ // exclude a current class or one of the nested ones, java.lang and empty packages
+ if (!setNotImportedNames.contains(ent.getKey()) &&
+ !JAVA_LANG_PACKAGE.equals(ent.getValue()) &&
+ !ent.getValue().isEmpty()) {
+ res.add(ent.getValue() + "." + ent.getKey());
+ }
+ }
+
+ return res;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/collectors/VarNamesCollector.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/collectors/VarNamesCollector.java
new file mode 100644
index 000000000000..dfde971ac628
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/collectors/VarNamesCollector.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.main.collectors;
+
+import java.util.HashSet;
+
+public class VarNamesCollector {
+
+ private HashSet<String> usedNames = new HashSet<String>();
+
+ public VarNamesCollector() {
+ }
+
+ public VarNamesCollector(HashSet<String> setNames) {
+ usedNames.addAll(setNames);
+ }
+
+ public void addName(String value) {
+ usedNames.add(value);
+ }
+
+ public String getFreeName(int index) {
+ return getFreeName("var" + index);
+ }
+
+ public String getFreeName(String proposition) {
+
+ while (usedNames.contains(proposition)) {
+ proposition += "x";
+ }
+ usedNames.add(proposition);
+ return proposition;
+ }
+
+ public HashSet<String> getUsedNames() {
+ return usedNames;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/decompiler/BaseDecompiler.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/decompiler/BaseDecompiler.java
new file mode 100644
index 000000000000..07b857838e5a
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/decompiler/BaseDecompiler.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.main.decompiler;
+
+import org.jetbrains.java.decompiler.main.Fernflower;
+import org.jetbrains.java.decompiler.main.extern.IBytecodeProvider;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
+import org.jetbrains.java.decompiler.main.extern.IResultSaver;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
+
+public class BaseDecompiler {
+
+ private final Fernflower fernflower;
+
+ public BaseDecompiler(IBytecodeProvider provider, IResultSaver saver, Map<String, Object> options, IFernflowerLogger logger) {
+ fernflower = new Fernflower(provider, saver, options, logger);
+ }
+
+ public void addSpace(File file, boolean isOwn) throws IOException {
+ fernflower.getStructContext().addSpace(file, isOwn);
+ }
+
+ public void decompileContext() {
+ try {
+ fernflower.decompileContext();
+ }
+ finally {
+ fernflower.clearContext();
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/decompiler/ConsoleDecompiler.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/decompiler/ConsoleDecompiler.java
new file mode 100644
index 000000000000..a486d9f83ee1
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/decompiler/ConsoleDecompiler.java
@@ -0,0 +1,299 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.main.decompiler;
+
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.main.Fernflower;
+import org.jetbrains.java.decompiler.main.extern.IBytecodeProvider;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
+import org.jetbrains.java.decompiler.main.extern.IResultSaver;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+
+import java.io.*;
+import java.util.*;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+
+public class ConsoleDecompiler implements IBytecodeProvider, IResultSaver {
+
+ @SuppressWarnings("UseOfSystemOutOrSystemErr")
+ public static void main(String[] args) {
+ if (args.length < 2) {
+ System.out.println(
+ "Usage: java -jar fernflower.jar [-<option>=<value>]* [<source>]+ <destination>\n" +
+ "Example: java -jar fernflower.jar -dgs=true c:\\my\\source\\ c:\\my.jar d:\\decompiled\\");
+ return;
+ }
+
+ Map<String, Object> mapOptions = new HashMap<String, Object>();
+ List<String> lstSources = new ArrayList<String>();
+ List<String> lstLibraries = new ArrayList<String>();
+
+ boolean isOption = true;
+ for (int i = 0; i < args.length - 1; ++i) { // last parameter - destination
+ String arg = args[i];
+
+ if (isOption && arg.startsWith("-") &&
+ arg.length() > 5 && arg.charAt(4) == '=') {
+ String value = arg.substring(5).toUpperCase(Locale.US);
+ if ("TRUE".equals(value)) {
+ value = "1";
+ }
+ else if ("FALSE".equals(value)) {
+ value = "0";
+ }
+
+ mapOptions.put(arg.substring(1, 4), value);
+ }
+ else {
+ isOption = false;
+
+ if (arg.startsWith("-e=")) {
+ lstLibraries.add(arg.substring(3));
+ }
+ else {
+ lstSources.add(arg);
+ }
+ }
+ }
+
+ if (lstSources.isEmpty()) {
+ System.out.println("error: no sources given");
+ return;
+ }
+
+ File destination = new File(args[args.length - 1]);
+ if (!destination.isDirectory()) {
+ System.out.println("error: destination '" + destination + "' is not a directory");
+ return;
+ }
+
+ PrintStreamLogger logger = new PrintStreamLogger(System.out);
+ ConsoleDecompiler decompiler = new ConsoleDecompiler(destination, mapOptions, logger);
+
+ for (String source : lstSources) {
+ decompiler.addSpace(new File(source), true);
+ }
+ for (String library : lstLibraries) {
+ decompiler.addSpace(new File(library), false);
+ }
+
+ decompiler.decompileContext();
+ }
+
+ // *******************************************************************
+ // Implementation
+ // *******************************************************************
+
+ private final File root;
+ private final Fernflower fernflower;
+ private Map<String, ZipOutputStream> mapArchiveStreams = new HashMap<String, ZipOutputStream>();
+ private Map<String, Set<String>> mapArchiveEntries = new HashMap<String, Set<String>>();
+
+ @SuppressWarnings("UseOfSystemOutOrSystemErr")
+ public ConsoleDecompiler(File destination, Map<String, Object> options) {
+ this(destination, options, new PrintStreamLogger(System.out));
+ }
+
+ protected ConsoleDecompiler(File destination, Map<String, Object> options, IFernflowerLogger logger) {
+ root = destination;
+ fernflower = new Fernflower(this, this, options, logger);
+ }
+
+ public void addSpace(File file, boolean isOwn) {
+ fernflower.getStructContext().addSpace(file, isOwn);
+ }
+
+ public void decompileContext() {
+ try {
+ fernflower.decompileContext();
+ }
+ finally {
+ fernflower.clearContext();
+ }
+ }
+
+ // *******************************************************************
+ // Interface IBytecodeProvider
+ // *******************************************************************
+
+ @Override
+ public byte[] getBytecode(String externalPath, String internalPath) throws IOException {
+ File file = new File(externalPath);
+ if (internalPath == null) {
+ return InterpreterUtil.getBytes(file);
+ }
+ else {
+ ZipFile archive = new ZipFile(file);
+ try {
+ ZipEntry entry = archive.getEntry(internalPath);
+ if (entry == null) {
+ throw new IOException("Entry not found: " + internalPath);
+ }
+ return InterpreterUtil.getBytes(archive, entry);
+ }
+ finally {
+ archive.close();
+ }
+ }
+ }
+
+ // *******************************************************************
+ // Interface IResultSaver
+ // *******************************************************************
+
+ private String getAbsolutePath(String path) {
+ return new File(root, path).getAbsolutePath();
+ }
+
+ @Override
+ public void saveFolder(String path) {
+ File dir = new File(getAbsolutePath(path));
+ if (!(dir.mkdirs() || dir.isDirectory())) {
+ throw new RuntimeException("Cannot create directory " + dir);
+ }
+ }
+
+ @Override
+ public void copyFile(String source, String path, String entryName) {
+ try {
+ InterpreterUtil.copyFile(new File(source), new File(getAbsolutePath(path), entryName));
+ }
+ catch (IOException ex) {
+ DecompilerContext.getLogger().writeMessage("Cannot copy " + source + " to " + entryName, ex);
+ }
+ }
+
+ @Override
+ public void saveClassFile(String path, String qualifiedName, String entryName, String content) {
+ File file = new File(getAbsolutePath(path), entryName);
+ try {
+ Writer out = new OutputStreamWriter(new FileOutputStream(file), "UTF8");
+ try {
+ out.write(content);
+ }
+ finally {
+ out.close();
+ }
+ }
+ catch (IOException ex) {
+ DecompilerContext.getLogger().writeMessage("Cannot write class file " + file, ex);
+ }
+ }
+
+ @Override
+ public void createArchive(String path, String archiveName, Manifest manifest) {
+ File file = new File(getAbsolutePath(path), archiveName);
+ try {
+ if (!(file.createNewFile() || file.isFile())) {
+ throw new IOException("Cannot create file " + file);
+ }
+
+ FileOutputStream fileStream = new FileOutputStream(file);
+ @SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
+ ZipOutputStream zipStream = manifest != null ? new JarOutputStream(fileStream, manifest) : new ZipOutputStream(fileStream);
+ mapArchiveStreams.put(file.getPath(), zipStream);
+ }
+ catch (IOException ex) {
+ DecompilerContext.getLogger().writeMessage("Cannot create archive " + file, ex);
+ }
+ }
+
+ @Override
+ public void saveDirEntry(String path, String archiveName, String entryName) {
+ saveClassEntry(path, archiveName, null, entryName, null);
+ }
+
+ @Override
+ public void copyEntry(String source, String path, String archiveName, String entryName) {
+ String file = new File(getAbsolutePath(path), archiveName).getPath();
+
+ if (!checkEntry(entryName, file)) {
+ return;
+ }
+
+ try {
+ ZipFile srcArchive = new ZipFile(new File(source));
+ try {
+ ZipEntry entry = srcArchive.getEntry(entryName);
+ if (entry != null) {
+ InputStream in = srcArchive.getInputStream(entry);
+ ZipOutputStream out = mapArchiveStreams.get(file);
+ out.putNextEntry(new ZipEntry(entryName));
+ InterpreterUtil.copyStream(in, out);
+ in.close();
+ }
+ }
+ finally {
+ srcArchive.close();
+ }
+ }
+ catch (IOException ex) {
+ String message = "Cannot copy entry " + entryName + " from " + source + " to " + file;
+ DecompilerContext.getLogger().writeMessage(message, ex);
+ }
+ }
+
+ @Override
+ public void saveClassEntry(String path, String archiveName, String qualifiedName, String entryName, String content) {
+ String file = new File(getAbsolutePath(path), archiveName).getPath();
+
+ if (!checkEntry(entryName, file)) {
+ return;
+ }
+
+ try {
+ ZipOutputStream out = mapArchiveStreams.get(file);
+ out.putNextEntry(new ZipEntry(entryName));
+ if (content != null) {
+ out.write(content.getBytes("UTF-8"));
+ }
+ }
+ catch (IOException ex) {
+ String message = "Cannot write entry " + entryName + " to " + file;
+ DecompilerContext.getLogger().writeMessage(message, ex);
+ }
+ }
+
+ private boolean checkEntry(String entryName, String file) {
+ Set<String> set = mapArchiveEntries.get(file);
+ if (set == null) {
+ mapArchiveEntries.put(file, set = new HashSet<String>());
+ }
+
+ boolean added = set.add(entryName);
+ if (!added) {
+ String message = "Zip entry " + entryName + " already exists in " + file;
+ DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.WARN);
+ }
+ return added;
+ }
+
+ @Override
+ public void closeArchive(String path, String archiveName) {
+ String file = new File(getAbsolutePath(path), archiveName).getPath();
+ try {
+ mapArchiveEntries.remove(file);
+ mapArchiveStreams.remove(file).close();
+ }
+ catch (IOException ex) {
+ DecompilerContext.getLogger().writeMessage("Cannot close " + file, IFernflowerLogger.Severity.WARN);
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/decompiler/PrintStreamLogger.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/decompiler/PrintStreamLogger.java
new file mode 100644
index 000000000000..7bbcc192fcd3
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/decompiler/PrintStreamLogger.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.main.decompiler;
+
+import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+
+import java.io.PrintStream;
+
+public class PrintStreamLogger extends IFernflowerLogger {
+
+ private final PrintStream stream;
+ private int indent;
+
+ public PrintStreamLogger(PrintStream printStream) {
+ stream = printStream;
+ indent = 0;
+ }
+
+ @Override
+ public void writeMessage(String message, Severity severity) {
+ if (accepts(severity)) {
+ stream.println(InterpreterUtil.getIndentString(indent) + severity.name() + ": " + message);
+ }
+ }
+
+ @Override
+ public void writeMessage(String message, Throwable t) {
+ writeMessage(message, Severity.ERROR);
+ if (accepts(Severity.ERROR)) {
+ t.printStackTrace(stream);
+ }
+ }
+
+ @Override
+ public void startClass(String className) {
+ writeMessage("Processing class " + className + " ...", Severity.INFO);
+ ++indent;
+ }
+
+ @Override
+ public void endClass() {
+ --indent;
+ writeMessage("... proceeded.", Severity.INFO);
+ }
+
+ @Override
+ public void startWriteClass(String className) {
+ writeMessage("Writing class " + className + " ...", Severity.INFO);
+ ++indent;
+ }
+
+ @Override
+ public void endWriteClass() {
+ --indent;
+ writeMessage("... written.", Severity.INFO);
+ }
+
+ @Override
+ public void startMethod(String methodName) {
+ writeMessage("Processing method " + methodName + " ...", Severity.INFO);
+ }
+
+ public void endMethod() {
+ writeMessage("... proceeded.", Severity.INFO);
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/extern/IBytecodeProvider.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/extern/IBytecodeProvider.java
new file mode 100644
index 000000000000..adf32707379e
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/extern/IBytecodeProvider.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.main.extern;
+
+import java.io.IOException;
+
+public interface IBytecodeProvider {
+ byte[] getBytecode(String externalPath, String internalPath) throws IOException;
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/extern/IFernflowerLogger.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/extern/IFernflowerLogger.java
new file mode 100644
index 000000000000..65b2c6da8641
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/extern/IFernflowerLogger.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.main.extern;
+
+public abstract class IFernflowerLogger {
+
+ public enum Severity {
+ TRACE, INFO, WARN, ERROR
+ }
+
+ private Severity severity = Severity.INFO;
+
+ public boolean accepts(Severity severity) {
+ return severity.ordinal() >= this.severity.ordinal();
+ }
+
+ public void setSeverity(Severity severity) {
+ this.severity = severity;
+ }
+
+ public abstract void writeMessage(String message, Severity severity);
+
+ public abstract void writeMessage(String message, Throwable t);
+
+ public void startClass(String className) { }
+
+ public void endClass() { }
+
+ public void startWriteClass(String className) { }
+
+ public void endWriteClass() { }
+
+ public void startMethod(String methodName) { }
+
+ public void endMethod() { }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java
new file mode 100644
index 000000000000..69dd218a0340
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/extern/IFernflowerPreferences.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.main.extern;
+
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+public interface IFernflowerPreferences {
+ String REMOVE_BRIDGE = "rbr";
+ String REMOVE_SYNTHETIC = "rsy";
+ String DECOMPILE_INNER = "din";
+ String DECOMPILE_CLASS_1_4 = "dc4";
+ String DECOMPILE_ASSERTIONS = "das";
+ String HIDE_EMPTY_SUPER = "hes";
+ String HIDE_DEFAULT_CONSTRUCTOR = "hdc";
+ String DECOMPILE_GENERIC_SIGNATURES = "dgs";
+ String NO_EXCEPTIONS_RETURN = "ner";
+ String DECOMPILE_ENUM = "den";
+ String REMOVE_GET_CLASS_NEW = "rgn";
+ String LITERALS_AS_IS = "lit";
+ String BOOLEAN_TRUE_ONE = "bto";
+ String ASCII_STRING_CHARACTERS = "asc";
+ String SYNTHETIC_NOT_SET = "nns";
+ String UNDEFINED_PARAM_TYPE_OBJECT = "uto";
+ String USE_DEBUG_VAR_NAMES = "udv";
+ String REMOVE_EMPTY_RANGES = "rer";
+ String FINALLY_DEINLINE = "fdi";
+ String IDEA_NOT_NULL_ANNOTATION = "inn";
+ String LAMBDA_TO_ANONYMOUS_CLASS = "lac";
+
+ String LOG_LEVEL = "log";
+ String MAX_PROCESSING_METHOD = "mpm";
+ String RENAME_ENTITIES = "ren";
+ String USER_RENAMER_CLASS = "urc";
+ String NEW_LINE_SEPARATOR = "nls";
+ String INDENT_STRING = "ind";
+
+ String LINE_SEPARATOR_WIN = "\r\n";
+ String LINE_SEPARATOR_LIN = "\n";
+
+ Map<String, Object> DEFAULTS = Collections.unmodifiableMap(new HashMap<String, Object>() {{
+ put(REMOVE_BRIDGE, "1");
+ put(REMOVE_SYNTHETIC, "0");
+ put(DECOMPILE_INNER, "1");
+ put(DECOMPILE_CLASS_1_4, "1");
+ put(DECOMPILE_ASSERTIONS, "1");
+ put(HIDE_EMPTY_SUPER, "1");
+ put(HIDE_DEFAULT_CONSTRUCTOR, "1");
+ put(DECOMPILE_GENERIC_SIGNATURES, "0");
+ put(NO_EXCEPTIONS_RETURN, "1");
+ put(DECOMPILE_ENUM, "1");
+ put(REMOVE_GET_CLASS_NEW, "1");
+ put(LITERALS_AS_IS, "0");
+ put(BOOLEAN_TRUE_ONE, "1");
+ put(ASCII_STRING_CHARACTERS, "0");
+ put(SYNTHETIC_NOT_SET, "1");
+ put(UNDEFINED_PARAM_TYPE_OBJECT, "1");
+ put(USE_DEBUG_VAR_NAMES, "1");
+ put(REMOVE_EMPTY_RANGES, "1");
+ put(FINALLY_DEINLINE, "1");
+ put(IDEA_NOT_NULL_ANNOTATION, "1");
+ put(LAMBDA_TO_ANONYMOUS_CLASS, "0");
+
+ put(LOG_LEVEL, IFernflowerLogger.Severity.INFO.name());
+ put(MAX_PROCESSING_METHOD, "0");
+ put(RENAME_ENTITIES, "0");
+ put(NEW_LINE_SEPARATOR, (InterpreterUtil.IS_WINDOWS ? "0" : "1"));
+ put(INDENT_STRING, " ");
+ }});
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/extern/IIdentifierRenamer.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/extern/IIdentifierRenamer.java
new file mode 100644
index 000000000000..fc0971e10612
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/extern/IIdentifierRenamer.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.main.extern;
+
+
+public interface IIdentifierRenamer {
+
+ int ELEMENT_CLASS = 1;
+
+ int ELEMENT_FIELD = 2;
+
+ int ELEMENT_METHOD = 3;
+
+
+ boolean toBeRenamed(int element_type, String classname, String element, String descriptor);
+
+ String getNextClassname(String fullname, String shortname);
+
+ String getNextFieldname(String classname, String field, String descriptor);
+
+ String getNextMethodname(String classname, String method, String descriptor);
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/extern/IResultSaver.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/extern/IResultSaver.java
new file mode 100644
index 000000000000..1e6a7d4262a5
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/extern/IResultSaver.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.main.extern;
+
+import java.util.jar.Manifest;
+
+public interface IResultSaver {
+ void saveFolder(String path);
+
+ void copyFile(String source, String path, String entryName);
+
+ void saveClassFile(String path, String qualifiedName, String entryName, String content);
+
+ void createArchive(String path, String archiveName, Manifest manifest);
+
+ void saveDirEntry(String path, String archiveName, String entryName);
+
+ void copyEntry(String source, String path, String archiveName, String entry);
+
+ void saveClassEntry(String path, String archiveName, String qualifiedName, String entryName, String content);
+
+ void closeArchive(String path, String archiveName);
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/rels/ClassWrapper.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/rels/ClassWrapper.java
new file mode 100644
index 000000000000..4a321799bc4b
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/rels/ClassWrapper.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.main.rels;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
+import org.jetbrains.java.decompiler.main.collectors.VarNamesCollector;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar;
+import org.jetbrains.java.decompiler.struct.StructClass;
+import org.jetbrains.java.decompiler.struct.StructField;
+import org.jetbrains.java.decompiler.struct.StructMethod;
+import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute;
+import org.jetbrains.java.decompiler.struct.attr.StructLocalVariableTableAttribute;
+import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import org.jetbrains.java.decompiler.util.VBStyleCollection;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+
+public class ClassWrapper {
+
+ private StructClass classStruct;
+ private Set<String> hiddenMembers = new HashSet<String>();
+ private VBStyleCollection<Exprent, String> staticFieldInitializers = new VBStyleCollection<Exprent, String>();
+ private VBStyleCollection<Exprent, String> dynamicFieldInitializers = new VBStyleCollection<Exprent, String>();
+ private VBStyleCollection<MethodWrapper, String> methods = new VBStyleCollection<MethodWrapper, String>();
+
+
+ public ClassWrapper(StructClass classStruct) {
+ this.classStruct = classStruct;
+ }
+
+ public void init() throws IOException {
+
+ DecompilerContext.setProperty(DecompilerContext.CURRENT_CLASS, classStruct);
+
+ DecompilerContext.getLogger().startClass(classStruct.qualifiedName);
+
+ // collect field names
+ HashSet<String> setFieldNames = new HashSet<String>();
+ for (StructField fd : classStruct.getFields()) {
+ setFieldNames.add(fd.getName());
+ }
+
+ int maxsec = Integer.parseInt(DecompilerContext.getProperty(IFernflowerPreferences.MAX_PROCESSING_METHOD).toString());
+
+ for (StructMethod mt : classStruct.getMethods()) {
+
+ DecompilerContext.getLogger().startMethod(mt.getName() + " " + mt.getDescriptor());
+
+ VarNamesCollector vc = new VarNamesCollector();
+ DecompilerContext.setVarNamesCollector(vc);
+
+ CounterContainer counter = new CounterContainer();
+ DecompilerContext.setCounterContainer(counter);
+
+ DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD, mt);
+ DecompilerContext.setProperty(DecompilerContext.CURRENT_METHOD_DESCRIPTOR, MethodDescriptor.parseDescriptor(mt.getDescriptor()));
+
+ VarProcessor varproc = new VarProcessor();
+ DecompilerContext.setProperty(DecompilerContext.CURRENT_VAR_PROCESSOR, varproc);
+
+ RootStatement root = null;
+
+ boolean isError = false;
+
+ try {
+ if (mt.containsCode()) {
+
+ if (maxsec == 0) { // blocking wait
+ root = MethodProcessorThread.codeToJava(mt, varproc);
+ }
+ else {
+ MethodProcessorThread mtproc = new MethodProcessorThread(mt, varproc, DecompilerContext.getCurrentContext());
+ Thread mtthread = new Thread(mtproc);
+ long stopAt = System.currentTimeMillis() + maxsec * 1000;
+
+ mtthread.start();
+
+ while (mtthread.isAlive()) {
+
+ synchronized (mtproc.lock) {
+ mtproc.lock.wait(100);
+ }
+
+ if (System.currentTimeMillis() >= stopAt) {
+ String message = "Processing time limit exceeded for method " + mt.getName() + ", execution interrupted.";
+ DecompilerContext.getLogger().writeMessage(message, IFernflowerLogger.Severity.ERROR);
+ killThread(mtthread);
+ isError = true;
+ break;
+ }
+ }
+
+ if (!isError) {
+ root = mtproc.getResult();
+ }
+ }
+ }
+ else {
+ boolean thisvar = !mt.hasModifier(CodeConstants.ACC_STATIC);
+ MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
+
+ int paramcount = 0;
+ if (thisvar) {
+ varproc.getThisvars().put(new VarVersionPaar(0, 0), classStruct.qualifiedName);
+ paramcount = 1;
+ }
+ paramcount += md.params.length;
+
+ int varindex = 0;
+ for (int i = 0; i < paramcount; i++) {
+ varproc.setVarName(new VarVersionPaar(varindex, 0), vc.getFreeName(varindex));
+
+ if (thisvar) {
+ if (i == 0) {
+ varindex++;
+ }
+ else {
+ varindex += md.params[i - 1].stack_size;
+ }
+ }
+ else {
+ varindex += md.params[i].stack_size;
+ }
+ }
+ }
+ }
+ catch (Throwable ex) {
+ DecompilerContext.getLogger().writeMessage("Method " + mt.getName() + " " + mt.getDescriptor() + " couldn't be decompiled.", ex);
+ isError = true;
+ }
+
+ MethodWrapper meth = new MethodWrapper(root, varproc, mt, counter);
+ meth.decompiledWithErrors = isError;
+
+ methods.addWithKey(meth, InterpreterUtil.makeUniqueKey(mt.getName(), mt.getDescriptor()));
+
+ // rename vars so that no one has the same name as a field
+ varproc.refreshVarNames(new VarNamesCollector(setFieldNames));
+
+ // if debug information present and should be used
+ if (DecompilerContext.getOption(IFernflowerPreferences.USE_DEBUG_VAR_NAMES)) {
+ StructLocalVariableTableAttribute attr = (StructLocalVariableTableAttribute)mt.getAttributes().getWithKey(
+ StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TABLE);
+
+ if (attr != null) {
+ varproc.setDebugVarNames(attr.getMapVarNames());
+ }
+ }
+
+ DecompilerContext.getLogger().endMethod();
+ }
+
+ DecompilerContext.getLogger().endClass();
+ }
+
+ @SuppressWarnings("deprecation")
+ private static void killThread(Thread thread) {
+ thread.stop();
+ }
+
+ public MethodWrapper getMethodWrapper(String name, String descriptor) {
+ return methods.getWithKey(InterpreterUtil.makeUniqueKey(name, descriptor));
+ }
+
+ public StructClass getClassStruct() {
+ return classStruct;
+ }
+
+ public VBStyleCollection<MethodWrapper, String> getMethods() {
+ return methods;
+ }
+
+ public Set<String> getHiddenMembers() {
+ return hiddenMembers;
+ }
+
+ public VBStyleCollection<Exprent, String> getStaticFieldInitializers() {
+ return staticFieldInitializers;
+ }
+
+ public VBStyleCollection<Exprent, String> getDynamicFieldInitializers() {
+ return dynamicFieldInitializers;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/rels/LambdaProcessor.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/rels/LambdaProcessor.java
new file mode 100644
index 000000000000..743ce1215381
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/rels/LambdaProcessor.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.main.rels;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.code.Instruction;
+import org.jetbrains.java.decompiler.code.InstructionSequence;
+import org.jetbrains.java.decompiler.main.ClassesProcessor;
+import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.struct.StructClass;
+import org.jetbrains.java.decompiler.struct.StructMethod;
+import org.jetbrains.java.decompiler.struct.attr.StructBootstrapMethodsAttribute;
+import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute;
+import org.jetbrains.java.decompiler.struct.consts.LinkConstant;
+import org.jetbrains.java.decompiler.struct.consts.PooledConstant;
+import org.jetbrains.java.decompiler.struct.consts.PrimitiveConstant;
+import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+
+import java.io.IOException;
+import java.util.*;
+
+public class LambdaProcessor {
+
+ private static final String JAVAC_LAMBDA_CLASS = "java/lang/invoke/LambdaMetafactory";
+ private static final String JAVAC_LAMBDA_METHOD = "metafactory";
+ private static final String JAVAC_LAMBDA_METHOD_DESCRIPTOR =
+ "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;";
+
+ public void processClass(ClassNode node) throws IOException {
+
+ for (ClassNode child : node.nested) {
+ processClass(child);
+ }
+
+ if (node.nested.isEmpty()) {
+ hasLambda(node);
+ }
+ }
+
+ public boolean hasLambda(ClassNode node) throws IOException {
+
+ ClassesProcessor clprocessor = DecompilerContext.getClassProcessor();
+ StructClass cl = node.classStruct;
+
+ if (cl.getBytecodeVersion() < CodeConstants.BYTECODE_JAVA_8) { // lamda beginning with Java 8
+ return false;
+ }
+
+ StructBootstrapMethodsAttribute bootstrap =
+ (StructBootstrapMethodsAttribute)cl.getAttributes().getWithKey(StructGeneralAttribute.ATTRIBUTE_BOOTSTRAP_METHODS);
+ if (bootstrap == null || bootstrap.getMethodsNumber() == 0) {
+ return false; // no bootstrap constants in pool
+ }
+
+ Set<Integer> lambda_methods = new HashSet<Integer>();
+
+ // find lambda bootstrap constants
+ for (int i = 0; i < bootstrap.getMethodsNumber(); ++i) {
+ LinkConstant method_ref = bootstrap.getMethodReference(i); // method handle
+
+ if (JAVAC_LAMBDA_CLASS.equals(method_ref.classname) &&
+ JAVAC_LAMBDA_METHOD.equals(method_ref.elementname) &&
+ JAVAC_LAMBDA_METHOD_DESCRIPTOR
+ .equals(method_ref.descriptor)) { // check for javac lambda structure. FIXME: extend for Eclipse etc. at some point
+ lambda_methods.add(i);
+ }
+ }
+
+ if (lambda_methods.isEmpty()) {
+ return false; // no lambda bootstrap constant found
+ }
+
+ Map<String, String> mapMethodsLambda = new HashMap<String, String>();
+
+ // iterate over code and find invocations of bootstrap methods. Replace them with anonymous classes.
+ for (StructMethod mt : cl.getMethods()) {
+ mt.expandData();
+
+ InstructionSequence seq = mt.getInstructionSequence();
+ if (seq != null && seq.length() > 0) {
+ int len = seq.length();
+
+ for (int i = 0; i < len; ++i) {
+ Instruction instr = seq.getInstr(i);
+
+ if (instr.opcode == CodeConstants.opc_invokedynamic) {
+ LinkConstant invoke_dynamic = cl.getPool().getLinkConstant(instr.getOperand(0));
+
+ if (lambda_methods.contains(invoke_dynamic.index1)) { // lambda invocation found
+
+ List<PooledConstant> bootstrap_arguments = bootstrap.getMethodArguments(invoke_dynamic.index1);
+ MethodDescriptor md = MethodDescriptor.parseDescriptor(invoke_dynamic.descriptor);
+
+ String lambda_class_name = md.ret.value;
+ String lambda_method_name = invoke_dynamic.elementname;
+ String lambda_method_descriptor = ((PrimitiveConstant)bootstrap_arguments.get(2)).getString(); // method type
+
+ LinkConstant content_method_handle = (LinkConstant)bootstrap_arguments.get(1);
+
+ ClassNode node_lambda = new ClassNode(content_method_handle.classname, content_method_handle.elementname,
+ content_method_handle.descriptor, content_method_handle.index1,
+ lambda_class_name, lambda_method_name, lambda_method_descriptor, cl);
+ node_lambda.simpleName = cl.qualifiedName + "##Lambda_" + invoke_dynamic.index1 + "_" + invoke_dynamic.index2;
+ node_lambda.enclosingMethod = InterpreterUtil.makeUniqueKey(mt.getName(), mt.getDescriptor());
+
+ node.nested.add(node_lambda);
+ node_lambda.parent = node;
+
+ clprocessor.getMapRootClasses().put(node_lambda.simpleName, node_lambda);
+ mapMethodsLambda.put(node_lambda.lambda_information.content_method_key, node_lambda.simpleName);
+ }
+ }
+ }
+ }
+
+ mt.releaseResources();
+ }
+
+ // build class hierarchy on lambda
+ for (ClassNode nd : node.nested) {
+ if (nd.type == ClassNode.CLASS_LAMBDA) {
+ String parent_class_name = mapMethodsLambda.get(nd.enclosingMethod);
+ if (parent_class_name != null) {
+ ClassNode parent_class = clprocessor.getMapRootClasses().get(parent_class_name);
+
+ parent_class.nested.add(nd);
+ nd.parent = parent_class;
+ }
+ }
+ }
+
+ // FIXME: mixed hierarchy?
+
+ return false;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/rels/MethodProcessorThread.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/rels/MethodProcessorThread.java
new file mode 100644
index 000000000000..2f98cf82ce08
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/rels/MethodProcessorThread.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.main.rels;
+
+import org.jetbrains.java.decompiler.code.InstructionSequence;
+import org.jetbrains.java.decompiler.code.cfg.ControlFlowGraph;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
+import org.jetbrains.java.decompiler.modules.code.DeadCodeHelper;
+import org.jetbrains.java.decompiler.modules.decompiler.*;
+import org.jetbrains.java.decompiler.modules.decompiler.deobfuscator.ExceptionDeobfuscator;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor;
+import org.jetbrains.java.decompiler.struct.StructClass;
+import org.jetbrains.java.decompiler.struct.StructMethod;
+
+import java.io.IOException;
+
+public class MethodProcessorThread implements Runnable {
+
+ public final Object lock = new Object();
+
+ private final StructMethod method;
+ private final VarProcessor varproc;
+ private final DecompilerContext parentContext;
+
+ private volatile RootStatement root;
+ private volatile Throwable error;
+
+ public MethodProcessorThread(StructMethod method, VarProcessor varproc, DecompilerContext parentContext) {
+ this.method = method;
+ this.varproc = varproc;
+ this.parentContext = parentContext;
+ }
+
+ public void run() {
+
+ DecompilerContext.setCurrentContext(parentContext);
+
+ error = null;
+ root = null;
+
+ try {
+ root = codeToJava(method, varproc);
+
+ synchronized (lock) {
+ lock.notifyAll();
+ }
+ }
+ catch (ThreadDeath ex) {
+ throw ex;
+ }
+ catch (Throwable ex) {
+ error = ex;
+ }
+ }
+
+ public static RootStatement codeToJava(StructMethod mt, VarProcessor varproc) throws IOException {
+
+ StructClass cl = mt.getClassStruct();
+
+ boolean isInitializer = "<clinit>".equals(mt.getName()); // for now static initializer only
+
+ mt.expandData();
+ InstructionSequence seq = mt.getInstructionSequence();
+ ControlFlowGraph graph = new ControlFlowGraph(seq);
+
+ // System.out.println(graph.toString());
+
+
+ // if(mt.getName().endsWith("_getActiveServers")) {
+ // System.out.println();
+ // }
+
+ //DotExporter.toDotFile(graph, new File("c:\\Temp\\fern1.dot"), true);
+
+ DeadCodeHelper.removeDeadBlocks(graph);
+ graph.inlineJsr(mt);
+
+ // DotExporter.toDotFile(graph, new File("c:\\Temp\\fern4.dot"), true);
+
+ // TODO: move to the start, before jsr inlining
+ DeadCodeHelper.connectDummyExitBlock(graph);
+
+ DeadCodeHelper.removeGotos(graph);
+ ExceptionDeobfuscator.removeCircularRanges(graph);
+ //DeadCodeHelper.removeCircularRanges(graph);
+
+
+ // DotExporter.toDotFile(graph, new File("c:\\Temp\\fern3.dot"), true);
+
+ ExceptionDeobfuscator.restorePopRanges(graph);
+
+ if (DecompilerContext.getOption(IFernflowerPreferences.REMOVE_EMPTY_RANGES)) {
+ ExceptionDeobfuscator.removeEmptyRanges(graph);
+ }
+
+ // DotExporter.toDotFile(graph, new File("c:\\Temp\\fern3.dot"), true);
+
+ if (DecompilerContext.getOption(IFernflowerPreferences.NO_EXCEPTIONS_RETURN)) {
+ // special case: single return instruction outside of a protected range
+ DeadCodeHelper.incorporateValueReturns(graph);
+ }
+
+ // DotExporter.toDotFile(graph, new File("c:\\Temp\\fern5.dot"), true);
+
+ // ExceptionDeobfuscator.restorePopRanges(graph);
+ ExceptionDeobfuscator.insertEmptyExceptionHandlerBlocks(graph);
+
+ DeadCodeHelper.mergeBasicBlocks(graph);
+
+ DecompilerContext.getCounterContainer().setCounter(CounterContainer.VAR_COUNTER, mt.getLocalVariables());
+
+ //DotExporter.toDotFile(graph, new File("c:\\Temp\\fern3.dot"), true);
+ //System.out.println(graph.toString());
+
+ if (ExceptionDeobfuscator.hasObfuscatedExceptions(graph)) {
+ DecompilerContext.getLogger().writeMessage("Heavily obfuscated exception ranges found!", IFernflowerLogger.Severity.WARN);
+ }
+
+ RootStatement root = DomHelper.parseGraph(graph);
+
+ FinallyProcessor fproc = new FinallyProcessor(varproc);
+ while (fproc.iterateGraph(mt, root, graph)) {
+
+ //DotExporter.toDotFile(graph, new File("c:\\Temp\\fern2.dot"), true);
+ //System.out.println(graph.toString());
+ //System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
+
+ root = DomHelper.parseGraph(graph);
+ }
+
+ // remove synchronized exception handler
+ // not until now because of comparison between synchronized statements in the finally cycle
+ DomHelper.removeSynchronizedHandler(root);
+
+ // DotExporter.toDotFile(graph, new File("c:\\Temp\\fern3.dot"), true);
+ // System.out.println(graph.toString());
+
+ // LabelHelper.lowContinueLabels(root, new HashSet<StatEdge>());
+
+ SequenceHelper.condenseSequences(root);
+
+ ClearStructHelper.clearStatements(root);
+
+ ExprProcessor proc = new ExprProcessor();
+ proc.processStatement(root, cl);
+
+ // DotExporter.toDotFile(graph, new File("c:\\Temp\\fern3.dot"), true);
+ // System.out.println(graph.toString());
+
+ //System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
+
+ while (true) {
+ StackVarsProcessor stackproc = new StackVarsProcessor();
+ stackproc.simplifyStackVars(root, mt, cl);
+
+ //System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
+
+ varproc.setVarVersions(root);
+
+ // System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
+
+ if (!new PPandMMHelper().findPPandMM(root)) {
+ break;
+ }
+ }
+
+ while (true) {
+
+ LabelHelper.cleanUpEdges(root);
+
+ while (true) {
+
+ MergeHelper.enhanceLoops(root);
+
+ if (LoopExtractHelper.extractLoops(root)) {
+ continue;
+ }
+
+ if (!IfHelper.mergeAllIfs(root)) {
+ break;
+ }
+ }
+
+ if (DecompilerContext.getOption(IFernflowerPreferences.IDEA_NOT_NULL_ANNOTATION)) {
+
+ if (IdeaNotNullHelper.removeHardcodedChecks(root, mt)) {
+
+ SequenceHelper.condenseSequences(root);
+
+ StackVarsProcessor stackproc = new StackVarsProcessor();
+ stackproc.simplifyStackVars(root, mt, cl);
+
+ varproc.setVarVersions(root);
+ }
+ }
+
+ LabelHelper.identifyLabels(root);
+
+ // System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
+
+ if (InlineSingleBlockHelper.inlineSingleBlocks(root)) {
+ continue;
+ }
+
+ // initializer may have at most one return point, so no transformation of method exits permitted
+ if (isInitializer || !ExitHelper.condenseExits(root)) {
+ break;
+ }
+
+ // FIXME: !!
+ // if(!EliminateLoopsHelper.eliminateLoops(root)) {
+ // break;
+ // }
+ }
+
+ ExitHelper.removeRedundantReturns(root);
+
+ SecondaryFunctionsHelper.identifySecondaryFunctions(root);
+
+ varproc.setVarDefinitions(root);
+
+ // must be the last invocation, because it makes the statement structure inconsistent
+ // FIXME: new edge type needed
+ LabelHelper.replaceContinueWithBreak(root);
+
+ mt.releaseResources();
+
+ // System.out.println("++++++++++++++++++++++/// \r\n"+root.toJava());
+
+ return root;
+ }
+
+ public RootStatement getResult() throws Throwable {
+ Throwable t = error;
+ if (t != null) throw t;
+ return root;
+ }
+
+ public Throwable getError() {
+ return error;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/rels/MethodWrapper.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/rels/MethodWrapper.java
new file mode 100644
index 000000000000..d36b8bc578fd
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/rels/MethodWrapper.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.main.rels;
+
+import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
+import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectGraph;
+import org.jetbrains.java.decompiler.modules.decompiler.sforms.FlattenStatementsHelper;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar;
+import org.jetbrains.java.decompiler.struct.StructMethod;
+
+import java.util.HashSet;
+import java.util.List;
+
+
+public class MethodWrapper {
+
+ public RootStatement root;
+
+ public VarProcessor varproc;
+
+ public StructMethod methodStruct;
+
+ public CounterContainer counter;
+
+ public DirectGraph graph;
+
+ public List<VarVersionPaar> signatureFields;
+
+ public boolean decompiledWithErrors;
+
+ public HashSet<String> setOuterVarNames = new HashSet<String>();
+
+ public MethodWrapper(RootStatement root, VarProcessor varproc, StructMethod methodStruct, CounterContainer counter) {
+ this.root = root;
+ this.varproc = varproc;
+ this.methodStruct = methodStruct;
+ this.counter = counter;
+ }
+
+ public DirectGraph getOrBuildGraph() {
+ if (graph == null && root != null) {
+ FlattenStatementsHelper flatthelper = new FlattenStatementsHelper();
+ graph = flatthelper.buildDirectGraph(root);
+ }
+ return graph;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java
new file mode 100644
index 000000000000..2e839461125c
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/rels/NestedClassProcessor.java
@@ -0,0 +1,1030 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.main.rels;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
+import org.jetbrains.java.decompiler.main.collectors.VarNamesCollector;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
+import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectGraph;
+import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectNode;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.DoStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarTypeProcessor;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar;
+import org.jetbrains.java.decompiler.struct.StructClass;
+import org.jetbrains.java.decompiler.struct.StructField;
+import org.jetbrains.java.decompiler.struct.StructMethod;
+import org.jetbrains.java.decompiler.struct.attr.StructEnclosingMethodAttribute;
+import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+
+import java.util.*;
+import java.util.Map.Entry;
+
+public class NestedClassProcessor {
+
+
+ public void processClass(ClassNode root, ClassNode node) {
+
+ // hide synthetic lambda content methods
+ if (node.type == ClassNode.CLASS_LAMBDA && !node.lambda_information.is_method_reference) {
+ ClassNode node_content = DecompilerContext.getClassProcessor().getMapRootClasses().get(node.classStruct.qualifiedName);
+ if (node_content != null && node_content.wrapper != null) {
+ node_content.wrapper.getHiddenMembers().add(node.lambda_information.content_method_key);
+ }
+ }
+
+ if (node.nested.isEmpty()) {
+ return;
+ }
+
+ if (node.type != ClassNode.CLASS_LAMBDA) {
+
+ computeLocalVarsAndDefinitions(node);
+
+ // for each local or anonymous class ensure not empty enclosing method
+ checkNotFoundClasses(root, node);
+ }
+
+ int nameless = 0, synthetics = 0;
+ for (ClassNode child : node.nested) {
+ // ensure not-empty class name
+ if ((child.type == ClassNode.CLASS_LOCAL || child.type == ClassNode.CLASS_MEMBER) && child.simpleName == null) {
+ StructClass cl = child.classStruct;
+ if ((child.access & CodeConstants.ACC_SYNTHETIC) != 0 || cl.isSynthetic()) {
+ child.simpleName = "SyntheticClass_" + (++synthetics);
+ }
+ else {
+ DecompilerContext.getLogger().writeMessage("Nameless local or member class " + cl.qualifiedName + "!",
+ IFernflowerLogger.Severity.WARN);
+ child.simpleName = "NamelessClass_" + (++nameless);
+ }
+ }
+ }
+
+ for (ClassNode child : node.nested) {
+ if (child.type == ClassNode.CLASS_LAMBDA) {
+ setLambdaVars(node, child);
+ }
+ else {
+ if (child.type != ClassNode.CLASS_MEMBER || (child.access & CodeConstants.ACC_STATIC) == 0) {
+ insertLocalVars(node, child);
+
+ if (child.type == ClassNode.CLASS_LOCAL) {
+ setLocalClassDefinition(node.wrapper.getMethods().getWithKey(child.enclosingMethod), child);
+ }
+ }
+ }
+ }
+
+ for (ClassNode child : node.nested) {
+ processClass(root, child);
+ }
+ }
+
+ private static void setLambdaVars(ClassNode parent, ClassNode child) {
+
+ if (child.lambda_information.is_method_reference) { // method reference, no code and no parameters
+ return;
+ }
+
+ final MethodWrapper meth = parent.wrapper.getMethods().getWithKey(child.lambda_information.content_method_key);
+ final MethodWrapper encmeth = parent.wrapper.getMethods().getWithKey(child.enclosingMethod);
+
+ MethodDescriptor md_lambda = MethodDescriptor.parseDescriptor(child.lambda_information.method_descriptor);
+ final MethodDescriptor md_content = MethodDescriptor.parseDescriptor(child.lambda_information.content_method_descriptor);
+
+ final int vars_count = md_content.params.length - md_lambda.params.length;
+ // if(vars_count < 0) { // should not happen, but just in case...
+ // vars_count = 0;
+ // }
+
+ final boolean is_static_lambda_content = child.lambda_information.is_content_method_static;
+
+ final String parent_class_name = parent.wrapper.getClassStruct().qualifiedName;
+ final String lambda_class_name = child.simpleName;
+
+ final VarType lambda_class_type = new VarType(lambda_class_name, true);
+
+ // this pointer
+ if (!is_static_lambda_content && DecompilerContext.getOption(IFernflowerPreferences.LAMBDA_TO_ANONYMOUS_CLASS)) {
+ meth.varproc.getThisvars().put(new VarVersionPaar(0, 0), parent_class_name);
+ meth.varproc.setVarName(new VarVersionPaar(0, 0), parent.simpleName + ".this");
+ }
+
+ // local variables
+ DirectGraph graph = encmeth.getOrBuildGraph();
+
+ final HashMap<VarVersionPaar, String> mapNewNames = new HashMap<VarVersionPaar, String>();
+
+ graph.iterateExprents(new DirectGraph.ExprentIterator() {
+ public int processExprent(Exprent exprent) {
+
+ List<Exprent> lst = exprent.getAllExprents(true);
+ lst.add(exprent);
+
+ for (Exprent expr : lst) {
+
+ if (expr.type == Exprent.EXPRENT_NEW) {
+ NewExprent new_expr = (NewExprent)expr;
+ if (new_expr.isLambda() && lambda_class_type.equals(new_expr.getNewtype())) {
+
+ InvocationExprent inv_dynamic = new_expr.getConstructor();
+
+ int param_index = is_static_lambda_content ? 0 : 1;
+ int varindex = is_static_lambda_content ? 0 : 1;
+
+ for (int i = 0; i < vars_count; ++i) {
+
+ Exprent param = inv_dynamic.getLstParameters().get(param_index + i);
+
+ if (param.type == Exprent.EXPRENT_VAR) {
+ VarVersionPaar enc_varpaar = new VarVersionPaar((VarExprent)param);
+ String enc_varname = encmeth.varproc.getVarName(enc_varpaar);
+
+ //meth.varproc.setVarName(new VarVersionPaar(varindex, 0), enc_varname);
+ mapNewNames.put(new VarVersionPaar(varindex, 0), enc_varname);
+ }
+
+ varindex += md_content.params[i].stack_size;
+ }
+ }
+ }
+ }
+
+ return 0;
+ }
+ });
+
+ // update names of local variables
+ HashSet<String> setNewOuterNames = new HashSet<String>(mapNewNames.values());
+ setNewOuterNames.removeAll(meth.setOuterVarNames);
+
+ meth.varproc.refreshVarNames(new VarNamesCollector(setNewOuterNames));
+ meth.setOuterVarNames.addAll(setNewOuterNames);
+
+ for (Entry<VarVersionPaar, String> entr : mapNewNames.entrySet()) {
+ meth.varproc.setVarName(entr.getKey(), entr.getValue());
+ }
+ }
+
+ private static void checkNotFoundClasses(ClassNode root, ClassNode node) {
+
+ List<ClassNode> lstChildren = new ArrayList<ClassNode>(node.nested);
+
+ for (ClassNode child : lstChildren) {
+
+ if ((child.type == ClassNode.CLASS_LOCAL || child.type == ClassNode.CLASS_ANONYMOUS) && child.enclosingMethod == null) {
+
+ Set<String> setEnclosing = child.enclosingClasses;
+
+ if (setEnclosing.size() == 1) {
+ StructEnclosingMethodAttribute attr =
+ (StructEnclosingMethodAttribute)child.classStruct.getAttributes().getWithKey("EnclosingMethod");
+ if (attr != null && attr.getMethodName() != null) {
+ if (node.classStruct.qualifiedName.equals(attr.getClassName()) &&
+ node.classStruct.getMethod(attr.getMethodName(), attr.getMethodDescriptor()) != null) {
+ child.enclosingMethod = InterpreterUtil.makeUniqueKey(attr.getMethodName(), attr.getMethodDescriptor());
+ continue;
+ }
+ }
+ }
+
+ node.nested.remove(child);
+ child.parent = null;
+ setEnclosing.remove(node.classStruct.qualifiedName);
+
+ boolean hasEnclosing = !setEnclosing.isEmpty();
+ if (hasEnclosing) {
+ hasEnclosing = insertNestedClass(root, child);
+ }
+
+ if (!hasEnclosing) {
+ if (child.type == ClassNode.CLASS_ANONYMOUS) {
+ DecompilerContext.getLogger()
+ .writeMessage("Unreferenced anonymous class " + child.classStruct.qualifiedName + "!", IFernflowerLogger.Severity.WARN);
+ }
+ else if (child.type == ClassNode.CLASS_LOCAL) {
+ DecompilerContext.getLogger()
+ .writeMessage("Unreferenced local class " + child.classStruct.qualifiedName + "!", IFernflowerLogger.Severity.WARN);
+ }
+ }
+ }
+ }
+ }
+
+ private static boolean insertNestedClass(ClassNode root, ClassNode child) {
+
+ Set<String> setEnclosing = child.enclosingClasses;
+
+ LinkedList<ClassNode> stack = new LinkedList<ClassNode>();
+ stack.add(root);
+
+ while (!stack.isEmpty()) {
+
+ ClassNode node = stack.removeFirst();
+
+ if (setEnclosing.contains(node.classStruct.qualifiedName)) {
+ node.nested.add(child);
+ child.parent = node;
+
+ return true;
+ }
+
+ // note: ordered list
+ stack.addAll(node.nested);
+ }
+
+ return false;
+ }
+
+
+ private static void computeLocalVarsAndDefinitions(final ClassNode node) {
+
+ // local var masks
+ // class name, constructor descriptor, field mask
+ final HashMap<String, HashMap<String, List<VarFieldPair>>> mapVarMasks = new HashMap<String, HashMap<String, List<VarFieldPair>>>();
+
+ int cltypes = 0;
+
+ for (ClassNode nd : node.nested) {
+ if (nd.type != ClassNode.CLASS_LAMBDA) {
+ if ((nd.access & CodeConstants.ACC_STATIC) == 0 && (nd.access & CodeConstants.ACC_INTERFACE) == 0) {
+
+ cltypes |= nd.type;
+
+ HashMap<String, List<VarFieldPair>> mask = getMaskLocalVars(nd.wrapper);
+ if (mask.isEmpty()) {
+ DecompilerContext.getLogger()
+ .writeMessage("Nested class " + nd.classStruct.qualifiedName + " has no constructor!", IFernflowerLogger.Severity.WARN);
+ }
+ else {
+ mapVarMasks.put(nd.classStruct.qualifiedName, mask);
+ }
+ }
+ }
+ }
+
+ // local var masks
+ final HashMap<String, HashMap<String, List<VarFieldPair>>> mapVarFieldPairs =
+ new HashMap<String, HashMap<String, List<VarFieldPair>>>();
+
+ if (cltypes != ClassNode.CLASS_MEMBER) {
+
+ // iterate enclosing class
+ for (final MethodWrapper meth : node.wrapper.getMethods()) {
+
+ if (meth.root != null) { // neither abstract, nor native
+ DirectGraph graph = meth.getOrBuildGraph();
+
+ graph.iterateExprents(new DirectGraph.ExprentIterator() {
+ public int processExprent(Exprent exprent) {
+ List<Exprent> lst = exprent.getAllExprents(true);
+ lst.add(exprent);
+
+ for (Exprent expr : lst) {
+
+ if (expr.type == Exprent.EXPRENT_NEW) {
+ InvocationExprent constr = ((NewExprent)expr).getConstructor();
+
+ if (constr != null && mapVarMasks.containsKey(constr.getClassname())) { // non-static inner class constructor
+
+ String refclname = constr.getClassname();
+
+ ClassNode nestedClassNode = node.getClassNode(refclname);
+
+ if (nestedClassNode.type != ClassNode.CLASS_MEMBER) {
+
+ List<VarFieldPair> mask = mapVarMasks.get(refclname).get(constr.getStringDescriptor());
+
+ if (!mapVarFieldPairs.containsKey(refclname)) {
+ mapVarFieldPairs.put(refclname, new HashMap<String, List<VarFieldPair>>());
+ }
+
+ List<VarFieldPair> lstTemp = new ArrayList<VarFieldPair>();
+
+ for (int i = 0; i < mask.size(); i++) {
+ Exprent param = constr.getLstParameters().get(i);
+ VarFieldPair pair = null;
+
+ if (param.type == Exprent.EXPRENT_VAR && mask.get(i) != null) {
+ VarVersionPaar varpaar = new VarVersionPaar((VarExprent)param);
+
+ // FIXME: final flags of variables are wrong! Correct the entire final functionality.
+ // if(meth.varproc.getVarFinal(varpaar) != VarTypeProcessor.VAR_NONFINAL) {
+ pair = new VarFieldPair(mask.get(i).keyfield, varpaar);
+ // }
+ }
+
+ lstTemp.add(pair);
+ }
+
+ List<VarFieldPair> pairmask = mapVarFieldPairs.get(refclname).get(constr.getStringDescriptor());
+
+ if (pairmask == null) {
+ pairmask = lstTemp;
+ }
+ else {
+ for (int i = 0; i < pairmask.size(); i++) {
+ if (!InterpreterUtil.equalObjects(pairmask.get(i), lstTemp.get(i))) {
+ pairmask.set(i, null);
+ }
+ }
+ }
+
+ mapVarFieldPairs.get(refclname).put(constr.getStringDescriptor(), pairmask);
+ nestedClassNode.enclosingMethod =
+ InterpreterUtil.makeUniqueKey(meth.methodStruct.getName(), meth.methodStruct.getDescriptor());
+ }
+ }
+ }
+ }
+ return 0;
+ }
+ });
+ }
+ }
+ }
+
+ // merge var masks
+ for (Entry<String, HashMap<String, List<VarFieldPair>>> entcl : mapVarMasks.entrySet()) {
+
+ ClassNode nestedNode = node.getClassNode(entcl.getKey());
+
+ // intersection
+ List<VarFieldPair> intrPairMask = null;
+ // merge referenced constructors
+ if (mapVarFieldPairs.containsKey(entcl.getKey())) {
+ for (List<VarFieldPair> mask : mapVarFieldPairs.get(entcl.getKey()).values()) {
+ if (intrPairMask == null) {
+ intrPairMask = new ArrayList<VarFieldPair>(mask);
+ }
+ else {
+ mergeListSignatures(intrPairMask, mask, false);
+ }
+ }
+ }
+
+ List<VarFieldPair> intrMask = null;
+ // merge all constructors
+ for (List<VarFieldPair> mask : entcl.getValue().values()) {
+ if (intrMask == null) {
+ intrMask = new ArrayList<VarFieldPair>(mask);
+ }
+ else {
+ mergeListSignatures(intrMask, mask, false);
+ }
+ }
+
+ if (intrPairMask == null) { // member or local and never instantiated
+ intrPairMask = new ArrayList<VarFieldPair>(intrMask);
+
+ boolean found = false;
+
+ for (int i = 0; i < intrPairMask.size(); i++) {
+ if (intrPairMask.get(i) != null) {
+ if (found) {
+ intrPairMask.set(i, null);
+ }
+ found = true;
+ }
+ }
+ }
+
+ mergeListSignatures(intrPairMask, intrMask, true);
+
+ for (int i = 0; i < intrPairMask.size(); i++) {
+ VarFieldPair pair = intrPairMask.get(i);
+ if (pair != null && pair.keyfield.length() > 0) {
+ nestedNode.mapFieldsToVars.put(pair.keyfield, pair.varpaar);
+ }
+ }
+
+ // set resulting constructor signatures
+ for (Entry<String, List<VarFieldPair>> entmt : entcl.getValue().entrySet()) {
+ mergeListSignatures(entmt.getValue(), intrPairMask, false);
+
+ MethodWrapper meth = nestedNode.wrapper.getMethodWrapper("<init>", entmt.getKey());
+ meth.signatureFields = new ArrayList<VarVersionPaar>();
+
+ for (VarFieldPair pair : entmt.getValue()) {
+ meth.signatureFields.add(pair == null ? null : pair.varpaar);
+ }
+ }
+ }
+ }
+
+ private static void insertLocalVars(final ClassNode parent, final ClassNode child) {
+
+ // enclosing method, is null iff member class
+ MethodWrapper encmeth = parent.wrapper.getMethods().getWithKey(child.enclosingMethod);
+
+ // iterate all child methods
+ for (final MethodWrapper meth : child.wrapper.getMethods()) {
+
+ if (meth.root != null) { // neither abstract nor native
+
+ // local var names
+ HashMap<VarVersionPaar, String> mapNewNames = new HashMap<VarVersionPaar, String>();
+ // local var types
+ HashMap<VarVersionPaar, VarType> mapNewTypes = new HashMap<VarVersionPaar, VarType>();
+
+ final HashMap<Integer, VarVersionPaar> mapParamsToNewVars = new HashMap<Integer, VarVersionPaar>();
+ if (meth.signatureFields != null) {
+ int index = 0;
+ int varindex = 1;
+ MethodDescriptor md = MethodDescriptor.parseDescriptor(meth.methodStruct.getDescriptor());
+
+ for (VarVersionPaar paar : meth.signatureFields) {
+ if (paar != null) {
+ VarVersionPaar newvar = new VarVersionPaar(meth.counter.getCounterAndIncrement(CounterContainer.VAR_COUNTER), 0);
+
+ mapParamsToNewVars.put(varindex, newvar);
+
+ String varname = null;
+ VarType vartype = null;
+
+ if (child.type != ClassNode.CLASS_MEMBER) {
+ varname = encmeth.varproc.getVarName(paar);
+ vartype = encmeth.varproc.getVarType(paar);
+
+ encmeth.varproc.setVarFinal(paar, VarTypeProcessor.VAR_FINALEXPLICIT);
+ }
+
+ if (paar.var == -1 || "this".equals(varname)) {
+ if (parent.simpleName == null) {
+ // anonymous enclosing class, no access to this
+ varname = VarExprent.VAR_NAMELESS_ENCLOSURE;
+ }
+ else {
+ varname = parent.simpleName + ".this";
+ }
+ meth.varproc.getThisvars().put(newvar, parent.classStruct.qualifiedName);
+ }
+
+ mapNewNames.put(newvar, varname);
+ mapNewTypes.put(newvar, vartype);
+ }
+ varindex += md.params[index++].stack_size;
+ }
+ }
+
+ // new vars
+ final HashMap<String, VarVersionPaar> mapFieldsToNewVars = new HashMap<String, VarVersionPaar>();
+
+ for (ClassNode clnode = child; clnode != null; clnode = clnode.parent) {
+
+ for (Entry<String, VarVersionPaar> entr : clnode.mapFieldsToVars.entrySet()) {
+ VarVersionPaar newvar = new VarVersionPaar(meth.counter.getCounterAndIncrement(CounterContainer.VAR_COUNTER), 0);
+
+ mapFieldsToNewVars.put(InterpreterUtil.makeUniqueKey(clnode.classStruct.qualifiedName, entr.getKey()), newvar);
+
+ String varname = null;
+ VarType vartype = null;
+
+ if (clnode.type != ClassNode.CLASS_MEMBER) {
+
+ MethodWrapper enclosing_method = clnode.parent.wrapper.getMethods().getWithKey(clnode.enclosingMethod);
+
+ varname = enclosing_method.varproc.getVarName(entr.getValue());
+ vartype = enclosing_method.varproc.getVarType(entr.getValue());
+
+ enclosing_method.varproc.setVarFinal(entr.getValue(), VarTypeProcessor.VAR_FINALEXPLICIT);
+ }
+
+ if (entr.getValue().var == -1 || "this".equals(varname)) {
+ if (clnode.parent.simpleName == null) {
+ // anonymous enclosing class, no access to this
+ varname = VarExprent.VAR_NAMELESS_ENCLOSURE;
+ }
+ else {
+ varname = clnode.parent.simpleName + ".this";
+ }
+ meth.varproc.getThisvars().put(newvar, clnode.parent.classStruct.qualifiedName);
+ }
+
+ mapNewNames.put(newvar, varname);
+ mapNewTypes.put(newvar, vartype);
+
+ // hide synthetic field
+ if (clnode == child) { // fields higher up the chain were already handled with their classes
+ StructField fd = child.classStruct.getFields().getWithKey(entr.getKey());
+ child.wrapper.getHiddenMembers().add(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor()));
+ }
+ }
+ }
+
+ HashSet<String> setNewOuterNames = new HashSet<String>(mapNewNames.values());
+ setNewOuterNames.removeAll(meth.setOuterVarNames);
+
+ meth.varproc.refreshVarNames(new VarNamesCollector(setNewOuterNames));
+ meth.setOuterVarNames.addAll(setNewOuterNames);
+
+ for (Entry<VarVersionPaar, String> entr : mapNewNames.entrySet()) {
+ VarVersionPaar varpaar = entr.getKey();
+ VarType vartype = mapNewTypes.get(varpaar);
+
+ meth.varproc.setVarName(varpaar, entr.getValue());
+ if (vartype != null) {
+ meth.varproc.setVarType(varpaar, vartype);
+ }
+ }
+
+ DirectGraph graph = meth.getOrBuildGraph();
+
+ graph.iterateExprents(new DirectGraph.ExprentIterator() {
+ public int processExprent(Exprent exprent) {
+
+ if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent asexpr = (AssignmentExprent)exprent;
+ if (asexpr.getLeft().type == Exprent.EXPRENT_FIELD) {
+ FieldExprent fexpr = (FieldExprent)asexpr.getLeft();
+
+ if (fexpr.getClassname().equals(child.classStruct.qualifiedName) && // process this class only
+ mapFieldsToNewVars.containsKey(InterpreterUtil.makeUniqueKey(child.classStruct.qualifiedName,
+ InterpreterUtil.makeUniqueKey(fexpr.getName(), fexpr
+ .getDescriptor().descriptorString)))) {
+ return 2;
+ }
+
+ //if(fexpr.getClassname().equals(child.classStruct.qualifiedName) &&
+ // mapFieldsToNewVars.containsKey(InterpreterUtil.makeUniqueKey(fexpr.getName(), fexpr.getDescriptor().descriptorString))) {
+ // return 2;
+ //}
+ }
+ }
+
+ if (child.type == ClassNode.CLASS_ANONYMOUS && "<init>".equals(meth.methodStruct.getName())
+ && exprent.type == Exprent.EXPRENT_INVOCATION) {
+ InvocationExprent invexpr = (InvocationExprent)exprent;
+ if (invexpr.getFunctype() == InvocationExprent.TYP_INIT) {
+ // invocation of the super constructor in an anonymous class
+ child.superInvocation = invexpr; // FIXME: save original names of parameters
+ return 2;
+ }
+ }
+
+ replaceExprent(exprent);
+
+ return 0;
+ }
+
+ private Exprent replaceExprent(Exprent exprent) {
+
+ if (exprent.type == Exprent.EXPRENT_VAR) {
+ int varindex = ((VarExprent)exprent).getIndex();
+ if (mapParamsToNewVars.containsKey(varindex)) {
+ VarVersionPaar newvar = mapParamsToNewVars.get(varindex);
+ meth.varproc.getExternvars().add(newvar);
+ return new VarExprent(newvar.var, meth.varproc.getVarType(newvar), meth.varproc);
+ }
+ }
+ else if (exprent.type == Exprent.EXPRENT_FIELD) {
+ FieldExprent fexpr = (FieldExprent)exprent;
+
+ String keyField = InterpreterUtil.makeUniqueKey(fexpr.getClassname(), InterpreterUtil
+ .makeUniqueKey(fexpr.getName(), fexpr.getDescriptor().descriptorString));
+
+ if (mapFieldsToNewVars.containsKey(keyField)) {
+ //if(fexpr.getClassname().equals(child.classStruct.qualifiedName) &&
+ // mapFieldsToNewVars.containsKey(keyField)) {
+ VarVersionPaar newvar = mapFieldsToNewVars.get(keyField);
+ meth.varproc.getExternvars().add(newvar);
+ return new VarExprent(newvar.var, meth.varproc.getVarType(newvar), meth.varproc);
+ }
+ }
+
+ boolean replaced = true;
+ while (replaced) {
+ replaced = false;
+
+ for (Exprent expr : exprent.getAllExprents()) {
+ Exprent retexpr = replaceExprent(expr);
+ if (retexpr != null) {
+ exprent.replaceExprent(expr, retexpr);
+ replaced = true;
+ break;
+ }
+ }
+ }
+
+ return null;
+ }
+ });
+ }
+ }
+ }
+
+ private static HashMap<String, List<VarFieldPair>> getMaskLocalVars(ClassWrapper wrapper) {
+
+ HashMap<String, List<VarFieldPair>> mapMasks = new HashMap<String, List<VarFieldPair>>();
+
+ StructClass cl = wrapper.getClassStruct();
+
+ // iterate over constructors
+ for (StructMethod mt : cl.getMethods()) {
+ if ("<init>".equals(mt.getName())) {
+
+ MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
+
+ MethodWrapper meth = wrapper.getMethodWrapper("<init>", mt.getDescriptor());
+ DirectGraph graph = meth.getOrBuildGraph();
+
+ if (graph != null) { // something gone wrong, should not be null
+ List<VarFieldPair> fields = new ArrayList<VarFieldPair>();
+
+ int varindex = 1;
+ for (int i = 0; i < md.params.length; i++) { // no static methods allowed
+ String keyField = getEnclosingVarField(cl, meth, graph, varindex);
+ fields.add(keyField == null ? null : new VarFieldPair(keyField, new VarVersionPaar(-1, 0))); // TODO: null?
+ varindex += md.params[i].stack_size;
+ }
+ mapMasks.put(mt.getDescriptor(), fields);
+ }
+ }
+ }
+
+ return mapMasks;
+ }
+
+ private static String getEnclosingVarField(StructClass cl, MethodWrapper meth, DirectGraph graph, final int index) {
+
+ String field = "";
+
+ // parameter variable final
+ if (meth.varproc.getVarFinal(new VarVersionPaar(index, 0)) == VarTypeProcessor.VAR_NONFINAL) {
+ return null;
+ }
+
+ boolean noSynthFlag = DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET);
+
+ // no loop at the begin
+ DirectNode firstnode = graph.first;
+ if (firstnode.preds.isEmpty()) {
+ // assignment to a final synthetic field?
+ for (Exprent exprent : firstnode.exprents) {
+ if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent asexpr = (AssignmentExprent)exprent;
+ if (asexpr.getRight().type == Exprent.EXPRENT_VAR && ((VarExprent)asexpr.getRight()).getIndex() == index) {
+ if (asexpr.getLeft().type == Exprent.EXPRENT_FIELD) {
+
+ FieldExprent left = (FieldExprent)asexpr.getLeft();
+ StructField fd = cl.getField(left.getName(), left.getDescriptor().descriptorString);
+
+ if (fd != null) { // local (== not inherited) field
+ if (cl.qualifiedName.equals(left.getClassname()) &&
+ fd.hasModifier(CodeConstants.ACC_FINAL) &&
+ (fd.isSynthetic() || (noSynthFlag && fd.hasModifier(CodeConstants.ACC_PRIVATE)))) {
+ field = InterpreterUtil.makeUniqueKey(left.getName(), left.getDescriptor().descriptorString);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return field;
+ }
+
+ private static void mergeListSignatures(List<VarFieldPair> first, List<VarFieldPair> second, boolean both) {
+
+ int i = 1;
+ while (true) {
+ if (first.size() <= i || second.size() <= i) {
+ break;
+ }
+
+ VarFieldPair fobj = first.get(first.size() - i);
+ VarFieldPair sobj = second.get(second.size() - i);
+
+ boolean eq = false;
+ if (fobj == null || sobj == null) {
+ eq = (fobj == sobj);
+ }
+ else {
+ eq = true;
+ if (fobj.keyfield.length() == 0) {
+ fobj.keyfield = sobj.keyfield;
+ }
+ else if (sobj.keyfield.length() == 0) {
+ if (both) {
+ sobj.keyfield = fobj.keyfield;
+ }
+ }
+ else {
+ eq = fobj.keyfield.equals(sobj.keyfield);
+ }
+ }
+
+ if (!eq) {
+ first.set(first.size() - i, null);
+ if (both) {
+ second.set(second.size() - i, null);
+ }
+ }
+ else {
+ if (fobj != null) {
+ if (fobj.varpaar.var == -1) {
+ fobj.varpaar = sobj.varpaar;
+ }
+ else {
+ sobj.varpaar = fobj.varpaar;
+ }
+ }
+ }
+ i++;
+ }
+
+ for (int j = 1; j <= first.size() - i; j++) {
+ first.set(j, null);
+ }
+
+ if (both) {
+ for (int j = 1; j <= second.size() - i; j++) {
+ second.set(j, null);
+ }
+ }
+
+ // first
+ if (first.isEmpty()) {
+ if (!second.isEmpty() && both) {
+ second.set(0, null);
+ }
+ }
+ else if (second.isEmpty()) {
+ first.set(0, null);
+ }
+ else {
+ VarFieldPair fobj = first.get(0);
+ VarFieldPair sobj = second.get(0);
+
+ boolean eq = false;
+ if (fobj == null || sobj == null) {
+ eq = (fobj == sobj);
+ }
+ else {
+ eq = true;
+ if (fobj.keyfield.length() == 0) {
+ fobj.keyfield = sobj.keyfield;
+ }
+ else if (sobj.keyfield.length() == 0) {
+ if (both) {
+ sobj.keyfield = fobj.keyfield;
+ }
+ }
+ else {
+ eq = fobj.keyfield.equals(sobj.keyfield);
+ }
+ }
+
+ if (!eq) {
+ first.set(0, null);
+ if (both) {
+ second.set(0, null);
+ }
+ }
+ else if (fobj != null) {
+ if (fobj.varpaar.var == -1) {
+ fobj.varpaar = sobj.varpaar;
+ }
+ else {
+ sobj.varpaar = fobj.varpaar;
+ }
+ }
+ }
+ }
+
+
+ private static void setLocalClassDefinition(MethodWrapper meth, ClassNode node) {
+
+ RootStatement root = meth.root;
+
+ HashSet<Statement> setStats = new HashSet<Statement>();
+ VarType classtype = new VarType(node.classStruct.qualifiedName, true);
+
+ Statement stdef = getDefStatement(root, classtype, setStats);
+ if (stdef == null) {
+ // unreferenced local class
+ stdef = root.getFirst();
+ }
+
+ Statement first = findFirstBlock(stdef, setStats);
+
+ List<Exprent> lst;
+ if (first == null) {
+ lst = stdef.getVarDefinitions();
+ }
+ else if (first.getExprents() == null) {
+ lst = first.getVarDefinitions();
+ }
+ else {
+ lst = first.getExprents();
+ }
+
+
+ int addindex = 0;
+ for (Exprent expr : lst) {
+ if (searchForClass(expr, classtype)) {
+ break;
+ }
+ addindex++;
+ }
+
+ VarExprent var = new VarExprent(meth.counter.getCounterAndIncrement(CounterContainer.VAR_COUNTER),
+ classtype, meth.varproc);
+ var.setDefinition(true);
+ var.setClassdef(true);
+
+ lst.add(addindex, var);
+ }
+
+
+ private static Statement findFirstBlock(Statement stat, HashSet<Statement> setStats) {
+
+ LinkedList<Statement> stack = new LinkedList<Statement>();
+ stack.add(stat);
+
+ while (!stack.isEmpty()) {
+ Statement st = stack.remove(0);
+
+ if (stack.isEmpty() || setStats.contains(st)) {
+
+ if (st.isLabeled() && !stack.isEmpty()) {
+ return st;
+ }
+
+ if (st.getExprents() != null) {
+ return st;
+ }
+ else {
+ stack.clear();
+
+ switch (st.type) {
+ case Statement.TYPE_SEQUENCE:
+ stack.addAll(0, st.getStats());
+ break;
+ case Statement.TYPE_IF:
+ case Statement.TYPE_ROOT:
+ case Statement.TYPE_SWITCH:
+ case Statement.TYPE_SYNCRONIZED:
+ stack.add(st.getFirst());
+ break;
+ default:
+ return st;
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+
+ private static Statement getDefStatement(Statement stat, VarType classtype, HashSet<Statement> setStats) {
+
+ List<Exprent> condlst = new ArrayList<Exprent>();
+ Statement retstat = null;
+
+ if (stat.getExprents() == null) {
+ int counter = 0;
+
+ for (Object obj : stat.getSequentialObjects()) {
+ if (obj instanceof Statement) {
+ Statement st = (Statement)obj;
+
+ Statement stTemp = getDefStatement(st, classtype, setStats);
+
+ if (stTemp != null) {
+ if (counter == 1) {
+ retstat = stat;
+ break;
+ }
+ retstat = stTemp;
+ counter++;
+ }
+
+ if (st.type == DoStatement.TYPE_DO) {
+ DoStatement dost = (DoStatement)st;
+
+ condlst.addAll(dost.getInitExprentList());
+ condlst.addAll(dost.getConditionExprentList());
+ }
+ }
+ else if (obj instanceof Exprent) {
+ condlst.add((Exprent)obj);
+ }
+ }
+ }
+ else {
+ condlst = stat.getExprents();
+ }
+
+ if (retstat != stat) {
+ for (Exprent exprent : condlst) {
+ if (exprent != null && searchForClass(exprent, classtype)) {
+ retstat = stat;
+ break;
+ }
+ }
+ }
+
+ if (retstat != null) {
+ setStats.add(stat);
+ }
+
+ return retstat;
+ }
+
+ private static boolean searchForClass(Exprent exprent, VarType classtype) {
+
+ List<Exprent> lst = exprent.getAllExprents(true);
+ lst.add(exprent);
+
+ String classname = classtype.value;
+
+ for (Exprent expr : lst) {
+
+ boolean res = false;
+
+ switch (expr.type) {
+ case Exprent.EXPRENT_CONST:
+ ConstExprent cexpr = (ConstExprent)expr;
+ res = (VarType.VARTYPE_CLASS.equals(cexpr.getConsttype()) && classname.equals(cexpr.getValue()) ||
+ classtype.equals(cexpr.getConsttype()));
+ break;
+ case Exprent.EXPRENT_FIELD:
+ res = classname.equals(((FieldExprent)expr).getClassname());
+ break;
+ case Exprent.EXPRENT_INVOCATION:
+ res = classname.equals(((InvocationExprent)expr).getClassname());
+ break;
+ case Exprent.EXPRENT_NEW:
+ VarType newType = expr.getExprType();
+ res = newType.type == CodeConstants.TYPE_OBJECT && classname.equals(newType.value);
+ break;
+ case Exprent.EXPRENT_VAR:
+ VarExprent vexpr = (VarExprent)expr;
+ if (vexpr.isDefinition()) {
+ VarType vtype = vexpr.getVartype();
+ if (classtype.equals(vtype) || (vtype.arraydim > 0 && classtype.value.equals(vtype.value))) {
+ res = true;
+ }
+ }
+ }
+
+ if (res) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ private static class VarFieldPair {
+
+ public String keyfield = "";
+ public VarVersionPaar varpaar;
+
+ public VarFieldPair(String field, VarVersionPaar varpaar) {
+ this.keyfield = field;
+ this.varpaar = varpaar;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof VarFieldPair)) return false;
+
+ VarFieldPair pair = (VarFieldPair)o;
+ return keyfield.equals(pair.keyfield) && varpaar.equals(pair.varpaar);
+ }
+
+ @Override
+ public int hashCode() {
+ return keyfield.hashCode() + varpaar.hashCode();
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/rels/NestedMemberAccess.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/rels/NestedMemberAccess.java
new file mode 100644
index 000000000000..7e5eaa54326a
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/main/rels/NestedMemberAccess.java
@@ -0,0 +1,449 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.main.rels;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
+import org.jetbrains.java.decompiler.main.collectors.VarNamesCollector;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
+import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectGraph;
+import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectNode;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar;
+import org.jetbrains.java.decompiler.struct.StructMethod;
+import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Map;
+
+public class NestedMemberAccess {
+
+ private static final int METHOD_ACCESS_NORMAL = 1;
+ private static final int METHOD_ACCESS_FIELD_GET = 2;
+ private static final int METHOD_ACCESS_FIELD_SET = 3;
+ private static final int METHOD_ACCESS_METHOD = 4;
+
+ private boolean noSynthFlag;
+ private Map<MethodWrapper, Integer> mapMethodType = new HashMap<MethodWrapper, Integer>();
+
+
+ public void propagateMemberAccess(ClassNode root) {
+ if (root.nested.isEmpty()) {
+ return;
+ }
+
+ noSynthFlag = DecompilerContext.getOption(IFernflowerPreferences.SYNTHETIC_NOT_SET);
+
+ computeMethodTypes(root);
+
+ eliminateStaticAccess(root);
+ }
+
+
+ private void computeMethodTypes(ClassNode node) {
+ if (node.type == ClassNode.CLASS_LAMBDA) {
+ return;
+ }
+
+ for (ClassNode nd : node.nested) {
+ computeMethodTypes(nd);
+ }
+
+ for (MethodWrapper method : node.wrapper.getMethods()) {
+ computeMethodType(node, method);
+ }
+ }
+
+ private void computeMethodType(ClassNode node, MethodWrapper method) {
+ int type = METHOD_ACCESS_NORMAL;
+
+ if (method.root != null) {
+ DirectGraph graph = method.getOrBuildGraph();
+
+ StructMethod mt = method.methodStruct;
+ if ((noSynthFlag || mt.isSynthetic()) && mt.hasModifier(CodeConstants.ACC_STATIC)) {
+ if (graph.nodes.size() == 2) { // incl. dummy exit node
+ if (graph.first.exprents.size() == 1) {
+ Exprent exprent = graph.first.exprents.get(0);
+
+ MethodDescriptor mtdesc = MethodDescriptor.parseDescriptor(mt.getDescriptor());
+ int parcount = mtdesc.params.length;
+
+ Exprent exprCore = exprent;
+
+ if (exprent.type == Exprent.EXPRENT_EXIT) {
+ ExitExprent exexpr = (ExitExprent)exprent;
+ if (exexpr.getExittype() == ExitExprent.EXIT_RETURN && exexpr.getValue() != null) {
+ exprCore = exexpr.getValue();
+ }
+ }
+
+ switch (exprCore.type) {
+ case Exprent.EXPRENT_FIELD:
+ FieldExprent fexpr = (FieldExprent)exprCore;
+ if ((parcount == 1 && !fexpr.isStatic()) ||
+ (parcount == 0 && fexpr.isStatic())) {
+ if (fexpr.getClassname().equals(node.classStruct.qualifiedName)) { // FIXME: check for private flag of the field
+ if (fexpr.isStatic() ||
+ (fexpr.getInstance().type == Exprent.EXPRENT_VAR && ((VarExprent)fexpr.getInstance()).getIndex() == 0)) {
+ type = METHOD_ACCESS_FIELD_GET;
+ }
+ }
+ }
+ break;
+ case Exprent.EXPRENT_VAR: // qualified this
+ if (parcount == 1) {
+ // this or final variable
+ if (((VarExprent)exprCore).getIndex() != 0) {
+ type = METHOD_ACCESS_FIELD_GET;
+ }
+ }
+
+ break;
+ case Exprent.EXPRENT_INVOCATION:
+ type = METHOD_ACCESS_METHOD;
+ break;
+ case Exprent.EXPRENT_ASSIGNMENT:
+ AssignmentExprent asexpr = (AssignmentExprent)exprCore;
+ if (asexpr.getLeft().type == Exprent.EXPRENT_FIELD && asexpr.getRight().type == Exprent.EXPRENT_VAR) {
+ FieldExprent fexpras = (FieldExprent)asexpr.getLeft();
+ if ((parcount == 2 && !fexpras.isStatic()) ||
+ (parcount == 1 && fexpras.isStatic())) {
+ if (fexpras.getClassname().equals(node.classStruct.qualifiedName)) { // FIXME: check for private flag of the field
+ if (fexpras.isStatic() ||
+ (fexpras.getInstance().type == Exprent.EXPRENT_VAR && ((VarExprent)fexpras.getInstance()).getIndex() == 0)) {
+ if (((VarExprent)asexpr.getRight()).getIndex() == parcount - 1) {
+ type = METHOD_ACCESS_FIELD_SET;
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ if (type == METHOD_ACCESS_METHOD) { // FIXME: check for private flag of the method
+
+ type = METHOD_ACCESS_NORMAL;
+
+ InvocationExprent invexpr = (InvocationExprent)exprCore;
+
+ if ((invexpr.isStatic() && invexpr.getLstParameters().size() == parcount) ||
+ (!invexpr.isStatic() && invexpr.getInstance().type == Exprent.EXPRENT_VAR
+ && ((VarExprent)invexpr.getInstance()).getIndex() == 0 && invexpr.getLstParameters().size() == parcount - 1)) {
+
+ boolean equalpars = true;
+
+ for (int i = 0; i < invexpr.getLstParameters().size(); i++) {
+ Exprent parexpr = invexpr.getLstParameters().get(i);
+ if (parexpr.type != Exprent.EXPRENT_VAR ||
+ ((VarExprent)parexpr).getIndex() != i + (invexpr.isStatic() ? 0 : 1)) {
+ equalpars = false;
+ break;
+ }
+ }
+
+ if (equalpars) {
+ type = METHOD_ACCESS_METHOD;
+ }
+ }
+ }
+ }
+ else if (graph.first.exprents.size() == 2) {
+ Exprent exprentFirst = graph.first.exprents.get(0);
+ Exprent exprentSecond = graph.first.exprents.get(1);
+
+ if (exprentFirst.type == Exprent.EXPRENT_ASSIGNMENT &&
+ exprentSecond.type == Exprent.EXPRENT_EXIT) {
+
+ MethodDescriptor mtdesc = MethodDescriptor.parseDescriptor(mt.getDescriptor());
+ int parcount = mtdesc.params.length;
+
+ AssignmentExprent asexpr = (AssignmentExprent)exprentFirst;
+ if (asexpr.getLeft().type == Exprent.EXPRENT_FIELD && asexpr.getRight().type == Exprent.EXPRENT_VAR) {
+ FieldExprent fexpras = (FieldExprent)asexpr.getLeft();
+ if ((parcount == 2 && !fexpras.isStatic()) ||
+ (parcount == 1 && fexpras.isStatic())) {
+ if (fexpras.getClassname().equals(node.classStruct.qualifiedName)) { // FIXME: check for private flag of the field
+ if (fexpras.isStatic() ||
+ (fexpras.getInstance().type == Exprent.EXPRENT_VAR && ((VarExprent)fexpras.getInstance()).getIndex() == 0)) {
+ if (((VarExprent)asexpr.getRight()).getIndex() == parcount - 1) {
+
+ ExitExprent exexpr = (ExitExprent)exprentSecond;
+ if (exexpr.getExittype() == ExitExprent.EXIT_RETURN && exexpr.getValue() != null) {
+ if (exexpr.getValue().type == Exprent.EXPRENT_VAR &&
+ ((VarExprent)asexpr.getRight()).getIndex() == parcount - 1) {
+ type = METHOD_ACCESS_FIELD_SET;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (type != METHOD_ACCESS_NORMAL) {
+ mapMethodType.put(method, type);
+ }
+ else {
+ mapMethodType.remove(method);
+ }
+ }
+
+
+ private void eliminateStaticAccess(ClassNode node) {
+
+ if (node.type == ClassNode.CLASS_LAMBDA) {
+ return;
+ }
+
+ for (MethodWrapper meth : node.wrapper.getMethods()) {
+
+ if (meth.root != null) {
+
+ boolean replaced = false;
+
+ DirectGraph graph = meth.getOrBuildGraph();
+
+ HashSet<DirectNode> setVisited = new HashSet<DirectNode>();
+ LinkedList<DirectNode> stack = new LinkedList<DirectNode>();
+ stack.add(graph.first);
+
+ while (!stack.isEmpty()) { // TODO: replace with interface iterator?
+
+ DirectNode nd = stack.removeFirst();
+
+ if (setVisited.contains(nd)) {
+ continue;
+ }
+ setVisited.add(nd);
+
+ for (int i = 0; i < nd.exprents.size(); i++) {
+ Exprent exprent = nd.exprents.get(i);
+
+ replaced |= replaceInvocations(node, meth, exprent);
+
+ if (exprent.type == Exprent.EXPRENT_INVOCATION) {
+ Exprent ret = replaceAccessExprent(node, meth, (InvocationExprent)exprent);
+
+ if (ret != null) {
+ nd.exprents.set(i, ret);
+ replaced = true;
+ }
+ }
+ }
+
+ for (DirectNode ndx : nd.succs) {
+ stack.add(ndx);
+ }
+ }
+
+ if (replaced) {
+ computeMethodType(node, meth);
+ }
+ }
+ }
+
+ for (ClassNode child : node.nested) {
+ eliminateStaticAccess(child);
+ }
+ }
+
+
+ private boolean replaceInvocations(ClassNode caller, MethodWrapper meth, Exprent exprent) {
+
+ boolean res = false;
+
+ for (Exprent expr : exprent.getAllExprents()) {
+ res |= replaceInvocations(caller, meth, expr);
+ }
+
+ while (true) {
+
+ boolean found = false;
+
+ for (Exprent expr : exprent.getAllExprents()) {
+ if (expr.type == Exprent.EXPRENT_INVOCATION) {
+ Exprent newexpr = replaceAccessExprent(caller, meth, (InvocationExprent)expr);
+ if (newexpr != null) {
+ exprent.replaceExprent(expr, newexpr);
+ found = true;
+ res = true;
+ break;
+ }
+ }
+ }
+
+ if (!found) {
+ break;
+ }
+ }
+
+ return res;
+ }
+
+ private static boolean sameTree(ClassNode caller, ClassNode callee) {
+
+ if (caller.classStruct.qualifiedName.equals(callee.classStruct.qualifiedName)) {
+ return false;
+ }
+
+ while (caller.parent != null) {
+ caller = caller.parent;
+ }
+
+ while (callee.parent != null) {
+ callee = callee.parent;
+ }
+
+ return caller == callee;
+ }
+
+ private Exprent replaceAccessExprent(ClassNode caller, MethodWrapper methdest, InvocationExprent invexpr) {
+
+ ClassNode node = DecompilerContext.getClassProcessor().getMapRootClasses().get(invexpr.getClassname());
+
+ MethodWrapper methsource = null;
+ if (node != null && node.wrapper != null) {
+ methsource = node.wrapper.getMethodWrapper(invexpr.getName(), invexpr.getStringDescriptor());
+ }
+
+ if (methsource == null || !mapMethodType.containsKey(methsource)) {
+ return null;
+ }
+
+ // if same method, return
+ if (node.classStruct.qualifiedName.equals(caller.classStruct.qualifiedName) &&
+ methsource.methodStruct.getName().equals(methdest.methodStruct.getName()) &&
+ methsource.methodStruct.getDescriptor().equals(methdest.methodStruct.getDescriptor())) {
+ // no recursive invocations permitted!
+ return null;
+ }
+
+ int type = mapMethodType.get(methsource);
+
+ // // FIXME: impossible case. METHOD_ACCESS_NORMAL is not saved in the map
+ // if(type == METHOD_ACCESS_NORMAL) {
+ // return null;
+ // }
+
+ if (!sameTree(caller, node)) {
+ return null;
+ }
+
+ DirectGraph graph = methsource.getOrBuildGraph();
+ Exprent source = graph.first.exprents.get(0);
+
+ Exprent retexprent = null;
+
+ switch (type) {
+ case METHOD_ACCESS_FIELD_GET:
+ ExitExprent exsource = (ExitExprent)source;
+ if (exsource.getValue().type == Exprent.EXPRENT_VAR) { // qualified this
+ VarExprent var = (VarExprent)exsource.getValue();
+ String varname = methsource.varproc.getVarName(new VarVersionPaar(var));
+
+ if (!methdest.setOuterVarNames.contains(varname)) {
+ VarNamesCollector vnc = new VarNamesCollector();
+ vnc.addName(varname);
+
+ methdest.varproc.refreshVarNames(vnc);
+ methdest.setOuterVarNames.add(varname);
+ }
+
+ int index = methdest.counter.getCounterAndIncrement(CounterContainer.VAR_COUNTER);
+ VarExprent ret = new VarExprent(index, var.getVartype(), methdest.varproc);
+ methdest.varproc.setVarName(new VarVersionPaar(index, 0), varname);
+
+ retexprent = ret;
+ }
+ else { // field
+ FieldExprent ret = (FieldExprent)exsource.getValue().copy();
+ if (!ret.isStatic()) {
+ ret.replaceExprent(ret.getInstance(), invexpr.getLstParameters().get(0));
+ }
+ retexprent = ret;
+ }
+ break;
+ case METHOD_ACCESS_FIELD_SET:
+ AssignmentExprent ret;
+ if (source.type == Exprent.EXPRENT_EXIT) {
+ ExitExprent extex = (ExitExprent)source;
+ ret = (AssignmentExprent)extex.getValue().copy();
+ }
+ else {
+ ret = (AssignmentExprent)source.copy();
+ }
+ FieldExprent fexpr = (FieldExprent)ret.getLeft();
+
+ if (fexpr.isStatic()) {
+ ret.replaceExprent(ret.getRight(), invexpr.getLstParameters().get(0));
+ }
+ else {
+ ret.replaceExprent(ret.getRight(), invexpr.getLstParameters().get(1));
+ fexpr.replaceExprent(fexpr.getInstance(), invexpr.getLstParameters().get(0));
+ }
+ retexprent = ret;
+ break;
+ case METHOD_ACCESS_METHOD:
+ if (source.type == Exprent.EXPRENT_EXIT) {
+ source = ((ExitExprent)source).getValue();
+ }
+
+ InvocationExprent invret = (InvocationExprent)source.copy();
+
+ int index = 0;
+ if (!invret.isStatic()) {
+ invret.replaceExprent(invret.getInstance(), invexpr.getLstParameters().get(0));
+ index = 1;
+ }
+
+ for (int i = 0; i < invret.getLstParameters().size(); i++) {
+ invret.replaceExprent(invret.getLstParameters().get(i), invexpr.getLstParameters().get(i + index));
+ }
+
+ retexprent = invret;
+ }
+
+
+ if (retexprent != null) {
+ // hide synthetic access method
+ boolean hide = true;
+
+ if (node.type == ClassNode.CLASS_ROOT || (node.access & CodeConstants.ACC_STATIC) != 0) {
+ StructMethod mt = methsource.methodStruct;
+ if (!mt.isSynthetic()) {
+ hide = false;
+ }
+ }
+ if (hide) {
+ node.wrapper.getHiddenMembers().add(InterpreterUtil.makeUniqueKey(invexpr.getName(), invexpr.getStringDescriptor()));
+ }
+ }
+
+ return retexprent;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/code/DeadCodeHelper.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/code/DeadCodeHelper.java
new file mode 100644
index 000000000000..c7dd8ca1c173
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/code/DeadCodeHelper.java
@@ -0,0 +1,436 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.code;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.code.Instruction;
+import org.jetbrains.java.decompiler.code.InstructionSequence;
+import org.jetbrains.java.decompiler.code.cfg.BasicBlock;
+import org.jetbrains.java.decompiler.code.cfg.ControlFlowGraph;
+import org.jetbrains.java.decompiler.code.cfg.ExceptionRangeCFG;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
+
+import java.util.*;
+
+public class DeadCodeHelper {
+
+ public static void removeDeadBlocks(ControlFlowGraph graph) {
+
+ LinkedList<BasicBlock> stack = new LinkedList<BasicBlock>();
+ HashSet<BasicBlock> setStacked = new HashSet<BasicBlock>();
+
+ stack.add(graph.getFirst());
+ setStacked.add(graph.getFirst());
+
+ while (!stack.isEmpty()) {
+ BasicBlock block = stack.removeFirst();
+
+ List<BasicBlock> lstSuccs = new ArrayList<BasicBlock>(block.getSuccs());
+ lstSuccs.addAll(block.getSuccExceptions());
+
+ for (BasicBlock succ : lstSuccs) {
+ if (!setStacked.contains(succ)) {
+ stack.add(succ);
+ setStacked.add(succ);
+ }
+ }
+ }
+
+ HashSet<BasicBlock> setAllBlocks = new HashSet<BasicBlock>(graph.getBlocks());
+ setAllBlocks.removeAll(setStacked);
+
+ for (BasicBlock block : setAllBlocks) {
+ graph.removeBlock(block);
+ }
+ }
+
+ public static void removeEmptyBlocks(ControlFlowGraph graph) {
+
+ List<BasicBlock> blocks = graph.getBlocks();
+
+ boolean cont;
+ do {
+ cont = false;
+
+ for (int i = blocks.size() - 1; i >= 0; i--) {
+ BasicBlock block = blocks.get(i);
+
+ if (removeEmptyBlock(graph, block, false)) {
+ cont = true;
+ break;
+ }
+ }
+ }
+ while (cont);
+ }
+
+ private static boolean removeEmptyBlock(ControlFlowGraph graph, BasicBlock block, boolean merging) {
+
+ boolean deletedRanges = false;
+
+ if (block.getSeq().isEmpty()) {
+
+ if (block.getSuccs().size() > 1) {
+ if (block.getPreds().size() > 1) {
+ // ambiguous block
+ throw new RuntimeException("ERROR: empty block with multiple predecessors and successors found");
+ }
+ else if (!merging) {
+ throw new RuntimeException("ERROR: empty block with multiple successors found");
+ }
+ }
+
+ HashSet<BasicBlock> setExits = new HashSet<BasicBlock>(graph.getLast().getPreds());
+
+ if (block.getPredExceptions().isEmpty() &&
+ (!setExits.contains(block) || block.getPreds().size() == 1)) {
+
+ if (setExits.contains(block)) {
+ BasicBlock pred = block.getPreds().get(0);
+
+ // FIXME: flag in the basic block
+ if (pred.getSuccs().size() != 1 || (!pred.getSeq().isEmpty()
+ && pred.getSeq().getLastInstr().group == CodeConstants.GROUP_SWITCH)) {
+ return false;
+ }
+ }
+
+ HashSet<BasicBlock> setPreds = new HashSet<BasicBlock>(block.getPreds());
+ HashSet<BasicBlock> setSuccs = new HashSet<BasicBlock>(block.getSuccs());
+
+ // collect common exception ranges of predecessors and successors
+ HashSet<BasicBlock> setCommonExceptionHandlers = null;
+ for (int i = 0; i < 2; ++i) {
+ for (BasicBlock pred : i == 0 ? setPreds : setSuccs) {
+ if (setCommonExceptionHandlers == null) {
+ setCommonExceptionHandlers = new HashSet<BasicBlock>(pred.getSuccExceptions());
+ }
+ else {
+ setCommonExceptionHandlers.retainAll(pred.getSuccExceptions());
+ }
+ }
+ }
+
+ // check the block to be in each of the common ranges
+ if (setCommonExceptionHandlers != null && !setCommonExceptionHandlers.isEmpty()) {
+ for (BasicBlock handler : setCommonExceptionHandlers) {
+ if (!block.getSuccExceptions().contains(handler)) {
+ return false;
+ }
+ }
+ }
+
+ // remove ranges consisting of this one block
+ List<ExceptionRangeCFG> lstRanges = graph.getExceptions();
+ for (int i = lstRanges.size() - 1; i >= 0; i--) {
+ ExceptionRangeCFG range = lstRanges.get(i);
+ List<BasicBlock> lst = range.getProtectedRange();
+
+ if (lst.size() == 1 && lst.get(0) == block) {
+ if (DecompilerContext.getOption(IFernflowerPreferences.REMOVE_EMPTY_RANGES)) {
+ block.removeSuccessorException(range.getHandler());
+ lstRanges.remove(i);
+
+ deletedRanges = true;
+ }
+ else {
+ return false;
+ }
+ }
+ }
+
+
+ // connect remaining nodes
+ if (merging) {
+ BasicBlock pred = block.getPreds().get(0);
+ pred.removeSuccessor(block);
+
+ List<BasicBlock> lstSuccs = new ArrayList<BasicBlock>(block.getSuccs());
+ for (BasicBlock succ : lstSuccs) {
+ block.removeSuccessor(succ);
+ pred.addSuccessor(succ);
+ }
+ }
+ else {
+ for (BasicBlock pred : setPreds) {
+ for (BasicBlock succ : setSuccs) {
+ pred.replaceSuccessor(block, succ);
+ }
+ }
+ }
+
+ // finally exit edges
+ Set<BasicBlock> setFinallyExits = graph.getFinallyExits();
+ if (setFinallyExits.contains(block)) {
+ setFinallyExits.remove(block);
+ setFinallyExits.add(setPreds.iterator().next());
+ }
+
+ // replace first if necessary
+ if (graph.getFirst() == block) {
+ if (setSuccs.size() != 1) {
+ throw new RuntimeException("multiple or no entry blocks!");
+ }
+ else {
+ graph.setFirst(setSuccs.iterator().next());
+ }
+ }
+
+ // remove this block
+ graph.removeBlock(block);
+
+ if (deletedRanges) {
+ removeDeadBlocks(graph);
+ }
+ }
+ }
+
+ return deletedRanges;
+ }
+
+
+ public static boolean isDominator(ControlFlowGraph graph, BasicBlock block, BasicBlock dom) {
+
+ HashSet<BasicBlock> marked = new HashSet<BasicBlock>();
+
+ if (block == dom) {
+ return true;
+ }
+
+ LinkedList<BasicBlock> lstNodes = new LinkedList<BasicBlock>();
+ lstNodes.add(block);
+
+ while (!lstNodes.isEmpty()) {
+
+ BasicBlock node = lstNodes.remove(0);
+ if (marked.contains(node)) {
+ continue;
+ }
+ else {
+ marked.add(node);
+ }
+
+ if (node == graph.getFirst()) {
+ return false;
+ }
+
+ for (int i = 0; i < node.getPreds().size(); i++) {
+ BasicBlock pred = node.getPreds().get(i);
+ if (!marked.contains(pred) && pred != dom) {
+ lstNodes.add(pred);
+ }
+ }
+
+ for (int i = 0; i < node.getPredExceptions().size(); i++) {
+ BasicBlock pred = node.getPredExceptions().get(i);
+ if (!marked.contains(pred) && pred != dom) {
+ lstNodes.add(pred);
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public static void removeGotos(ControlFlowGraph graph) {
+
+ for (BasicBlock block : graph.getBlocks()) {
+ Instruction instr = block.getLastInstruction();
+
+ if (instr != null && instr.opcode == CodeConstants.opc_goto) {
+ block.getSeq().removeInstruction(block.getSeq().length() - 1);
+ }
+ }
+
+ removeEmptyBlocks(graph);
+ }
+
+ public static void connectDummyExitBlock(ControlFlowGraph graph) {
+
+ BasicBlock exit = graph.getLast();
+ for (BasicBlock block : new HashSet<BasicBlock>(exit.getPreds())) {
+ exit.removePredecessor(block);
+ block.addSuccessor(exit);
+ }
+ }
+
+ public static void incorporateValueReturns(ControlFlowGraph graph) {
+
+ for (BasicBlock block : graph.getBlocks()) {
+ InstructionSequence seq = block.getSeq();
+
+ int len = seq.length();
+ if (len > 0 && len < 3) {
+
+ boolean ok = false;
+
+ if (seq.getLastInstr().opcode >= CodeConstants.opc_ireturn && seq.getLastInstr().opcode <= CodeConstants.opc_return) {
+ if (len == 1) {
+ ok = true;
+ }
+ else if (seq.getLastInstr().opcode != CodeConstants.opc_return) {
+ switch (seq.getInstr(0).opcode) {
+ case CodeConstants.opc_iload:
+ case CodeConstants.opc_lload:
+ case CodeConstants.opc_fload:
+ case CodeConstants.opc_dload:
+ case CodeConstants.opc_aload:
+ case CodeConstants.opc_aconst_null:
+ case CodeConstants.opc_bipush:
+ case CodeConstants.opc_sipush:
+ case CodeConstants.opc_lconst_0:
+ case CodeConstants.opc_lconst_1:
+ case CodeConstants.opc_fconst_0:
+ case CodeConstants.opc_fconst_1:
+ case CodeConstants.opc_fconst_2:
+ case CodeConstants.opc_dconst_0:
+ case CodeConstants.opc_dconst_1:
+ case CodeConstants.opc_ldc:
+ case CodeConstants.opc_ldc_w:
+ case CodeConstants.opc_ldc2_w:
+ ok = true;
+ }
+ }
+ }
+
+ if (ok) {
+
+ if (!block.getPreds().isEmpty()) {
+
+ HashSet<BasicBlock> setPredHandlersUnion = new HashSet<BasicBlock>();
+ HashSet<BasicBlock> setPredHandlersIntersection = new HashSet<BasicBlock>();
+
+ boolean firstpred = true;
+ for (BasicBlock pred : block.getPreds()) {
+ if (firstpred) {
+ setPredHandlersIntersection.addAll(pred.getSuccExceptions());
+ firstpred = false;
+ }
+ else {
+ setPredHandlersIntersection.retainAll(pred.getSuccExceptions());
+ }
+
+ setPredHandlersUnion.addAll(pred.getSuccExceptions());
+ }
+
+ // add exception ranges from predecessors
+ setPredHandlersIntersection.removeAll(block.getSuccExceptions());
+ BasicBlock predecessor = block.getPreds().get(0);
+
+ for (BasicBlock handler : setPredHandlersIntersection) {
+ ExceptionRangeCFG range = graph.getExceptionRange(handler, predecessor);
+
+ range.getProtectedRange().add(block);
+ block.addSuccessorException(handler);
+ }
+
+ // remove redundant ranges
+ HashSet<BasicBlock> setRangesToBeRemoved = new HashSet<BasicBlock>(block.getSuccExceptions());
+ setRangesToBeRemoved.removeAll(setPredHandlersUnion);
+
+ for (BasicBlock handler : setRangesToBeRemoved) {
+ ExceptionRangeCFG range = graph.getExceptionRange(handler, block);
+
+ if (range.getProtectedRange().size() > 1) {
+ range.getProtectedRange().remove(block);
+ block.removeSuccessorException(handler);
+ }
+ }
+ }
+
+
+ if (block.getPreds().size() == 1 && block.getPredExceptions().isEmpty()) {
+
+ BasicBlock bpred = block.getPreds().get(0);
+ if (bpred.getSuccs().size() == 1) {
+
+ // add exception ranges of predecessor
+ for (BasicBlock succ : bpred.getSuccExceptions()) {
+ if (!block.getSuccExceptions().contains(succ)) {
+ ExceptionRangeCFG range = graph.getExceptionRange(succ, bpred);
+
+ range.getProtectedRange().add(block);
+ block.addSuccessorException(succ);
+ }
+ }
+
+ // remove superfluous ranges from successors
+ for (BasicBlock succ : new HashSet<BasicBlock>(block.getSuccExceptions())) {
+ if (!bpred.getSuccExceptions().contains(succ)) {
+ ExceptionRangeCFG range = graph.getExceptionRange(succ, block);
+
+ if (range.getProtectedRange().size() > 1) {
+ range.getProtectedRange().remove(block);
+ block.removeSuccessorException(succ);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ public static void mergeBasicBlocks(ControlFlowGraph graph) {
+
+ while (true) {
+
+ boolean merged = false;
+
+ for (BasicBlock block : graph.getBlocks()) {
+
+ InstructionSequence seq = block.getSeq();
+
+ if (block.getSuccs().size() == 1) {
+ BasicBlock next = block.getSuccs().get(0);
+
+ if (next != graph.getLast() && (seq.isEmpty() || seq.getLastInstr().group != CodeConstants.GROUP_SWITCH)) {
+
+ if (next.getPreds().size() == 1 && next.getPredExceptions().isEmpty()
+ && next != graph.getFirst()) {
+ // TODO: implement a dummy start block
+ boolean sameRanges = true;
+ for (ExceptionRangeCFG range : graph.getExceptions()) {
+ if (range.getProtectedRange().contains(block) ^
+ range.getProtectedRange().contains(next)) {
+ sameRanges = false;
+ break;
+ }
+ }
+
+ if (sameRanges) {
+ seq.addSequence(next.getSeq());
+ next.getSeq().clear();
+
+ removeEmptyBlock(graph, next, true);
+
+ merged = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (!merged) {
+ break;
+ }
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/ClearStructHelper.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/ClearStructHelper.java
new file mode 100644
index 000000000000..c6495e6ad13f
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/ClearStructHelper.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler;
+
+import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+
+import java.util.LinkedList;
+
+
+public class ClearStructHelper {
+
+ public static void clearStatements(RootStatement root) {
+
+ LinkedList<Statement> stack = new LinkedList<Statement>();
+ stack.add(root);
+
+ while (!stack.isEmpty()) {
+
+ Statement stat = stack.removeFirst();
+
+ stat.clearTempInformation();
+
+ stack.addAll(stat.getStats());
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/ConcatenationHelper.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/ConcatenationHelper.java
new file mode 100644
index 000000000000..1b641a695f2e
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/ConcatenationHelper.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
+import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ConcatenationHelper {
+
+ private static final String builderClass = "java/lang/StringBuilder";
+ private static final String bufferClass = "java/lang/StringBuffer";
+ private static final String stringClass = "java/lang/String";
+
+ private static final VarType builderType = new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/StringBuilder");
+ private static final VarType bufferType = new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/StringBuffer");
+
+
+ public static Exprent contractStringConcat(Exprent expr) {
+
+ Exprent exprTmp = null;
+ VarType cltype = null;
+
+ // first quick test
+ if (expr.type == Exprent.EXPRENT_INVOCATION) {
+ InvocationExprent iex = (InvocationExprent)expr;
+ if ("toString".equals(iex.getName())) {
+ if (builderClass.equals(iex.getClassname())) {
+ cltype = builderType;
+ }
+ else if (bufferClass.equals(iex.getClassname())) {
+ cltype = bufferType;
+ }
+ if (cltype != null) {
+ exprTmp = iex.getInstance();
+ }
+ }
+ }
+
+ if (exprTmp == null) {
+ return expr;
+ }
+
+
+ // iterate in depth, collecting possible operands
+ List<Exprent> lstOperands = new ArrayList<Exprent>();
+
+ while (true) {
+
+ int found = 0;
+
+ switch (exprTmp.type) {
+ case Exprent.EXPRENT_INVOCATION:
+ InvocationExprent iex = (InvocationExprent)exprTmp;
+ if (isAppendConcat(iex, cltype)) {
+ lstOperands.add(0, iex.getLstParameters().get(0));
+ exprTmp = iex.getInstance();
+ found = 1;
+ }
+ break;
+ case Exprent.EXPRENT_NEW:
+ NewExprent nex = (NewExprent)exprTmp;
+ if (isNewConcat(nex, cltype)) {
+ VarType[] params = nex.getConstructor().getDescriptor().params;
+ if (params.length == 1) {
+ lstOperands.add(0, nex.getConstructor().getLstParameters().get(0));
+ }
+ found = 2;
+ }
+ }
+
+ if (found == 0) {
+ return expr;
+ }
+ else if (found == 2) {
+ break;
+ }
+ }
+
+ int first2str = 0;
+ int index = 0;
+ while (index < lstOperands.size() && index < 2) {
+ if (lstOperands.get(index).getExprType().equals(VarType.VARTYPE_STRING)) {
+ first2str |= (index + 1);
+ }
+ index++;
+ }
+
+ if (first2str == 0) {
+ lstOperands.add(0, new ConstExprent(VarType.VARTYPE_STRING, ""));
+ }
+
+ // remove redundant String.valueOf
+ for (int i = 0; i < lstOperands.size(); i++) {
+ Exprent rep = removeStringValueOf(lstOperands.get(i));
+
+ boolean ok = (i > 1);
+ if (!ok) {
+ boolean isstr = rep.getExprType().equals(VarType.VARTYPE_STRING);
+ ok = isstr || first2str != i + 1;
+
+ if (i == 0) {
+ first2str &= 2;
+ }
+ }
+
+ if (ok) {
+ lstOperands.set(i, rep);
+ }
+ }
+
+ // build exprent to return
+ Exprent func = lstOperands.get(0);
+
+ for (int i = 1; i < lstOperands.size(); i++) {
+ List<Exprent> lstTmp = new ArrayList<Exprent>();
+ lstTmp.add(func);
+ lstTmp.add(lstOperands.get(i));
+ func = new FunctionExprent(FunctionExprent.FUNCTION_STRCONCAT, lstTmp);
+ }
+
+ return func;
+ }
+
+ private static boolean isAppendConcat(InvocationExprent expr, VarType cltype) {
+
+ if ("append".equals(expr.getName())) {
+ MethodDescriptor md = expr.getDescriptor();
+ if (md.ret.equals(cltype) && md.params.length == 1) {
+ VarType param = md.params[0];
+ switch (param.type) {
+ case CodeConstants.TYPE_OBJECT:
+ if (!param.equals(VarType.VARTYPE_STRING) &&
+ !param.equals(VarType.VARTYPE_OBJECT)) {
+ break;
+ }
+ case CodeConstants.TYPE_BOOLEAN:
+ case CodeConstants.TYPE_CHAR:
+ case CodeConstants.TYPE_DOUBLE:
+ case CodeConstants.TYPE_FLOAT:
+ case CodeConstants.TYPE_INT:
+ case CodeConstants.TYPE_LONG:
+ return true;
+ default:
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private static boolean isNewConcat(NewExprent expr, VarType cltype) {
+
+ if (expr.getNewtype().equals(cltype)) {
+ VarType[] params = expr.getConstructor().getDescriptor().params;
+ if (params.length == 0 || (params.length == 1 &&
+ params[0].equals(VarType.VARTYPE_STRING))) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private static Exprent removeStringValueOf(Exprent exprent) {
+
+ if (exprent.type == Exprent.EXPRENT_INVOCATION) {
+ InvocationExprent iex = (InvocationExprent)exprent;
+ if ("valueOf".equals(iex.getName()) && stringClass.equals(iex.getClassname())) {
+ MethodDescriptor md = iex.getDescriptor();
+ if (md.params.length == 1) {
+ VarType param = md.params[0];
+ switch (param.type) {
+ case CodeConstants.TYPE_OBJECT:
+ if (!param.equals(VarType.VARTYPE_OBJECT)) {
+ break;
+ }
+ case CodeConstants.TYPE_BOOLEAN:
+ case CodeConstants.TYPE_CHAR:
+ case CodeConstants.TYPE_DOUBLE:
+ case CodeConstants.TYPE_FLOAT:
+ case CodeConstants.TYPE_INT:
+ case CodeConstants.TYPE_LONG:
+ return iex.getLstParameters().get(0);
+ }
+ }
+ }
+ }
+
+ return exprent;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/DecHelper.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/DecHelper.java
new file mode 100644
index 000000000000..9c719dbc9141
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/DecHelper.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler;
+
+import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+
+import java.util.*;
+
+
+public class DecHelper {
+
+ public static boolean checkStatementExceptions(List<Statement> lst) {
+
+ Set<Statement> all = new HashSet<Statement>(lst);
+
+ Set<Statement> handlers = new HashSet<Statement>();
+ Set<Statement> intersection = null;
+
+ for (Statement stat : lst) {
+ Set<Statement> setNew = stat.getNeighboursSet(StatEdge.TYPE_EXCEPTION, Statement.DIRECTION_FORWARD);
+
+ if (intersection == null) {
+ intersection = setNew;
+ }
+ else {
+ HashSet<Statement> interclone = new HashSet<Statement>(intersection);
+ interclone.removeAll(setNew);
+
+ intersection.retainAll(setNew);
+
+ setNew.removeAll(intersection);
+
+ handlers.addAll(interclone);
+ handlers.addAll(setNew);
+ }
+ }
+
+ for (Statement stat : handlers) {
+ if (!all.contains(stat) || !all.containsAll(stat.getNeighbours(StatEdge.TYPE_EXCEPTION, Statement.DIRECTION_BACKWARD))) {
+ return false;
+ }
+ }
+
+ // check for other handlers (excluding head)
+ for (int i = 1; i < lst.size(); i++) {
+ Statement stat = lst.get(i);
+ if (!stat.getPredecessorEdges(StatEdge.TYPE_EXCEPTION).isEmpty() && !handlers.contains(stat)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public static boolean isChoiceStatement(Statement head, List<Statement> lst) {
+
+ Statement post = null;
+
+ Set<Statement> setDest = head.getNeighboursSet(StatEdge.TYPE_REGULAR, Statement.DIRECTION_FORWARD);
+
+ if (setDest.contains(head)) {
+ return false;
+ }
+
+ while (true) {
+
+ lst.clear();
+
+ boolean repeat = false;
+
+ setDest.remove(post);
+
+ for (Statement stat : setDest) {
+ if (stat.getLastBasicType() != Statement.LASTBASICTYPE_GENERAL) {
+ if (post == null) {
+ post = stat;
+ repeat = true;
+ break;
+ }
+ else {
+ return false;
+ }
+ }
+
+ // preds
+ Set<Statement> setPred = stat.getNeighboursSet(StatEdge.TYPE_REGULAR, Statement.DIRECTION_BACKWARD);
+ setPred.remove(head);
+ if (setPred.contains(stat)) {
+ return false;
+ }
+
+ if (!setDest.containsAll(setPred) || setPred.size() > 1) {
+ if (post == null) {
+ post = stat;
+ repeat = true;
+ break;
+ }
+ else {
+ return false;
+ }
+ }
+ else if (setPred.size() == 1) {
+ Statement pred = setPred.iterator().next();
+ while (lst.contains(pred)) {
+ Set<Statement> setPredTemp = pred.getNeighboursSet(StatEdge.TYPE_REGULAR, Statement.DIRECTION_BACKWARD);
+ setPredTemp.remove(head);
+
+ if (!setPredTemp.isEmpty()) { // at most 1 predecessor
+ pred = setPredTemp.iterator().next();
+ if (pred == stat) {
+ return false; // loop found
+ }
+ }
+ else {
+ break;
+ }
+ }
+ }
+
+ // succs
+ List<StatEdge> lstEdges = stat.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL);
+ if (lstEdges.size() > 1) {
+ Set<Statement> setSucc = stat.getNeighboursSet(Statement.STATEDGE_DIRECT_ALL, Statement.DIRECTION_FORWARD);
+ setSucc.retainAll(setDest);
+
+ if (setSucc.size() > 0) {
+ return false;
+ }
+ else {
+ if (post == null) {
+ post = stat;
+ repeat = true;
+ break;
+ }
+ else {
+ return false;
+ }
+ }
+ }
+ else if (lstEdges.size() == 1) {
+
+ StatEdge edge = lstEdges.get(0);
+ if (edge.getType() == StatEdge.TYPE_REGULAR) {
+ Statement statd = edge.getDestination();
+ if (head == statd) {
+ return false;
+ }
+ if (!setDest.contains(statd) && post != statd) {
+ if (post != null) {
+ return false;
+ }
+ else {
+ Set<Statement> set = statd.getNeighboursSet(StatEdge.TYPE_REGULAR, Statement.DIRECTION_BACKWARD);
+ if (set.size() > 1) {
+ post = statd;
+ repeat = true;
+ break;
+ }
+ else {
+ return false;
+ }
+ }
+ }
+ }
+ }
+
+ lst.add(stat);
+ }
+
+ if (!repeat) {
+ break;
+ }
+ }
+
+ lst.add(head);
+ lst.remove(post);
+
+ lst.add(0, post);
+
+ return true;
+ }
+
+
+ public static HashSet<Statement> getUniquePredExceptions(Statement head) {
+
+ HashSet<Statement> setHandlers = new HashSet<Statement>(head.getNeighbours(StatEdge.TYPE_EXCEPTION, Statement.DIRECTION_FORWARD));
+
+ Iterator<Statement> it = setHandlers.iterator();
+ while (it.hasNext()) {
+ if (it.next().getPredecessorEdges(StatEdge.TYPE_EXCEPTION).size() > 1) {
+ it.remove();
+ }
+ }
+ return setHandlers;
+ }
+
+ public static List<Exprent> copyExprentList(List<Exprent> lst) {
+ List<Exprent> ret = new ArrayList<Exprent>();
+ for (Exprent expr : lst) {
+ ret.add(expr.copy());
+ }
+ return ret;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/DomHelper.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/DomHelper.java
new file mode 100644
index 000000000000..3bb45840f91d
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/DomHelper.java
@@ -0,0 +1,707 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler;
+
+import org.jetbrains.java.decompiler.code.cfg.BasicBlock;
+import org.jetbrains.java.decompiler.code.cfg.ControlFlowGraph;
+import org.jetbrains.java.decompiler.code.cfg.ExceptionRangeCFG;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
+import org.jetbrains.java.decompiler.modules.decompiler.decompose.FastExtendedPostdominanceHelper;
+import org.jetbrains.java.decompiler.modules.decompiler.deobfuscator.IrreducibleCFGDeobfuscator;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.*;
+import org.jetbrains.java.decompiler.util.FastFixedSetFactory;
+import org.jetbrains.java.decompiler.util.FastFixedSetFactory.FastFixedSet;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import org.jetbrains.java.decompiler.util.VBStyleCollection;
+
+import java.util.*;
+
+public class DomHelper {
+
+
+ private static RootStatement graphToStatement(ControlFlowGraph graph) {
+
+ VBStyleCollection<Statement, Integer> stats = new VBStyleCollection<Statement, Integer>();
+ VBStyleCollection<BasicBlock, Integer> blocks = graph.getBlocks();
+
+ for (BasicBlock block : blocks) {
+ stats.addWithKey(new BasicBlockStatement(block), block.id);
+ }
+
+ BasicBlock firstblock = graph.getFirst();
+ // head statement
+ Statement firstst = stats.getWithKey(firstblock.id);
+ // dummy exit statement
+ Statement dummyexit = new Statement();
+ dummyexit.type = Statement.TYPE_DUMMYEXIT;
+
+ Statement general;
+ if (stats.size() > 1 || firstblock.isSuccessor(firstblock)) { // multiple basic blocks or an infinite loop of one block
+ general = new GeneralStatement(firstst, stats, null);
+ }
+ else { // one straightforward basic block
+ RootStatement root = new RootStatement(firstst, dummyexit);
+ firstst.addSuccessor(new StatEdge(StatEdge.TYPE_BREAK, firstst, dummyexit, root));
+
+ return root;
+ }
+
+ for (BasicBlock block : blocks) {
+ Statement stat = stats.getWithKey(block.id);
+
+ for (BasicBlock succ : block.getSuccs()) {
+ Statement stsucc = stats.getWithKey(succ.id);
+
+ int type;
+ if (stsucc == firstst) {
+ type = StatEdge.TYPE_CONTINUE;
+ }
+ else if (graph.getFinallyExits().contains(block)) {
+ type = StatEdge.TYPE_FINALLYEXIT;
+ stsucc = dummyexit;
+ }
+ else if (succ.id == graph.getLast().id) {
+ type = StatEdge.TYPE_BREAK;
+ stsucc = dummyexit;
+ }
+ else {
+ type = StatEdge.TYPE_REGULAR;
+ }
+
+ stat.addSuccessor(new StatEdge(type, stat, (type == StatEdge.TYPE_CONTINUE) ? general : stsucc,
+ (type == StatEdge.TYPE_REGULAR) ? null : general));
+ }
+
+ // exceptions edges
+ for (BasicBlock succex : block.getSuccExceptions()) {
+ Statement stsuccex = stats.getWithKey(succex.id);
+
+ ExceptionRangeCFG range = graph.getExceptionRange(succex, block);
+ if (!range.isCircular()) {
+ stat.addSuccessor(new StatEdge(stat, stsuccex, range.getExceptionTypes()));
+ }
+ }
+ }
+
+ general.buildContinueSet();
+ general.buildMonitorFlags();
+ return new RootStatement(general, dummyexit);
+ }
+
+ public static VBStyleCollection<List<Integer>, Integer> calcPostDominators(Statement container) {
+
+ HashMap<Statement, FastFixedSet<Statement>> lists = new HashMap<Statement, FastFixedSet<Statement>>();
+
+ StrongConnectivityHelper schelper = new StrongConnectivityHelper(container);
+ List<List<Statement>> components = schelper.getComponents();
+
+ List<Statement> lstStats = container.getPostReversePostOrderList(StrongConnectivityHelper.getExitReps(components));
+
+ FastFixedSetFactory<Statement> factory = new FastFixedSetFactory<Statement>(lstStats);
+
+ FastFixedSet<Statement> setFlagNodes = factory.spawnEmptySet();
+ setFlagNodes.setAllElements();
+
+ FastFixedSet<Statement> initSet = factory.spawnEmptySet();
+ initSet.setAllElements();
+
+ for (List<Statement> lst : components) {
+ FastFixedSet<Statement> tmpSet;
+
+ if (StrongConnectivityHelper.isExitComponent(lst)) {
+ tmpSet = factory.spawnEmptySet();
+ tmpSet.addAll(lst);
+ }
+ else {
+ tmpSet = initSet.getCopy();
+ }
+
+ for (Statement stat : lst) {
+ lists.put(stat, tmpSet);
+ }
+ }
+
+ do {
+
+ for (Statement stat : lstStats) {
+
+ if (!setFlagNodes.contains(stat)) {
+ continue;
+ }
+ setFlagNodes.remove(stat);
+
+ FastFixedSet<Statement> doms = lists.get(stat);
+ FastFixedSet<Statement> domsSuccs = factory.spawnEmptySet();
+
+ List<Statement> lstSuccs = stat.getNeighbours(StatEdge.TYPE_REGULAR, Statement.DIRECTION_FORWARD);
+ for (int j = 0; j < lstSuccs.size(); j++) {
+ Statement succ = lstSuccs.get(j);
+ FastFixedSet<Statement> succlst = lists.get(succ);
+
+ if (j == 0) {
+ domsSuccs.union(succlst);
+ }
+ else {
+ domsSuccs.intersection(succlst);
+ }
+ }
+
+ if (!domsSuccs.contains(stat)) {
+ domsSuccs.add(stat);
+ }
+
+ if (!InterpreterUtil.equalObjects(domsSuccs, doms)) {
+
+ lists.put(stat, domsSuccs);
+
+ List<Statement> lstPreds = stat.getNeighbours(StatEdge.TYPE_REGULAR, Statement.DIRECTION_BACKWARD);
+ for (Statement pred : lstPreds) {
+ setFlagNodes.add(pred);
+ }
+ }
+ }
+ }
+ while (!setFlagNodes.isEmpty());
+
+ VBStyleCollection<List<Integer>, Integer> ret = new VBStyleCollection<List<Integer>, Integer>();
+ List<Statement> lstRevPost = container.getReversePostOrderList(); // sort order crucial!
+
+ final HashMap<Integer, Integer> mapSortOrder = new HashMap<Integer, Integer>();
+ for (int i = 0; i < lstRevPost.size(); i++) {
+ mapSortOrder.put(lstRevPost.get(i).id, i);
+ }
+
+ for (Statement st : lstStats) {
+
+ List<Integer> lstPosts = new ArrayList<Integer>();
+ for (Statement stt : lists.get(st)) {
+ lstPosts.add(stt.id);
+ }
+
+ Collections.sort(lstPosts, new Comparator<Integer>() {
+ public int compare(Integer o1, Integer o2) {
+ return mapSortOrder.get(o1).compareTo(mapSortOrder.get(o2));
+ }
+ });
+
+ if (lstPosts.size() > 1 && lstPosts.get(0).intValue() == st.id) {
+ lstPosts.add(lstPosts.remove(0));
+ }
+
+ ret.addWithKey(lstPosts, st.id);
+ }
+
+ return ret;
+ }
+
+ public static RootStatement parseGraph(ControlFlowGraph graph) {
+
+ RootStatement root = graphToStatement(graph);
+
+ if (!processStatement(root, new HashMap<Integer, Set<Integer>>())) {
+ DecompilerContext.getLogger().writeMessage("parsing failure!", IFernflowerLogger.Severity.ERROR);
+
+ // try {
+ // DotExporter.toDotFile(root.getFirst().getStats().get(13), new File("c:\\Temp\\stat1.dot"));
+ // } catch (Exception ex) {
+ // ex.printStackTrace();
+ // }
+ throw new RuntimeException("parsing failure!");
+ }
+
+ LabelHelper.lowContinueLabels(root, new HashSet<StatEdge>());
+
+ SequenceHelper.condenseSequences(root);
+ root.buildMonitorFlags();
+
+ // build synchronized statements
+ buildSynchronized(root);
+
+ return root;
+ }
+
+ public static void removeSynchronizedHandler(Statement stat) {
+
+ for (Statement st : stat.getStats()) {
+ removeSynchronizedHandler(st);
+ }
+
+ if (stat.type == Statement.TYPE_SYNCRONIZED) {
+ ((SynchronizedStatement)stat).removeExc();
+ }
+ }
+
+
+ private static void buildSynchronized(Statement stat) {
+
+ for (Statement st : stat.getStats()) {
+ buildSynchronized(st);
+ }
+
+ if (stat.type == Statement.TYPE_SEQUENCE) {
+
+ while (true) {
+
+ boolean found = false;
+
+ List<Statement> lst = stat.getStats();
+ for (int i = 0; i < lst.size() - 1; i++) {
+ Statement current = lst.get(i); // basic block
+
+ if (current.isMonitorEnter()) {
+
+ Statement next = lst.get(i + 1);
+ Statement nextDirect = next;
+
+ while (next.type == Statement.TYPE_SEQUENCE) {
+ next = next.getFirst();
+ }
+
+ if (next.type == Statement.TYPE_CATCHALL) {
+
+ CatchAllStatement ca = (CatchAllStatement)next;
+
+ if (ca.getFirst().isContainsMonitorExit() && ca.getHandler().isContainsMonitorExit()) {
+
+ // remove the head block from sequence
+ current.removeSuccessor(current.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL).get(0));
+
+ for (StatEdge edge : current.getPredecessorEdges(Statement.STATEDGE_DIRECT_ALL)) {
+ current.removePredecessor(edge);
+ edge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, edge, nextDirect);
+ nextDirect.addPredecessor(edge);
+ }
+
+ stat.getStats().removeWithKey(current.id);
+ stat.setFirst(stat.getStats().get(0));
+
+ // new statement
+ SynchronizedStatement sync = new SynchronizedStatement(current, ca.getFirst(), ca.getHandler());
+ sync.setAllParent();
+
+ for (StatEdge edge : new HashSet<StatEdge>(ca.getLabelEdges())) {
+ sync.addLabeledEdge(edge);
+ }
+
+ current.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, current, ca.getFirst()));
+
+ ca.getParent().replaceStatement(ca, sync);
+ found = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!found) {
+ break;
+ }
+ }
+ }
+ }
+
+ private static boolean processStatement(Statement general, HashMap<Integer, Set<Integer>> mapExtPost) {
+
+ if (general.type == Statement.TYPE_ROOT) {
+ Statement stat = general.getFirst();
+ if (stat.type != Statement.TYPE_GENERAL) {
+ return true;
+ }
+ else {
+ boolean complete = processStatement(stat, mapExtPost);
+ if (complete) {
+ // replace general purpose statement with simple one
+ general.replaceStatement(stat, stat.getFirst());
+ }
+ return complete;
+ }
+ }
+
+ boolean mapRefreshed = mapExtPost.isEmpty();
+
+ for (int mapstage = 0; mapstage < 2; mapstage++) {
+
+ for (int reducibility = 0;
+ reducibility < 5;
+ reducibility++) { // FIXME: implement proper node splitting. For now up to 5 nodes in sequence are splitted.
+
+ if (reducibility > 0) {
+
+ // try {
+ // DotExporter.toDotFile(general, new File("c:\\Temp\\stat1.dot"));
+ // } catch(Exception ex) {ex.printStackTrace();}
+
+ // take care of irreducible control flow graphs
+ if (IrreducibleCFGDeobfuscator.isStatementIrreducible(general)) {
+ if (!IrreducibleCFGDeobfuscator.splitIrreducibleNode(general)) {
+ DecompilerContext.getLogger().writeMessage("Irreducible statement cannot be decomposed!", IFernflowerLogger.Severity.ERROR);
+ break;
+ }
+ }
+ else {
+ if (mapstage == 2 || mapRefreshed) { // last chance lost
+ DecompilerContext.getLogger().writeMessage("Statement cannot be decomposed although reducible!",
+ IFernflowerLogger.Severity.ERROR);
+ }
+ break;
+ }
+
+ // try {
+ // DotExporter.toDotFile(general, new File("c:\\Temp\\stat1.dot"));
+ // } catch(Exception ex) {ex.printStackTrace();}
+
+ mapExtPost = new HashMap<Integer, Set<Integer>>();
+ mapRefreshed = true;
+ }
+
+ for (int i = 0; i < 2; i++) {
+
+ boolean forceall = i != 0;
+
+ while (true) {
+
+ if (findSimpleStatements(general, mapExtPost)) {
+ reducibility = 0;
+ }
+
+ if (general.type == Statement.TYPE_PLACEHOLDER) {
+ return true;
+ }
+
+ Statement stat = findGeneralStatement(general, forceall, mapExtPost);
+
+ if (stat != null) {
+ boolean complete = processStatement(stat, general.getFirst() == stat ? mapExtPost : new HashMap<Integer, Set<Integer>>());
+
+ if (complete) {
+ // replace general purpose statement with simple one
+ general.replaceStatement(stat, stat.getFirst());
+ }
+ else {
+ return false;
+ }
+
+ mapExtPost = new HashMap<Integer, Set<Integer>>();
+ mapRefreshed = true;
+ reducibility = 0;
+ }
+ else {
+ break;
+ }
+ }
+ }
+
+ // try {
+ // DotExporter.toDotFile(general, new File("c:\\Temp\\stat1.dot"));
+ // } catch (Exception ex) {
+ // ex.printStackTrace();
+ // }
+ }
+
+ if (mapRefreshed) {
+ break;
+ }
+ else {
+ mapExtPost = new HashMap<Integer, Set<Integer>>();
+ }
+ }
+
+ return false;
+ }
+
+ private static Statement findGeneralStatement(Statement stat, boolean forceall, HashMap<Integer, Set<Integer>> mapExtPost) {
+
+ VBStyleCollection<Statement, Integer> stats = stat.getStats();
+ VBStyleCollection<List<Integer>, Integer> vbPost;
+
+ if (mapExtPost.isEmpty()) {
+ FastExtendedPostdominanceHelper extpost = new FastExtendedPostdominanceHelper();
+ mapExtPost.putAll(extpost.getExtendedPostdominators(stat));
+ }
+
+ if (forceall) {
+ vbPost = new VBStyleCollection<List<Integer>, Integer>();
+ List<Statement> lstAll = stat.getPostReversePostOrderList();
+
+ for (Statement st : lstAll) {
+ Set<Integer> set = mapExtPost.get(st.id);
+ if (set != null) {
+ vbPost.addWithKey(new ArrayList<Integer>(set), st.id); // FIXME: sort order!!
+ }
+ }
+
+ // tail statements
+ Set<Integer> setFirst = mapExtPost.get(stat.getFirst().id);
+ if (setFirst != null) {
+ for (Integer id : setFirst) {
+ List<Integer> lst = vbPost.getWithKey(id);
+ if (lst == null) {
+ vbPost.addWithKey(lst = new ArrayList<Integer>(), id);
+ }
+ lst.add(id);
+ }
+ }
+ }
+ else {
+ vbPost = calcPostDominators(stat);
+ }
+
+ for (int k = 0; k < vbPost.size(); k++) {
+
+ Integer headid = vbPost.getKey(k);
+ List<Integer> posts = vbPost.get(k);
+
+ if (!mapExtPost.containsKey(headid) &&
+ !(posts.size() == 1 && posts.get(0).equals(headid))) {
+ continue;
+ }
+
+ Statement head = stats.getWithKey(headid);
+
+ Set<Integer> setExtPosts = mapExtPost.get(headid);
+
+ for (int i = 0; i < posts.size(); i++) {
+
+ Integer postid = posts.get(i);
+ if (!postid.equals(headid) && !setExtPosts.contains(postid)) {
+ continue;
+ }
+
+ Statement post = stats.getWithKey(postid);
+
+ if (post == null) { // possible in case of an inherited postdominance set
+ continue;
+ }
+
+ boolean same = (post == head);
+
+ HashSet<Statement> setNodes = new HashSet<Statement>();
+ HashSet<Statement> setPreds = new HashSet<Statement>();
+
+ // collect statement nodes
+ HashSet<Statement> setHandlers = new HashSet<Statement>();
+ setHandlers.add(head);
+ while (true) {
+
+ boolean hdfound = false;
+ for (Statement handler : setHandlers) {
+ if (setNodes.contains(handler)) {
+ continue;
+ }
+
+ boolean addhd = (setNodes.size() == 0); // first handler == head
+ if (!addhd) {
+ List<Statement> hdsupp = handler.getNeighbours(StatEdge.TYPE_EXCEPTION, Statement.DIRECTION_BACKWARD);
+ addhd = (setNodes.containsAll(hdsupp) && (setNodes.size() > hdsupp.size()
+ || setNodes.size() == 1)); // strict subset
+ }
+
+ if (addhd) {
+ LinkedList<Statement> lstStack = new LinkedList<Statement>();
+ lstStack.add(handler);
+
+ while (!lstStack.isEmpty()) {
+ Statement st = lstStack.remove(0);
+
+ if (!(setNodes.contains(st) || (!same && st == post))) {
+ setNodes.add(st);
+ if (st != head) {
+ // record predeccessors except for the head
+ setPreds.addAll(st.getNeighbours(StatEdge.TYPE_REGULAR, Statement.DIRECTION_BACKWARD));
+ }
+
+ // put successors on the stack
+ lstStack.addAll(st.getNeighbours(StatEdge.TYPE_REGULAR, Statement.DIRECTION_FORWARD));
+
+ // exception edges
+ setHandlers.addAll(st.getNeighbours(StatEdge.TYPE_EXCEPTION, Statement.DIRECTION_FORWARD));
+ }
+ }
+
+ hdfound = true;
+ setHandlers.remove(handler);
+ break;
+ }
+ }
+
+ if (!hdfound) {
+ break;
+ }
+ }
+
+ // check exception handlers
+ setHandlers.clear();
+ for (Statement st : setNodes) {
+ setHandlers.addAll(st.getNeighbours(StatEdge.TYPE_EXCEPTION, Statement.DIRECTION_FORWARD));
+ }
+ setHandlers.removeAll(setNodes);
+
+ boolean excok = true;
+ for (Statement handler : setHandlers) {
+ if (!handler.getNeighbours(StatEdge.TYPE_EXCEPTION, Statement.DIRECTION_BACKWARD).containsAll(setNodes)) {
+ excok = false;
+ break;
+ }
+ }
+
+ // build statement and return
+ if (excok) {
+ Statement res = null;
+
+ setPreds.removeAll(setNodes);
+ if (setPreds.size() == 0) {
+ if ((setNodes.size() > 1 ||
+ head.getNeighbours(StatEdge.TYPE_REGULAR, Statement.DIRECTION_BACKWARD).contains(head))
+ && setNodes.size() < stats.size()) {
+ if (checkSynchronizedCompleteness(head, setNodes)) {
+ res = new GeneralStatement(head, setNodes, same ? null : post);
+ stat.collapseNodesToStatement(res);
+
+ return res;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private static boolean checkSynchronizedCompleteness(Statement head, HashSet<Statement> setNodes) {
+
+ // check exit nodes
+ for (Statement stat : setNodes) {
+ if (stat.isMonitorEnter()) {
+ List<StatEdge> lstSuccs = stat.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL);
+ if (lstSuccs.size() != 1 || lstSuccs.get(0).getType() != StatEdge.TYPE_REGULAR) {
+ return false;
+ }
+
+ if (!setNodes.contains(lstSuccs.get(0).getDestination())) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ private static boolean findSimpleStatements(Statement stat, HashMap<Integer, Set<Integer>> mapExtPost) {
+
+ boolean found, success = false;
+
+ do {
+ found = false;
+
+ List<Statement> lstStats = stat.getPostReversePostOrderList();
+ for (Statement st : lstStats) {
+
+ Statement result = detectStatement(st);
+
+ if (result != null) {
+
+ if (stat.type == Statement.TYPE_GENERAL && result.getFirst() == stat.getFirst() &&
+ stat.getStats().size() == result.getStats().size()) {
+ // mark general statement
+ stat.type = Statement.TYPE_PLACEHOLDER;
+ }
+
+ stat.collapseNodesToStatement(result);
+
+ // update the postdominator map
+ if (!mapExtPost.isEmpty()) {
+ HashSet<Integer> setOldNodes = new HashSet<Integer>();
+ for (Statement old : result.getStats()) {
+ setOldNodes.add(old.id);
+ }
+
+ Integer newid = result.id;
+
+ for (Integer key : new ArrayList<Integer>(mapExtPost.keySet())) {
+ Set<Integer> set = mapExtPost.get(key);
+
+ int oldsize = set.size();
+ set.removeAll(setOldNodes);
+
+ if (setOldNodes.contains(key)) {
+ Set<Integer> setNew = mapExtPost.get(newid);
+ if (setNew == null) {
+ mapExtPost.put(newid, setNew = new HashSet<Integer>());
+ }
+ setNew.addAll(set);
+
+ mapExtPost.remove(key);
+ }
+ else {
+ if (set.size() < oldsize) {
+ set.add(newid);
+ }
+ }
+ }
+ }
+
+
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+ success = true;
+ }
+ }
+ while (found);
+
+ return success;
+ }
+
+
+ private static Statement detectStatement(Statement head) {
+
+ Statement res;
+
+ if ((res = DoStatement.isHead(head)) != null) {
+ return res;
+ }
+
+ if ((res = SwitchStatement.isHead(head)) != null) {
+ return res;
+ }
+
+ if ((res = IfStatement.isHead(head)) != null) {
+ return res;
+ }
+
+ // synchronized statements will be identified later
+ // right now they are recognized as catchall
+
+ if ((res = SequenceStatement.isHead2Block(head)) != null) {
+ return res;
+ }
+
+ if ((res = CatchStatement.isHead(head)) != null) {
+ return res;
+ }
+
+ if ((res = CatchAllStatement.isHead(head)) != null) {
+ return res;
+ }
+
+ return null;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/EliminateLoopsHelper.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/EliminateLoopsHelper.java
new file mode 100644
index 000000000000..16f7da084534
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/EliminateLoopsHelper.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler;
+
+import org.jetbrains.java.decompiler.modules.decompiler.stats.DoStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+
+public class EliminateLoopsHelper {
+
+
+ // public static boolean eliminateLoops(Statement root) {
+ //
+ // boolean ret = eliminateLoopsRec(root);
+ //
+ // if(ret) {
+ // SequenceHelper.condenseSequences(root);
+ //
+ // HashSet<Integer> setReorderedIfs = new HashSet<Integer>();
+ //
+ // SimplifyExprentsHelper sehelper = new SimplifyExprentsHelper(false);
+ // while(sehelper.simplifyStackVarsStatement(root, setReorderedIfs, null)) {
+ // SequenceHelper.condenseSequences(root);
+ // }
+ // }
+ //
+ // return ret;
+ // }
+
+ private static boolean eliminateLoopsRec(Statement stat) {
+
+ for (Statement st : stat.getStats()) {
+ if (eliminateLoopsRec(st)) {
+ return true;
+ }
+ }
+
+ if (stat.type == Statement.TYPE_DO && isLoopRedundant((DoStatement)stat)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ private static boolean isLoopRedundant(DoStatement loop) {
+
+ if (loop.getLooptype() != DoStatement.LOOP_DO) {
+ return false;
+ }
+
+ // get parent loop if exists
+ Statement parentloop = loop.getParent();
+ while (parentloop != null && parentloop.type != Statement.TYPE_DO) {
+ parentloop = parentloop.getParent();
+ }
+
+ if (parentloop == null || parentloop.getBasichead() != loop.getBasichead()) {
+ return false;
+ }
+
+ // collect relevant break edges
+ List<StatEdge> lstBreakEdges = new ArrayList<StatEdge>();
+ for (StatEdge edge : loop.getLabelEdges()) {
+ if (edge.getType() == StatEdge.TYPE_BREAK) { // all break edges are explicit because of LOOP_DO type
+ lstBreakEdges.add(edge);
+ }
+ }
+
+
+ Statement loopcontent = loop.getFirst();
+
+ boolean firstok = loopcontent.getAllSuccessorEdges().isEmpty();
+ if (!firstok) {
+ StatEdge edge = loopcontent.getAllSuccessorEdges().get(0);
+ firstok = (edge.closure == loop && edge.getType() == StatEdge.TYPE_BREAK);
+ if (firstok) {
+ lstBreakEdges.remove(edge);
+ }
+ }
+
+
+ if (!lstBreakEdges.isEmpty()) {
+ if (firstok) {
+
+ HashMap<Integer, Boolean> statLabeled = new HashMap<Integer, Boolean>();
+ List<Statement> lstEdgeClosures = new ArrayList<Statement>();
+
+ for (StatEdge edge : lstBreakEdges) {
+ Statement minclosure = LowBreakHelper.getMinClosure(loopcontent, edge.getSource());
+ lstEdgeClosures.add(minclosure);
+ }
+
+ int precount = loop.isLabeled() ? 1 : 0;
+ for (Statement st : lstEdgeClosures) {
+ if (!statLabeled.containsKey(st.id)) {
+ boolean btemp = st.isLabeled();
+ precount += btemp ? 1 : 0;
+ statLabeled.put(st.id, btemp);
+ }
+ }
+
+ for (int i = 0; i < lstBreakEdges.size(); i++) {
+ Statement st = lstEdgeClosures.get(i);
+ statLabeled.put(st.id, LowBreakHelper.isBreakEdgeLabeled(lstBreakEdges.get(i).getSource(), st) | statLabeled.get(st.id));
+ }
+
+ for (int i = 0; i < lstBreakEdges.size(); i++) {
+ lstEdgeClosures.set(i, getMaxBreakLift(lstEdgeClosures.get(i), lstBreakEdges.get(i), statLabeled, loop));
+ }
+
+ statLabeled.clear();
+ for (Statement st : lstEdgeClosures) {
+ statLabeled.put(st.id, st.isLabeled());
+ }
+
+ for (int i = 0; i < lstBreakEdges.size(); i++) {
+ Statement st = lstEdgeClosures.get(i);
+ statLabeled.put(st.id, LowBreakHelper.isBreakEdgeLabeled(lstBreakEdges.get(i).getSource(), st) | statLabeled.get(st.id));
+ }
+
+ int postcount = 0;
+ for (Boolean val : statLabeled.values()) {
+ postcount += val ? 1 : 0;
+ }
+
+ if (precount <= postcount) {
+ return false;
+ }
+ else {
+ for (int i = 0; i < lstBreakEdges.size(); i++) {
+ lstEdgeClosures.get(i).addLabeledEdge(lstBreakEdges.get(i));
+ }
+ }
+ }
+ else {
+ return false;
+ }
+ }
+
+ eliminateLoop(loop, parentloop);
+
+ return true;
+ }
+
+ private static Statement getMaxBreakLift(Statement stat, StatEdge edge, HashMap<Integer, Boolean> statLabeled, Statement max) {
+
+ Statement closure = stat;
+ Statement newclosure = stat;
+
+ while ((newclosure = getNextBreakLift(newclosure, edge, statLabeled, max)) != null) {
+ closure = newclosure;
+ }
+
+ return closure;
+ }
+
+ private static Statement getNextBreakLift(Statement stat, StatEdge edge, HashMap<Integer, Boolean> statLabeled, Statement max) {
+
+ Statement closure = stat.getParent();
+
+ while (closure != null && closure != max && !closure.containsStatementStrict(edge.getDestination())) {
+
+ boolean edge_labeled = LowBreakHelper.isBreakEdgeLabeled(edge.getSource(), closure);
+ boolean stat_labeled = statLabeled.containsKey(closure.id) ? statLabeled.get(closure.id) : closure.isLabeled();
+
+ if (stat_labeled || !edge_labeled) {
+ return closure;
+ }
+
+ closure = closure.getParent();
+ }
+
+ return null;
+ }
+
+ private static void eliminateLoop(Statement loop, Statement parentloop) {
+
+ // move continue edges to the parent loop
+ List<StatEdge> lst = new ArrayList<StatEdge>(loop.getLabelEdges());
+ for (StatEdge edge : lst) {
+ loop.removePredecessor(edge);
+ edge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, edge, parentloop);
+ parentloop.addPredecessor(edge);
+
+ parentloop.addLabeledEdge(edge);
+ }
+
+ // remove the last break edge, if exists
+ Statement loopcontent = loop.getFirst();
+ if (!loopcontent.getAllSuccessorEdges().isEmpty()) {
+ loopcontent.removeSuccessor(loopcontent.getAllSuccessorEdges().get(0));
+ }
+
+ // replace loop with its content
+ loop.getParent().replaceStatement(loop, loopcontent);
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/ExitHelper.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/ExitHelper.java
new file mode 100644
index 000000000000..af7358456ce5
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/ExitHelper.java
@@ -0,0 +1,345 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler;
+
+import org.jetbrains.java.decompiler.code.cfg.BasicBlock;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.ExitExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.*;
+import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+public class ExitHelper {
+
+
+ public static boolean condenseExits(RootStatement root) {
+
+ int changed = integrateExits(root);
+
+ if (changed > 0) {
+
+ cleanUpUnreachableBlocks(root);
+
+ SequenceHelper.condenseSequences(root);
+ }
+
+ return (changed > 0);
+ }
+
+
+ private static void cleanUpUnreachableBlocks(Statement stat) {
+
+ boolean found;
+ do {
+
+ found = false;
+
+ for (int i = 0; i < stat.getStats().size(); i++) {
+
+ Statement st = stat.getStats().get(i);
+
+ cleanUpUnreachableBlocks(st);
+
+ if (st.type == Statement.TYPE_SEQUENCE && st.getStats().size() > 1) {
+
+ Statement last = st.getStats().getLast();
+ Statement secondlast = st.getStats().get(st.getStats().size() - 2);
+
+ if (last.getExprents() == null || !last.getExprents().isEmpty()) {
+ if (!secondlast.hasBasicSuccEdge()) {
+
+ Set<Statement> set = last.getNeighboursSet(Statement.STATEDGE_DIRECT_ALL, Statement.DIRECTION_BACKWARD);
+ set.remove(secondlast);
+
+ if (set.isEmpty()) {
+ last.setExprents(new ArrayList<Exprent>());
+ found = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ while (found);
+ }
+
+
+ private static int integrateExits(Statement stat) {
+
+ int ret = 0;
+ Statement dest = null;
+
+ if (stat.getExprents() == null) {
+
+ while (true) {
+
+ int changed = 0;
+
+ for (Statement st : stat.getStats()) {
+ changed = integrateExits(st);
+ if (changed > 0) {
+ ret = 1;
+ break;
+ }
+ }
+
+ if (changed == 0) {
+ break;
+ }
+ }
+
+
+ switch (stat.type) {
+ case Statement.TYPE_IF:
+ IfStatement ifst = (IfStatement)stat;
+ if (ifst.getIfstat() == null) {
+ StatEdge ifedge = ifst.getIfEdge();
+ dest = isExitEdge(ifedge);
+ if (dest != null) {
+ BasicBlockStatement bstat = new BasicBlockStatement(new BasicBlock(
+ DecompilerContext.getCounterContainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER)));
+ bstat.setExprents(DecHelper.copyExprentList(dest.getExprents()));
+
+ ifst.getFirst().removeSuccessor(ifedge);
+ StatEdge newedge = new StatEdge(StatEdge.TYPE_REGULAR, ifst.getFirst(), bstat);
+ ifst.getFirst().addSuccessor(newedge);
+ ifst.setIfEdge(newedge);
+ ifst.setIfstat(bstat);
+ ifst.getStats().addWithKey(bstat, bstat.id);
+ bstat.setParent(ifst);
+
+ StatEdge oldexitedge = dest.getAllSuccessorEdges().get(0);
+ StatEdge newexitedge = new StatEdge(StatEdge.TYPE_BREAK, bstat, oldexitedge.getDestination());
+ bstat.addSuccessor(newexitedge);
+ oldexitedge.closure.addLabeledEdge(newexitedge);
+ ret = 1;
+ }
+ }
+ }
+ }
+
+
+ if (stat.getAllSuccessorEdges().size() == 1 &&
+ stat.getAllSuccessorEdges().get(0).getType() == StatEdge.TYPE_BREAK &&
+ stat.getLabelEdges().isEmpty()) {
+ Statement parent = stat.getParent();
+ if (stat != parent.getFirst() || (parent.type != Statement.TYPE_IF &&
+ parent.type != Statement.TYPE_SWITCH)) {
+
+ StatEdge destedge = stat.getAllSuccessorEdges().get(0);
+ dest = isExitEdge(destedge);
+ if (dest != null) {
+ stat.removeSuccessor(destedge);
+
+ BasicBlockStatement bstat = new BasicBlockStatement(new BasicBlock(
+ DecompilerContext.getCounterContainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER)));
+ bstat.setExprents(DecHelper.copyExprentList(dest.getExprents()));
+
+ StatEdge oldexitedge = dest.getAllSuccessorEdges().get(0);
+ StatEdge newexitedge = new StatEdge(StatEdge.TYPE_BREAK, bstat, oldexitedge.getDestination());
+ bstat.addSuccessor(newexitedge);
+ oldexitedge.closure.addLabeledEdge(newexitedge);
+
+ SequenceStatement block = new SequenceStatement(Arrays.asList(stat, bstat));
+ block.setAllParent();
+
+ parent.replaceStatement(stat, block);
+ // LabelHelper.lowContinueLabels not applicable because of forward continue edges
+ // LabelHelper.lowContinueLabels(block, new HashSet<StatEdge>());
+ // do it by hand
+ for (StatEdge prededge : block.getPredecessorEdges(StatEdge.TYPE_CONTINUE)) {
+
+ block.removePredecessor(prededge);
+ prededge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, prededge, stat);
+ stat.addPredecessor(prededge);
+
+ stat.addLabeledEdge(prededge);
+ }
+
+
+ stat.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, stat, bstat));
+
+ for (StatEdge edge : dest.getAllPredecessorEdges()) {
+ if (!edge.explicit && stat.containsStatementStrict(edge.getSource()) &&
+ MergeHelper.isDirectPath(edge.getSource().getParent(), bstat)) {
+
+ dest.removePredecessor(edge);
+ edge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, edge, bstat);
+ bstat.addPredecessor(edge);
+
+ if (!stat.containsStatementStrict(edge.closure)) {
+ stat.addLabeledEdge(edge);
+ }
+ }
+ }
+
+ ret = 2;
+ }
+ }
+ }
+
+ return ret;
+ }
+
+ private static Statement isExitEdge(StatEdge edge) {
+
+ Statement dest = edge.getDestination();
+
+ if (edge.getType() == StatEdge.TYPE_BREAK && dest.type == Statement.TYPE_BASICBLOCK
+ && edge.explicit && (edge.labeled || isOnlyEdge(edge))) {
+ List<Exprent> data = dest.getExprents();
+
+ if (data != null && data.size() == 1) {
+ if (data.get(0).type == Exprent.EXPRENT_EXIT) {
+ return dest;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private static boolean isOnlyEdge(StatEdge edge) {
+
+ Statement stat = edge.getDestination();
+
+ for (StatEdge ed : stat.getAllPredecessorEdges()) {
+ if (ed != edge) {
+ if (ed.getType() == StatEdge.TYPE_REGULAR) {
+ Statement source = ed.getSource();
+
+ if (source.type == Statement.TYPE_BASICBLOCK || (source.type == Statement.TYPE_IF &&
+ ((IfStatement)source).iftype == IfStatement.IFTYPE_IF) ||
+ (source.type == Statement.TYPE_DO && ((DoStatement)source).getLooptype() != DoStatement.LOOP_DO)) {
+ return false;
+ }
+ }
+ else {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public static boolean removeRedundantReturns(RootStatement root) {
+
+ boolean res = false;
+
+ for (StatEdge edge : root.getDummyExit().getAllPredecessorEdges()) {
+ if (!edge.explicit) {
+ Statement source = edge.getSource();
+ List<Exprent> lstExpr = source.getExprents();
+ if (lstExpr != null && !lstExpr.isEmpty()) {
+ Exprent expr = lstExpr.get(lstExpr.size() - 1);
+ if (expr.type == Exprent.EXPRENT_EXIT) {
+ ExitExprent ex = (ExitExprent)expr;
+ if (ex.getExittype() == ExitExprent.EXIT_RETURN && ex.getValue() == null) {
+ // remove redundant return
+ lstExpr.remove(lstExpr.size() - 1);
+ res = true;
+ }
+ }
+ }
+ }
+ }
+
+ return res;
+ }
+
+ public static boolean handleReturnFromInitializer(RootStatement root) {
+
+ boolean res = false;
+
+ Statement exit = root.getDummyExit();
+ Statement top = root.getFirst();
+ Statement newret = null;
+
+ boolean sharedcreated = false;
+
+ for (StatEdge edge : exit.getAllPredecessorEdges()) {
+ if (edge.explicit) {
+
+ if (!sharedcreated) {
+ newret = addSharedInitializerReturn(root);
+ sharedcreated = true;
+ }
+
+ Statement source = edge.getSource();
+ List<Exprent> lstExpr = source.getExprents();
+ if (lstExpr != null && !lstExpr.isEmpty()) {
+ Exprent expr = lstExpr.get(lstExpr.size() - 1);
+ if (expr.type == Exprent.EXPRENT_EXIT) {
+ ExitExprent ex = (ExitExprent)expr;
+ if (ex.getExittype() == ExitExprent.EXIT_RETURN && ex.getValue() == null) {
+ lstExpr.remove(lstExpr.size() - 1);
+
+ source.removeSuccessor(edge);
+ source.addSuccessor(new StatEdge(StatEdge.TYPE_BREAK, source, newret, top));
+
+ res = true;
+ }
+ }
+ }
+ }
+ }
+
+ return res;
+ }
+
+ private static Statement addSharedInitializerReturn(RootStatement root) {
+
+ Statement exit = root.getDummyExit();
+ Statement top = root.getFirst();
+
+ // build a new statement with the single instruction 'return'
+ BasicBlockStatement bstat = new BasicBlockStatement(new BasicBlock(
+ DecompilerContext.getCounterContainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER)));
+
+ ExitExprent retexpr = new ExitExprent(ExitExprent.EXIT_RETURN, null,
+ ((MethodDescriptor)DecompilerContext
+ .getProperty(DecompilerContext.CURRENT_METHOD_DESCRIPTOR)).ret);
+ // a changeable list needed
+ bstat.setExprents(new ArrayList<Exprent>(Arrays.asList(new Exprent[]{retexpr})));
+
+ // build sequence to replace the former top statement
+ SequenceStatement seq = new SequenceStatement(Arrays.asList(top, bstat));
+ top.setParent(seq);
+ bstat.setParent(seq);
+ seq.setParent(root);
+
+ root.getStats().removeWithKey(top.id);
+ root.getStats().addWithKeyAndIndex(0, seq, seq.id);
+ root.setFirst(seq);
+
+ for (StatEdge succedge : top.getAllSuccessorEdges()) {
+ top.removeSuccessor(succedge);
+ }
+
+ top.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, top, bstat));
+ bstat.addSuccessor(new StatEdge(StatEdge.TYPE_BREAK, bstat, exit, seq));
+
+ return bstat;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java
new file mode 100644
index 000000000000..0dc660ddf722
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java
@@ -0,0 +1,913 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.code.Instruction;
+import org.jetbrains.java.decompiler.code.InstructionSequence;
+import org.jetbrains.java.decompiler.code.cfg.BasicBlock;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
+import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectGraph;
+import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectNode;
+import org.jetbrains.java.decompiler.modules.decompiler.sforms.FlattenStatementsHelper;
+import org.jetbrains.java.decompiler.modules.decompiler.sforms.FlattenStatementsHelper.FinallyPathWrapper;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.*;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor;
+import org.jetbrains.java.decompiler.struct.StructClass;
+import org.jetbrains.java.decompiler.struct.attr.StructBootstrapMethodsAttribute;
+import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute;
+import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
+import org.jetbrains.java.decompiler.struct.consts.LinkConstant;
+import org.jetbrains.java.decompiler.struct.consts.PooledConstant;
+import org.jetbrains.java.decompiler.struct.consts.PrimitiveConstant;
+import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+
+import java.util.*;
+
+public class ExprProcessor implements CodeConstants {
+
+ public static final String UNDEFINED_TYPE_STRING = "<undefinedtype>";
+ public static final String UNKNOWN_TYPE_STRING = "<unknown>";
+ public static final String NULL_TYPE_STRING = "<null>";
+
+ private static final HashMap<Integer, Integer> mapConsts = new HashMap<Integer, Integer>();
+
+ static {
+
+ // mapConsts.put(new Integer(opc_i2l), new
+ // Integer(FunctionExprent.FUNCTION_I2L));
+ // mapConsts.put(new Integer(opc_i2f), new
+ // Integer(FunctionExprent.FUNCTION_I2F));
+ // mapConsts.put(new Integer(opc_i2d), new
+ // Integer(FunctionExprent.FUNCTION_I2D));
+ // mapConsts.put(new Integer(opc_l2i), new
+ // Integer(FunctionExprent.FUNCTION_L2I));
+ // mapConsts.put(new Integer(opc_l2f), new
+ // Integer(FunctionExprent.FUNCTION_L2F));
+ // mapConsts.put(new Integer(opc_l2d), new
+ // Integer(FunctionExprent.FUNCTION_L2D));
+ // mapConsts.put(new Integer(opc_f2i), new
+ // Integer(FunctionExprent.FUNCTION_F2I));
+ // mapConsts.put(new Integer(opc_f2l), new
+ // Integer(FunctionExprent.FUNCTION_F2L));
+ // mapConsts.put(new Integer(opc_f2d), new
+ // Integer(FunctionExprent.FUNCTION_F2D));
+ // mapConsts.put(new Integer(opc_d2i), new
+ // Integer(FunctionExprent.FUNCTION_D2I));
+ // mapConsts.put(new Integer(opc_d2l), new
+ // Integer(FunctionExprent.FUNCTION_D2L));
+ // mapConsts.put(new Integer(opc_d2f), new
+ // Integer(FunctionExprent.FUNCTION_D2F));
+ // mapConsts.put(new Integer(opc_i2b), new
+ // Integer(FunctionExprent.FUNCTION_I2B));
+ // mapConsts.put(new Integer(opc_i2c), new
+ // Integer(FunctionExprent.FUNCTION_I2C));
+ // mapConsts.put(new Integer(opc_i2s), new
+ // Integer(FunctionExprent.FUNCTION_I2S));
+
+ mapConsts.put(new Integer(opc_arraylength), new Integer(FunctionExprent.FUNCTION_ARRAYLENGTH));
+ mapConsts.put(new Integer(opc_checkcast), new Integer(FunctionExprent.FUNCTION_CAST));
+ mapConsts.put(new Integer(opc_instanceof), new Integer(FunctionExprent.FUNCTION_INSTANCEOF));
+ }
+
+ private static final VarType[] consts =
+ new VarType[]{VarType.VARTYPE_INT, VarType.VARTYPE_FLOAT, VarType.VARTYPE_LONG, VarType.VARTYPE_DOUBLE, VarType.VARTYPE_CLASS,
+ VarType.VARTYPE_STRING};
+
+ private static final VarType[] vartypes =
+ new VarType[]{VarType.VARTYPE_INT, VarType.VARTYPE_LONG, VarType.VARTYPE_FLOAT, VarType.VARTYPE_DOUBLE, VarType.VARTYPE_OBJECT};
+
+ private static final VarType[] arrtypes =
+ new VarType[]{VarType.VARTYPE_INT, VarType.VARTYPE_LONG, VarType.VARTYPE_FLOAT, VarType.VARTYPE_DOUBLE, VarType.VARTYPE_OBJECT,
+ VarType.VARTYPE_BOOLEAN, VarType.VARTYPE_CHAR, VarType.VARTYPE_SHORT};
+
+ private static final int[] func1 =
+ new int[]{FunctionExprent.FUNCTION_ADD, FunctionExprent.FUNCTION_SUB, FunctionExprent.FUNCTION_MUL, FunctionExprent.FUNCTION_DIV,
+ FunctionExprent.FUNCTION_REM};
+
+ private static final int[] func2 =
+ new int[]{FunctionExprent.FUNCTION_SHL, FunctionExprent.FUNCTION_SHR, FunctionExprent.FUNCTION_USHR, FunctionExprent.FUNCTION_AND,
+ FunctionExprent.FUNCTION_OR, FunctionExprent.FUNCTION_XOR};
+
+ private static final int[] func3 =
+ new int[]{FunctionExprent.FUNCTION_I2L, FunctionExprent.FUNCTION_I2F, FunctionExprent.FUNCTION_I2D, FunctionExprent.FUNCTION_L2I,
+ FunctionExprent.FUNCTION_L2F, FunctionExprent.FUNCTION_L2D, FunctionExprent.FUNCTION_F2I, FunctionExprent.FUNCTION_F2L,
+ FunctionExprent.FUNCTION_F2D,
+ FunctionExprent.FUNCTION_D2I, FunctionExprent.FUNCTION_D2L, FunctionExprent.FUNCTION_D2F, FunctionExprent.FUNCTION_I2B,
+ FunctionExprent.FUNCTION_I2C,
+ FunctionExprent.FUNCTION_I2S};
+
+ private static final int[] func4 =
+ new int[]{FunctionExprent.FUNCTION_LCMP, FunctionExprent.FUNCTION_FCMPL, FunctionExprent.FUNCTION_FCMPG, FunctionExprent.FUNCTION_DCMPL,
+ FunctionExprent.FUNCTION_DCMPG};
+
+ private static final int[] func5 =
+ new int[]{IfExprent.IF_EQ, IfExprent.IF_NE, IfExprent.IF_LT, IfExprent.IF_GE, IfExprent.IF_GT, IfExprent.IF_LE};
+
+ private static final int[] func6 =
+ new int[]{IfExprent.IF_ICMPEQ, IfExprent.IF_ICMPNE, IfExprent.IF_ICMPLT, IfExprent.IF_ICMPGE, IfExprent.IF_ICMPGT, IfExprent.IF_ICMPLE,
+ IfExprent.IF_ACMPEQ, IfExprent.IF_ACMPNE};
+
+ private static final int[] func7 = new int[]{IfExprent.IF_NULL, IfExprent.IF_NONNULL};
+
+ private static final int[] func8 = new int[]{MonitorExprent.MONITOR_ENTER, MonitorExprent.MONITOR_EXIT};
+
+ private static final int[] arr_type =
+ new int[]{CodeConstants.TYPE_BOOLEAN, CodeConstants.TYPE_CHAR, CodeConstants.TYPE_FLOAT, CodeConstants.TYPE_DOUBLE,
+ CodeConstants.TYPE_BYTE, CodeConstants.TYPE_SHORT, CodeConstants.TYPE_INT, CodeConstants.TYPE_LONG};
+
+ private static final int[] negifs =
+ new int[]{IfExprent.IF_NE, IfExprent.IF_EQ, IfExprent.IF_GE, IfExprent.IF_LT, IfExprent.IF_LE, IfExprent.IF_GT, IfExprent.IF_NONNULL,
+ IfExprent.IF_NULL, IfExprent.IF_ICMPNE, IfExprent.IF_ICMPEQ, IfExprent.IF_ICMPGE, IfExprent.IF_ICMPLT, IfExprent.IF_ICMPLE,
+ IfExprent.IF_ICMPGT, IfExprent.IF_ACMPNE,
+ IfExprent.IF_ACMPEQ};
+
+ private static final String[] typeNames = new String[]{"byte", "char", "double", "float", "int", "long", "short", "boolean",};
+
+ private VarProcessor varProcessor = (VarProcessor)DecompilerContext.getProperty(DecompilerContext.CURRENT_VAR_PROCESSOR);
+
+ public void processStatement(RootStatement root, StructClass cl) {
+
+ FlattenStatementsHelper flatthelper = new FlattenStatementsHelper();
+ DirectGraph dgraph = flatthelper.buildDirectGraph(root);
+
+ // try {
+ // DotExporter.toDotFile(dgraph, new File("c:\\Temp\\gr12_my.dot"));
+ // } catch (Exception ex) {
+ // ex.printStackTrace();
+ // }
+
+ // collect finally entry points
+ Set<String> setFinallyShortRangeEntryPoints = new HashSet<String>();
+ for (List<FinallyPathWrapper> lst : dgraph.mapShortRangeFinallyPaths.values()) {
+ for (FinallyPathWrapper finwrap : lst) {
+ setFinallyShortRangeEntryPoints.add(finwrap.entry);
+ }
+ }
+
+ Set<String> setFinallyLongRangeEntryPaths = new HashSet<String>();
+ for (List<FinallyPathWrapper> lst : dgraph.mapLongRangeFinallyPaths.values()) {
+ for (FinallyPathWrapper finwrap : lst) {
+ setFinallyLongRangeEntryPaths.add(finwrap.source + "##" + finwrap.entry);
+ }
+ }
+
+ Map<String, VarExprent> mapCatch = new HashMap<String, VarExprent>();
+ collectCatchVars(root, flatthelper, mapCatch);
+
+ Map<DirectNode, Map<String, PrimitiveExprsList>> mapData = new HashMap<DirectNode, Map<String, PrimitiveExprsList>>();
+
+ LinkedList<DirectNode> stack = new LinkedList<DirectNode>();
+ LinkedList<LinkedList<String>> stackEntryPoint = new LinkedList<LinkedList<String>>();
+
+ stack.add(dgraph.first);
+ stackEntryPoint.add(new LinkedList<String>());
+
+ Map<String, PrimitiveExprsList> map = new HashMap<String, PrimitiveExprsList>();
+ map.put(null, new PrimitiveExprsList());
+ mapData.put(dgraph.first, map);
+
+ while (!stack.isEmpty()) {
+
+ DirectNode node = stack.removeFirst();
+ LinkedList<String> entrypoints = stackEntryPoint.removeFirst();
+
+ PrimitiveExprsList data;
+ if (mapCatch.containsKey(node.id)) {
+ data = getExpressionData(mapCatch.get(node.id));
+ }
+ else {
+ data = mapData.get(node).get(buildEntryPointKey(entrypoints));
+ }
+
+ BasicBlockStatement block = node.block;
+ if (block != null) {
+ processBlock(block, data, cl);
+ block.setExprents(data.getLstExprents());
+ }
+
+ String currentEntrypoint = entrypoints.isEmpty() ? null : entrypoints.getLast();
+
+ for (DirectNode nd : node.succs) {
+
+ boolean isSuccessor = true;
+ if (currentEntrypoint != null && dgraph.mapLongRangeFinallyPaths.containsKey(node.id)) {
+ isSuccessor = false;
+ for (FinallyPathWrapper finwraplong : dgraph.mapLongRangeFinallyPaths.get(node.id)) {
+ if (finwraplong.source.equals(currentEntrypoint) && finwraplong.destination.equals(nd.id)) {
+ isSuccessor = true;
+ break;
+ }
+ }
+ }
+
+ if (isSuccessor) {
+
+ Map<String, PrimitiveExprsList> mapSucc = mapData.get(nd);
+ if (mapSucc == null) {
+ mapData.put(nd, mapSucc = new HashMap<String, PrimitiveExprsList>());
+ }
+
+ LinkedList<String> ndentrypoints = new LinkedList<String>(entrypoints);
+
+ if (setFinallyLongRangeEntryPaths.contains(node.id + "##" + nd.id)) {
+ ndentrypoints.addLast(node.id);
+ }
+ else if (!setFinallyShortRangeEntryPoints.contains(nd.id) && dgraph.mapLongRangeFinallyPaths.containsKey(node.id)) {
+ ndentrypoints.removeLast(); // currentEntrypoint should
+ // not be null at this point
+ }
+
+ // handling of entry point loops
+ int succ_entry_index = ndentrypoints.indexOf(nd.id);
+ if (succ_entry_index >=
+ 0) { // we are in a loop (e.g. continue in a finally block), drop all entry points in the list beginning with succ_entry_index
+ for (int elements_to_remove = ndentrypoints.size() - succ_entry_index; elements_to_remove > 0; elements_to_remove--) {
+ ndentrypoints.removeLast();
+ }
+ }
+
+ String ndentrykey = buildEntryPointKey(ndentrypoints);
+ if (!mapSucc.containsKey(ndentrykey)) {
+
+ mapSucc.put(ndentrykey, copyVarExprents(data.copyStack()));
+
+ stack.add(nd);
+ stackEntryPoint.add(ndentrypoints);
+ }
+ }
+ }
+ }
+
+ initStatementExprents(root);
+ }
+
+ // FIXME: Ugly code, to be rewritten. A tuple class is needed.
+ private static String buildEntryPointKey(LinkedList<String> entrypoints) {
+ if (entrypoints.isEmpty()) {
+ return null;
+ }
+ else {
+ StringBuilder buffer = new StringBuilder();
+ for (String point : entrypoints) {
+ buffer.append(point);
+ buffer.append(":");
+ }
+ return buffer.toString();
+ }
+ }
+
+ private static PrimitiveExprsList copyVarExprents(PrimitiveExprsList data) {
+ ExprentStack stack = data.getStack();
+ for (int i = 0; i < stack.size(); i++) {
+ stack.set(i, stack.get(i).copy());
+ }
+ return data;
+ }
+
+ private static void collectCatchVars(Statement stat, FlattenStatementsHelper flatthelper, Map<String, VarExprent> map) {
+
+ List<VarExprent> lst = null;
+
+ if (stat.type == Statement.TYPE_CATCHALL) {
+ CatchAllStatement catchall = (CatchAllStatement)stat;
+ if (!catchall.isFinally()) {
+ lst = catchall.getVars();
+ }
+ }
+ else if (stat.type == Statement.TYPE_TRYCATCH) {
+ lst = ((CatchStatement)stat).getVars();
+ }
+
+ if (lst != null) {
+ for (int i = 1; i < stat.getStats().size(); i++) {
+ map.put(flatthelper.getMapDestinationNodes().get(stat.getStats().get(i).id)[0], lst.get(i - 1));
+ }
+ }
+
+ for (Statement st : stat.getStats()) {
+ collectCatchVars(st, flatthelper, map);
+ }
+ }
+
+ private static void initStatementExprents(Statement stat) {
+ stat.initExprents();
+
+ for (Statement st : stat.getStats()) {
+ initStatementExprents(st);
+ }
+ }
+
+ public void processBlock(BasicBlockStatement stat, PrimitiveExprsList data, StructClass cl) {
+
+ ConstantPool pool = cl.getPool();
+ StructBootstrapMethodsAttribute bootstrap =
+ (StructBootstrapMethodsAttribute)cl.getAttributes().getWithKey(StructGeneralAttribute.ATTRIBUTE_BOOTSTRAP_METHODS);
+
+ BasicBlock block = stat.getBlock();
+
+ ExprentStack stack = data.getStack();
+ List<Exprent> exprlist = data.getLstExprents();
+
+ InstructionSequence seq = block.getSeq();
+
+ for (int i = 0; i < seq.length(); i++) {
+
+ Instruction instr = seq.getInstr(i);
+
+ switch (instr.opcode) {
+ case opc_aconst_null:
+ pushEx(stack, exprlist, new ConstExprent(VarType.VARTYPE_NULL, null));
+ break;
+ case opc_bipush:
+ case opc_sipush:
+ pushEx(stack, exprlist, new ConstExprent(instr.getOperand(0), true));
+ break;
+ case opc_lconst_0:
+ case opc_lconst_1:
+ pushEx(stack, exprlist, new ConstExprent(VarType.VARTYPE_LONG, new Long(instr.opcode - opc_lconst_0)));
+ break;
+ case opc_fconst_0:
+ case opc_fconst_1:
+ case opc_fconst_2:
+ pushEx(stack, exprlist, new ConstExprent(VarType.VARTYPE_FLOAT, new Float(instr.opcode - opc_fconst_0)));
+ break;
+ case opc_dconst_0:
+ case opc_dconst_1:
+ pushEx(stack, exprlist, new ConstExprent(VarType.VARTYPE_DOUBLE, new Double(instr.opcode - opc_dconst_0)));
+ break;
+ case opc_ldc:
+ case opc_ldc_w:
+ case opc_ldc2_w:
+ PrimitiveConstant cn = pool.getPrimitiveConstant(instr.getOperand(0));
+ pushEx(stack, exprlist, new ConstExprent(consts[cn.type - CONSTANT_Integer], cn.value));
+ break;
+ case opc_iload:
+ case opc_lload:
+ case opc_fload:
+ case opc_dload:
+ case opc_aload:
+ pushEx(stack, exprlist, new VarExprent(instr.getOperand(0), vartypes[instr.opcode - opc_iload], varProcessor));
+ break;
+ case opc_iaload:
+ case opc_laload:
+ case opc_faload:
+ case opc_daload:
+ case opc_aaload:
+ case opc_baload:
+ case opc_caload:
+ case opc_saload:
+ Exprent index = stack.pop();
+ Exprent arr = stack.pop();
+
+ VarType vartype = null;
+ switch (instr.opcode) {
+ case opc_laload:
+ vartype = VarType.VARTYPE_LONG;
+ break;
+ case opc_daload:
+ vartype = VarType.VARTYPE_DOUBLE;
+ }
+ pushEx(stack, exprlist, new ArrayExprent(arr, index, arrtypes[instr.opcode - opc_iaload]), vartype);
+ break;
+ case opc_istore:
+ case opc_lstore:
+ case opc_fstore:
+ case opc_dstore:
+ case opc_astore:
+ Exprent top = stack.pop();
+ int varindex = instr.getOperand(0);
+ AssignmentExprent assign =
+ new AssignmentExprent(new VarExprent(varindex, vartypes[instr.opcode - opc_istore], varProcessor), top);
+ exprlist.add(assign);
+ break;
+ case opc_iastore:
+ case opc_lastore:
+ case opc_fastore:
+ case opc_dastore:
+ case opc_aastore:
+ case opc_bastore:
+ case opc_castore:
+ case opc_sastore:
+ Exprent value = stack.pop();
+ Exprent index_store = stack.pop();
+ Exprent arr_store = stack.pop();
+ AssignmentExprent arrassign =
+ new AssignmentExprent(new ArrayExprent(arr_store, index_store, arrtypes[instr.opcode - opc_iastore]), value);
+ exprlist.add(arrassign);
+ break;
+ case opc_iadd:
+ case opc_ladd:
+ case opc_fadd:
+ case opc_dadd:
+ case opc_isub:
+ case opc_lsub:
+ case opc_fsub:
+ case opc_dsub:
+ case opc_imul:
+ case opc_lmul:
+ case opc_fmul:
+ case opc_dmul:
+ case opc_idiv:
+ case opc_ldiv:
+ case opc_fdiv:
+ case opc_ddiv:
+ case opc_irem:
+ case opc_lrem:
+ case opc_frem:
+ case opc_drem:
+ pushEx(stack, exprlist, new FunctionExprent(func1[(instr.opcode - opc_iadd) / 4], stack));
+ break;
+ case opc_ishl:
+ case opc_lshl:
+ case opc_ishr:
+ case opc_lshr:
+ case opc_iushr:
+ case opc_lushr:
+ case opc_iand:
+ case opc_land:
+ case opc_ior:
+ case opc_lor:
+ case opc_ixor:
+ case opc_lxor:
+ pushEx(stack, exprlist, new FunctionExprent(func2[(instr.opcode - opc_ishl) / 2], stack));
+ break;
+ case opc_ineg:
+ case opc_lneg:
+ case opc_fneg:
+ case opc_dneg:
+ pushEx(stack, exprlist, new FunctionExprent(FunctionExprent.FUNCTION_NEG, stack));
+ break;
+ case opc_iinc:
+ VarExprent vevar = new VarExprent(instr.getOperand(0), VarType.VARTYPE_INT, varProcessor);
+ exprlist.add(new AssignmentExprent(vevar, new FunctionExprent(
+ instr.getOperand(1) < 0 ? FunctionExprent.FUNCTION_SUB : FunctionExprent.FUNCTION_ADD, Arrays
+ .asList(new Exprent[]{vevar.copy(), new ConstExprent(VarType.VARTYPE_INT, new Integer(Math.abs(instr.getOperand(1))))}))));
+ break;
+ case opc_i2l:
+ case opc_i2f:
+ case opc_i2d:
+ case opc_l2i:
+ case opc_l2f:
+ case opc_l2d:
+ case opc_f2i:
+ case opc_f2l:
+ case opc_f2d:
+ case opc_d2i:
+ case opc_d2l:
+ case opc_d2f:
+ case opc_i2b:
+ case opc_i2c:
+ case opc_i2s:
+ pushEx(stack, exprlist, new FunctionExprent(func3[instr.opcode - opc_i2l], stack));
+ break;
+ case opc_lcmp:
+ case opc_fcmpl:
+ case opc_fcmpg:
+ case opc_dcmpl:
+ case opc_dcmpg:
+ pushEx(stack, exprlist, new FunctionExprent(func4[instr.opcode - opc_lcmp], stack));
+ break;
+ case opc_ifeq:
+ case opc_ifne:
+ case opc_iflt:
+ case opc_ifge:
+ case opc_ifgt:
+ case opc_ifle:
+ exprlist.add(new IfExprent(negifs[func5[instr.opcode - opc_ifeq]], stack));
+ break;
+ case opc_if_icmpeq:
+ case opc_if_icmpne:
+ case opc_if_icmplt:
+ case opc_if_icmpge:
+ case opc_if_icmpgt:
+ case opc_if_icmple:
+ case opc_if_acmpeq:
+ case opc_if_acmpne:
+ exprlist.add(new IfExprent(negifs[func6[instr.opcode - opc_if_icmpeq]], stack));
+ break;
+ case opc_ifnull:
+ case opc_ifnonnull:
+ exprlist.add(new IfExprent(negifs[func7[instr.opcode - opc_ifnull]], stack));
+ break;
+ case opc_tableswitch:
+ case opc_lookupswitch:
+ exprlist.add(new SwitchExprent(stack.pop()));
+ break;
+ case opc_ireturn:
+ case opc_lreturn:
+ case opc_freturn:
+ case opc_dreturn:
+ case opc_areturn:
+ case opc_return:
+ case opc_athrow:
+ exprlist.add(new ExitExprent(instr.opcode == opc_athrow ? ExitExprent.EXIT_THROW : ExitExprent.EXIT_RETURN,
+ instr.opcode == opc_return ? null : stack.pop(),
+ instr.opcode == opc_athrow
+ ? null
+ : ((MethodDescriptor)DecompilerContext
+ .getProperty(DecompilerContext.CURRENT_METHOD_DESCRIPTOR)).ret));
+ break;
+ case opc_monitorenter:
+ case opc_monitorexit:
+ exprlist.add(new MonitorExprent(func8[instr.opcode - opc_monitorenter], stack.pop()));
+ break;
+ case opc_checkcast:
+ case opc_instanceof:
+ stack.push(new ConstExprent(new VarType(pool.getPrimitiveConstant(instr.getOperand(0)).getString(), true), null));
+ case opc_arraylength:
+ pushEx(stack, exprlist, new FunctionExprent(mapConsts.get(instr.opcode).intValue(), stack));
+ break;
+ case opc_getstatic:
+ case opc_getfield:
+ pushEx(stack, exprlist,
+ new FieldExprent(pool.getLinkConstant(instr.getOperand(0)), instr.opcode == opc_getstatic ? null : stack.pop()));
+ break;
+ case opc_putstatic:
+ case opc_putfield:
+ Exprent valfield = stack.pop();
+ Exprent exprfield =
+ new FieldExprent(pool.getLinkConstant(instr.getOperand(0)), instr.opcode == opc_putstatic ? null : stack.pop());
+ exprlist.add(new AssignmentExprent(exprfield, valfield));
+ break;
+ case opc_invokevirtual:
+ case opc_invokespecial:
+ case opc_invokestatic:
+ case opc_invokeinterface:
+ case opc_invokedynamic:
+ if (instr.opcode != opc_invokedynamic || instr.bytecode_version >= CodeConstants.BYTECODE_JAVA_7) {
+
+ LinkConstant invoke_constant = pool.getLinkConstant(instr.getOperand(0));
+ int dynamic_invokation_type = -1;
+
+ if (instr.opcode == opc_invokedynamic && bootstrap != null) {
+ List<PooledConstant> bootstrap_arguments = bootstrap.getMethodArguments(invoke_constant.index1);
+ LinkConstant content_method_handle = (LinkConstant)bootstrap_arguments.get(1);
+
+ dynamic_invokation_type = content_method_handle.index1;
+ }
+
+ InvocationExprent exprinv = new InvocationExprent(instr.opcode, invoke_constant, stack, dynamic_invokation_type);
+ if (exprinv.getDescriptor().ret.type == CodeConstants.TYPE_VOID) {
+ exprlist.add(exprinv);
+ }
+ else {
+ pushEx(stack, exprlist, exprinv);
+ }
+ }
+ break;
+ case opc_new:
+ case opc_anewarray:
+ case opc_multianewarray:
+ int arrdims = (instr.opcode == opc_new) ? 0 : (instr.opcode == opc_anewarray) ? 1 : instr.getOperand(1);
+ VarType arrtype = new VarType(pool.getPrimitiveConstant(instr.getOperand(0)).getString(), true);
+ if (instr.opcode != opc_multianewarray) {
+ arrtype.arraydim += arrdims;
+ }
+ pushEx(stack, exprlist, new NewExprent(arrtype, stack, arrdims));
+ break;
+ case opc_newarray:
+ pushEx(stack, exprlist, new NewExprent(new VarType(arr_type[instr.getOperand(0) - 4], 1), stack, 1));
+ break;
+ case opc_dup:
+ pushEx(stack, exprlist, stack.getByOffset(-1).copy());
+ break;
+ case opc_dup_x1:
+ insertByOffsetEx(-2, stack, exprlist, -1);
+ break;
+ case opc_dup_x2:
+ if (stack.getByOffset(-2).getExprType().stack_size == 2) {
+ insertByOffsetEx(-2, stack, exprlist, -1);
+ }
+ else {
+ insertByOffsetEx(-3, stack, exprlist, -1);
+ }
+ break;
+ case opc_dup2:
+ if (stack.getByOffset(-1).getExprType().stack_size == 2) {
+ pushEx(stack, exprlist, stack.getByOffset(-1).copy());
+ }
+ else {
+ pushEx(stack, exprlist, stack.getByOffset(-2).copy());
+ pushEx(stack, exprlist, stack.getByOffset(-2).copy());
+ }
+ break;
+ case opc_dup2_x1:
+ if (stack.getByOffset(-1).getExprType().stack_size == 2) {
+ insertByOffsetEx(-2, stack, exprlist, -1);
+ }
+ else {
+ insertByOffsetEx(-3, stack, exprlist, -2);
+ insertByOffsetEx(-3, stack, exprlist, -1);
+ }
+ break;
+ case opc_dup2_x2:
+ if (stack.getByOffset(-1).getExprType().stack_size == 2) {
+ if (stack.getByOffset(-2).getExprType().stack_size == 2) {
+ insertByOffsetEx(-2, stack, exprlist, -1);
+ }
+ else {
+ insertByOffsetEx(-3, stack, exprlist, -1);
+ }
+ }
+ else {
+ if (stack.getByOffset(-3).getExprType().stack_size == 2) {
+ insertByOffsetEx(-3, stack, exprlist, -2);
+ insertByOffsetEx(-3, stack, exprlist, -1);
+ }
+ else {
+ insertByOffsetEx(-4, stack, exprlist, -2);
+ insertByOffsetEx(-4, stack, exprlist, -1);
+ }
+ }
+ break;
+ case opc_swap:
+ insertByOffsetEx(-2, stack, exprlist, -1);
+ stack.pop();
+ break;
+ case opc_pop:
+ case opc_pop2:
+ stack.pop();
+ }
+ }
+ }
+
+ private void pushEx(ExprentStack stack, List<Exprent> exprlist, Exprent exprent) {
+ pushEx(stack, exprlist, exprent, null);
+ }
+
+ private void pushEx(ExprentStack stack, List<Exprent> exprlist, Exprent exprent, VarType vartype) {
+ int varindex = VarExprent.STACK_BASE + stack.size();
+ VarExprent var = new VarExprent(varindex, vartype == null ? exprent.getExprType() : vartype, varProcessor);
+ var.setStack(true);
+
+ exprlist.add(new AssignmentExprent(var, exprent));
+ stack.push(var.copy());
+ }
+
+ private void insertByOffsetEx(int offset, ExprentStack stack, List<Exprent> exprlist, int copyoffset) {
+
+ int base = VarExprent.STACK_BASE + stack.size();
+
+ LinkedList<VarExprent> lst = new LinkedList<VarExprent>();
+
+ for (int i = -1; i >= offset; i--) {
+ Exprent varex = stack.pop();
+ VarExprent varnew = new VarExprent(base + i + 1, varex.getExprType(), varProcessor);
+ varnew.setStack(true);
+ exprlist.add(new AssignmentExprent(varnew, varex));
+ lst.add(0, (VarExprent)varnew.copy());
+ }
+
+ Exprent exprent = lst.get(lst.size() + copyoffset).copy();
+ VarExprent var = new VarExprent(base + offset, exprent.getExprType(), varProcessor);
+ var.setStack(true);
+ exprlist.add(new AssignmentExprent(var, exprent));
+ lst.add(0, (VarExprent)var.copy());
+
+ for (VarExprent expr : lst) {
+ stack.push(expr);
+ }
+ }
+
+ public static String getTypeName(VarType type) {
+ return getTypeName(type, true);
+ }
+
+ public static String getTypeName(VarType type, boolean getShort) {
+
+ int tp = type.type;
+ if (tp <= CodeConstants.TYPE_BOOLEAN) {
+ return typeNames[tp];
+ }
+ else if (tp == CodeConstants.TYPE_UNKNOWN) {
+ return UNKNOWN_TYPE_STRING; // INFO: should not occur
+ }
+ else if (tp == CodeConstants.TYPE_NULL) {
+ return NULL_TYPE_STRING; // INFO: should not occur
+ }
+ else if (tp == CodeConstants.TYPE_VOID) {
+ return "void";
+ }
+ else if (tp == CodeConstants.TYPE_OBJECT) {
+ String ret = buildJavaClassName(type.value);
+ if (getShort) {
+ ret = DecompilerContext.getImportCollector().getShortName(ret);
+ }
+
+ if (ret == null) {
+ // FIXME: a warning should be logged
+ ret = UNDEFINED_TYPE_STRING;
+ }
+ return ret;
+ }
+
+ throw new RuntimeException("invalid type");
+ }
+
+ public static String getCastTypeName(VarType type) {
+ return getCastTypeName(type, true);
+ }
+
+ public static String getCastTypeName(VarType type, boolean getShort) {
+ String s = getTypeName(type, getShort);
+ int dim = type.arraydim;
+ while (dim-- > 0) {
+ s += "[]";
+ }
+ return s;
+ }
+
+ public static PrimitiveExprsList getExpressionData(VarExprent var) {
+ PrimitiveExprsList prlst = new PrimitiveExprsList();
+ VarExprent vartmp = new VarExprent(VarExprent.STACK_BASE, var.getExprType(), var.getProcessor());
+ vartmp.setStack(true);
+
+ prlst.getLstExprents().add(new AssignmentExprent(vartmp, var.copy()));
+ prlst.getStack().push(vartmp.copy());
+ return prlst;
+ }
+
+ public static boolean endsWithSemikolon(Exprent expr) {
+ int type = expr.type;
+ return !(type == Exprent.EXPRENT_SWITCH ||
+ type == Exprent.EXPRENT_MONITOR ||
+ type == Exprent.EXPRENT_IF ||
+ (type == Exprent.EXPRENT_VAR && ((VarExprent)expr)
+ .isClassdef()));
+ }
+
+ public static String jmpWrapper(Statement stat, int indent, boolean semicolon) {
+ StringBuilder buf = new StringBuilder(stat.toJava(indent));
+
+ String new_line_separator = DecompilerContext.getNewLineSeparator();
+
+ List<StatEdge> lstSuccs = stat.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL);
+ if (lstSuccs.size() == 1) {
+ StatEdge edge = lstSuccs.get(0);
+ if (edge.getType() != StatEdge.TYPE_REGULAR && edge.explicit && edge.getDestination().type != Statement.TYPE_DUMMYEXIT) {
+ buf.append(InterpreterUtil.getIndentString(indent));
+
+ switch (edge.getType()) {
+ case StatEdge.TYPE_BREAK:
+ buf.append("break");
+ break;
+ case StatEdge.TYPE_CONTINUE:
+ buf.append("continue");
+ }
+
+ if (edge.labeled) {
+ buf.append(" label").append(edge.closure.id);
+ }
+ buf.append(";").append(new_line_separator);
+ }
+ }
+
+ if (buf.length() == 0 && semicolon) {
+ buf.append(InterpreterUtil.getIndentString(indent)).append(";").append(new_line_separator);
+ }
+
+ return buf.toString();
+ }
+
+ public static String buildJavaClassName(String name) {
+ String res = name.replace('/', '.');
+
+ if (res.contains("$")) { // attempt to invoke foreign member
+ // classes correctly
+ StructClass cl = DecompilerContext.getStructContext().getClass(name);
+ if (cl == null || !cl.isOwn()) {
+ res = res.replace('$', '.');
+ }
+ }
+
+ return res;
+ }
+
+ public static String listToJava(List<Exprent> lst, int indent) {
+ if (lst == null || lst.isEmpty()) {
+ return "";
+ }
+
+ String indstr = InterpreterUtil.getIndentString(indent);
+ String new_line_separator = DecompilerContext.getNewLineSeparator();
+
+ StringBuilder buf = new StringBuilder();
+
+ for (Exprent expr : lst) {
+ String content = expr.toJava(indent);
+ if (content.length() > 0) {
+ if (expr.type != Exprent.EXPRENT_VAR || !((VarExprent)expr).isClassdef()) {
+ buf.append(indstr);
+ }
+ buf.append(content);
+ if (expr.type == Exprent.EXPRENT_MONITOR && ((MonitorExprent)expr).getMontype() == MonitorExprent.MONITOR_ENTER) {
+ buf.append("{}"); // empty synchronized block
+ }
+ if (endsWithSemikolon(expr)) {
+ buf.append(";");
+ }
+ buf.append(new_line_separator);
+ }
+ }
+
+ return buf.toString();
+ }
+
+ public static ConstExprent getDefaultArrayValue(VarType arrtype) {
+
+ ConstExprent defaultval;
+ if (arrtype.type == CodeConstants.TYPE_OBJECT || arrtype.arraydim > 0) {
+ defaultval = new ConstExprent(VarType.VARTYPE_NULL, null);
+ }
+ else if (arrtype.type == CodeConstants.TYPE_FLOAT) {
+ defaultval = new ConstExprent(VarType.VARTYPE_FLOAT, new Float(0));
+ }
+ else if (arrtype.type == CodeConstants.TYPE_LONG) {
+ defaultval = new ConstExprent(VarType.VARTYPE_LONG, new Long(0));
+ }
+ else if (arrtype.type == CodeConstants.TYPE_DOUBLE) {
+ defaultval = new ConstExprent(VarType.VARTYPE_DOUBLE, new Double(0));
+ }
+ else { // integer types
+ defaultval = new ConstExprent(0, true);
+ }
+
+ return defaultval;
+ }
+
+ public static boolean getCastedExprent(Exprent exprent, VarType leftType, StringBuilder buffer, int indent, boolean castNull) {
+ return getCastedExprent(exprent, leftType, buffer, indent, castNull, false);
+ }
+
+ public static boolean getCastedExprent(Exprent exprent,
+ VarType leftType,
+ StringBuilder buffer,
+ int indent,
+ boolean castNull,
+ boolean castAlways) {
+
+ boolean ret = false;
+ VarType rightType = exprent.getExprType();
+
+ String res = exprent.toJava(indent);
+
+ boolean cast =
+ !leftType.isSuperset(rightType) && (rightType.equals(VarType.VARTYPE_OBJECT) || leftType.type != CodeConstants.TYPE_OBJECT);
+ cast |= castAlways;
+
+ if (!cast && castNull && rightType.type == CodeConstants.TYPE_NULL) {
+ // check for a nameless anonymous class
+ cast = !UNDEFINED_TYPE_STRING.equals(getTypeName(leftType));
+ }
+ if (!cast) {
+ cast = isIntConstant(exprent) && VarType.VARTYPE_INT.isStrictSuperset(leftType);
+ }
+
+ if (cast) {
+ if (exprent.getPrecedence() >= FunctionExprent.getPrecedence(FunctionExprent.FUNCTION_CAST)) {
+ res = "(" + res + ")";
+ }
+
+ res = "(" + getCastTypeName(leftType) + ")" + res;
+ ret = true;
+ }
+
+ buffer.append(res);
+
+ return ret;
+ }
+
+ private static boolean isIntConstant(Exprent exprent) {
+
+ if (exprent.type == Exprent.EXPRENT_CONST) {
+ ConstExprent cexpr = (ConstExprent)exprent;
+ switch (cexpr.getConsttype().type) {
+ case CodeConstants.TYPE_BYTE:
+ case CodeConstants.TYPE_BYTECHAR:
+ case CodeConstants.TYPE_SHORT:
+ case CodeConstants.TYPE_SHORTCHAR:
+ case CodeConstants.TYPE_INT:
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/ExprentStack.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/ExprentStack.java
new file mode 100644
index 000000000000..c4cded20428d
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/ExprentStack.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler;
+
+import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
+import org.jetbrains.java.decompiler.util.ListStack;
+
+public class ExprentStack extends ListStack<Exprent> {
+
+ public ExprentStack() {
+ }
+
+ public ExprentStack(ListStack<Exprent> list) {
+ super(list);
+ pointer = list.getPointer();
+ }
+
+ public Exprent push(Exprent item) {
+ super.push(item);
+
+ return item;
+ }
+
+ public Exprent pop() {
+
+ return this.remove(--pointer);
+ }
+
+ public ExprentStack clone() {
+ return new ExprentStack(this);
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/FinallyProcessor.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/FinallyProcessor.java
new file mode 100644
index 000000000000..6198da1b21bf
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/FinallyProcessor.java
@@ -0,0 +1,1087 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler;
+
+import org.jetbrains.java.decompiler.code.*;
+import org.jetbrains.java.decompiler.code.cfg.BasicBlock;
+import org.jetbrains.java.decompiler.code.cfg.ControlFlowGraph;
+import org.jetbrains.java.decompiler.code.cfg.ExceptionRangeCFG;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
+import org.jetbrains.java.decompiler.modules.code.DeadCodeHelper;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.AssignmentExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.ExitExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectGraph;
+import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectNode;
+import org.jetbrains.java.decompiler.modules.decompiler.sforms.FlattenStatementsHelper;
+import org.jetbrains.java.decompiler.modules.decompiler.sforms.SSAConstructorSparseEx;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.BasicBlockStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.CatchAllStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar;
+import org.jetbrains.java.decompiler.struct.StructMethod;
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+
+import java.util.*;
+import java.util.Map.Entry;
+
+public class FinallyProcessor {
+
+ private Map<Integer, Integer> finallyBlockIDs = new HashMap<Integer, Integer>();
+ private Map<Integer, Integer> catchallBlockIDs = new HashMap<Integer, Integer>();
+
+ private VarProcessor varprocessor;
+
+ public FinallyProcessor(VarProcessor varprocessor) {
+ this.varprocessor = varprocessor;
+ }
+
+ public boolean iterateGraph(StructMethod mt, RootStatement root, ControlFlowGraph graph) {
+ // return processStatement(mt, root, graph, root);
+ return processStatementEx(mt, root, graph);
+ }
+
+ private boolean processStatementEx(StructMethod mt, RootStatement root, ControlFlowGraph graph) {
+
+ int bytecode_version = mt.getClassStruct().getBytecodeVersion();
+
+ LinkedList<Statement> stack = new LinkedList<Statement>();
+ stack.add(root);
+
+ while (!stack.isEmpty()) {
+
+ Statement stat = stack.removeLast();
+
+ Statement parent = stat.getParent();
+ if (parent != null && parent.type == Statement.TYPE_CATCHALL &&
+ stat == parent.getFirst() && !parent.isCopied()) {
+
+ CatchAllStatement fin = (CatchAllStatement)parent;
+ BasicBlock head = fin.getBasichead().getBlock();
+ BasicBlock handler = fin.getHandler().getBasichead().getBlock();
+
+ if (catchallBlockIDs.containsKey(handler.id)) {
+ // do nothing
+ }
+ else if (finallyBlockIDs.containsKey(handler.id)) {
+
+ fin.setFinally(true);
+
+ Integer var = finallyBlockIDs.get(handler.id);
+ fin.setMonitor(var == null ? null : new VarExprent(var.intValue(), VarType.VARTYPE_INT, varprocessor));
+ }
+ else {
+
+ Record inf = getFinallyInformation(mt, root, fin);
+
+ if (inf == null) { // inconsistent finally
+ catchallBlockIDs.put(handler.id, null);
+ }
+ else {
+
+ if (DecompilerContext.getOption(IFernflowerPreferences.FINALLY_DEINLINE) && verifyFinallyEx(graph, fin, inf)) {
+ finallyBlockIDs.put(handler.id, null);
+ }
+ else {
+
+ int varindex = DecompilerContext.getCounterContainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER);
+ insertSemaphore(graph, getAllBasicBlocks(fin.getFirst()), head, handler, varindex, inf, bytecode_version);
+
+ finallyBlockIDs.put(handler.id, varindex);
+ }
+
+ DeadCodeHelper.removeDeadBlocks(graph); // e.g. multiple return blocks after a nested finally
+ DeadCodeHelper.removeEmptyBlocks(graph);
+ DeadCodeHelper.mergeBasicBlocks(graph);
+ }
+
+ return true;
+ }
+ }
+
+ stack.addAll(stat.getStats());
+ }
+
+ return false;
+ }
+
+
+ // private boolean processStatement(StructMethod mt, RootStatement root, ControlFlowGraph graph, Statement stat) {
+ //
+ // boolean res = false;
+ //
+ // for(int i=stat.getStats().size()-1;i>=0;i--) {
+ // if(processStatement(mt, root, graph, stat.getStats().get(i))) {
+ // return true;
+ // }
+ // }
+ //
+ //
+ // if(stat.type == Statement.TYPE_CATCHALL && !stat.isCopied()) {
+ //
+ // CatchAllStatement fin = (CatchAllStatement)stat;
+ // BasicBlock head = fin.getBasichead().getBlock();
+ // BasicBlock handler = fin.getHandler().getBasichead().getBlock();
+ //
+ // if(catchallBlockIDs.containsKey(handler.id)) {
+ // ; // do nothing
+ // }else if(finallyBlockIDs.containsKey(handler.id)) {
+ //
+ // fin.setFinally(true);
+ //
+ // Integer var = finallyBlockIDs.get(handler.id);
+ // fin.setMonitor(var==null?null:new VarExprent(var.intValue(), VarType.VARTYPE_INT, varprocessor));
+ //
+ // } else {
+ //
+ // Object[] inf = getFinallyInformation(mt, root, fin);
+ //
+ // if(inf == null) { // inconsistent finally
+ // catchallBlockIDs.put(handler.id, null);
+ // } else {
+ //
+ // if(DecompilerContext.getOption(IFernflowerPreferences.FINALLY_DEINLINE) && verifyFinallyEx(graph, fin, inf)) {
+ // finallyBlockIDs.put(handler.id, null);
+ // } else {
+ //
+ // int varindex = DecompilerContext.getCountercontainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER);
+ // insertSemaphore(graph, getAllBasicBlocks(fin.getFirst()), head, handler, varindex, inf);
+ //
+ // finallyBlockIDs.put(handler.id, varindex);
+ // }
+ //
+ // DeadCodeHelper.removeEmptyBlocks(graph);
+ // DeadCodeHelper.mergeBasicBlocks(graph);
+ // }
+ //
+ // res = true;
+ // }
+ // }
+ //
+ // return res;
+ // }
+
+ private static class Record {
+ private final int firstCode;
+ private final Map<BasicBlock, Boolean> mapLast;
+
+ private Record(int firstCode, Map<BasicBlock, Boolean> mapLast) {
+ this.firstCode = firstCode;
+ this.mapLast = mapLast;
+ }
+ }
+
+
+ private static Record getFinallyInformation(StructMethod mt, RootStatement root, CatchAllStatement fstat) {
+
+ Map<BasicBlock, Boolean> mapLast = new HashMap<BasicBlock, Boolean>();
+
+ BasicBlockStatement firstBlockStatement = fstat.getHandler().getBasichead();
+ BasicBlock firstBasicBlock = firstBlockStatement.getBlock();
+ Instruction instrFirst = firstBasicBlock.getInstruction(0);
+
+ int firstcode = 0;
+
+ switch (instrFirst.opcode) {
+ case CodeConstants.opc_pop:
+ firstcode = 1;
+ break;
+ case CodeConstants.opc_astore:
+ firstcode = 2;
+ }
+
+ ExprProcessor proc = new ExprProcessor();
+ proc.processStatement(root, mt.getClassStruct());
+
+ SSAConstructorSparseEx ssa = new SSAConstructorSparseEx();
+ ssa.splitVariables(root, mt);
+
+ List<Exprent> lstExprents = firstBlockStatement.getExprents();
+
+ VarVersionPaar varpaar = new VarVersionPaar((VarExprent)((AssignmentExprent)lstExprents.get(firstcode == 2 ? 1 : 0)).getLeft());
+
+ FlattenStatementsHelper flatthelper = new FlattenStatementsHelper();
+ DirectGraph dgraph = flatthelper.buildDirectGraph(root);
+
+ LinkedList<DirectNode> stack = new LinkedList<DirectNode>();
+ stack.add(dgraph.first);
+
+ Set<DirectNode> setVisited = new HashSet<DirectNode>();
+
+ while (!stack.isEmpty()) {
+
+ DirectNode node = stack.removeFirst();
+
+ if (setVisited.contains(node)) {
+ continue;
+ }
+ setVisited.add(node);
+
+ BasicBlockStatement blockStatement = null;
+ if (node.block != null) {
+ blockStatement = node.block;
+ }
+ else if (node.preds.size() == 1) {
+ blockStatement = node.preds.get(0).block;
+ }
+
+ boolean isTrueExit = true;
+
+ if (firstcode != 1) {
+
+ isTrueExit = false;
+
+ for (int i = 0; i < node.exprents.size(); i++) {
+ Exprent exprent = node.exprents.get(i);
+
+ if (firstcode == 0) {
+ List<Exprent> lst = exprent.getAllExprents();
+ lst.add(exprent);
+
+ boolean found = false;
+ for (Exprent expr : lst) {
+ if (expr.type == Exprent.EXPRENT_VAR && new VarVersionPaar((VarExprent)expr).equals(varpaar)) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+ found = false;
+ if (exprent.type == Exprent.EXPRENT_EXIT) {
+ ExitExprent exexpr = (ExitExprent)exprent;
+ if (exexpr.getExittype() == ExitExprent.EXIT_THROW && exexpr.getValue().type == Exprent.EXPRENT_VAR) {
+ found = true;
+ }
+ }
+
+ if (!found) {
+ return null;
+ }
+ else {
+ isTrueExit = true;
+ }
+ }
+ }
+ else if (firstcode == 2) {
+ // search for a load instruction
+ if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent assexpr = (AssignmentExprent)exprent;
+ if (assexpr.getRight().type == Exprent.EXPRENT_VAR &&
+ new VarVersionPaar((VarExprent)assexpr.getRight()).equals(varpaar)) {
+
+ Exprent next = null;
+ if (i == node.exprents.size() - 1) {
+ if (node.succs.size() == 1) {
+ DirectNode nd = node.succs.get(0);
+ if (!nd.exprents.isEmpty()) {
+ next = nd.exprents.get(0);
+ }
+ }
+ }
+ else {
+ next = node.exprents.get(i + 1);
+ }
+
+ boolean found = false;
+ if (next != null && next.type == Exprent.EXPRENT_EXIT) {
+ ExitExprent exexpr = (ExitExprent)next;
+ if (exexpr.getExittype() == ExitExprent.EXIT_THROW && exexpr.getValue().type == Exprent.EXPRENT_VAR
+ && assexpr.getLeft().equals(exexpr.getValue())) {
+ found = true;
+ }
+ }
+
+ if (!found) {
+ return null;
+ }
+ else {
+ isTrueExit = true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // find finally exits
+ if (blockStatement != null && blockStatement.getBlock() != null) {
+ Statement handler = fstat.getHandler();
+ for (StatEdge edge : blockStatement.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL)) {
+ if (edge.getType() != StatEdge.TYPE_REGULAR && handler.containsStatement(blockStatement)
+ && !handler.containsStatement(edge.getDestination())) {
+ Boolean existingFlag = mapLast.get(blockStatement.getBlock());
+ // note: the dummy node is also processed!
+ if (existingFlag == null || !existingFlag) {
+ mapLast.put(blockStatement.getBlock(), isTrueExit);
+ break;
+ }
+ }
+ }
+ }
+
+ stack.addAll(node.succs);
+ }
+
+ // empty finally block?
+ if (fstat.getHandler().type == Statement.TYPE_BASICBLOCK) {
+
+ boolean isEmpty = false;
+ boolean isFirstLast = mapLast.containsKey(firstBasicBlock);
+ InstructionSequence seq = firstBasicBlock.getSeq();
+
+ switch (firstcode) {
+ case 0:
+ isEmpty = isFirstLast && seq.length() == 1;
+ break;
+ case 1:
+ isEmpty = seq.length() == 1;
+ break;
+ case 2:
+ isEmpty = isFirstLast ? seq.length() == 3 : seq.length() == 1;
+ }
+
+ if (isEmpty) {
+ firstcode = 3;
+ }
+ }
+
+ return new Record(firstcode, mapLast);
+ }
+
+ private static void insertSemaphore(ControlFlowGraph graph,
+ Set<BasicBlock> setTry,
+ BasicBlock head,
+ BasicBlock handler,
+ int var,
+ Record information,
+ int bytecode_version) {
+
+ Set<BasicBlock> setCopy = new HashSet<BasicBlock>(setTry);
+
+ int finallytype = information.firstCode;
+ Map<BasicBlock, Boolean> mapLast = information.mapLast;
+
+ // first and last statements
+ removeExceptionInstructionsEx(handler, 1, finallytype);
+ for (Entry<BasicBlock, Boolean> entry : mapLast.entrySet()) {
+ BasicBlock last = entry.getKey();
+
+ if (entry.getValue()) {
+ removeExceptionInstructionsEx(last, 2, finallytype);
+ graph.getFinallyExits().add(last);
+ }
+ }
+
+ // disable semaphore at statement exit points
+ for (BasicBlock block : setTry) {
+
+ List<BasicBlock> lstSucc = block.getSuccs();
+ for (BasicBlock dest : lstSucc) {
+
+ // break out
+ if (!setCopy.contains(dest) && dest != graph.getLast()) {
+ // disable semaphore
+ SimpleInstructionSequence seq = new SimpleInstructionSequence();
+
+ seq.addInstruction(ConstantsUtil
+ .getInstructionInstance(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, bytecode_version,
+ new int[]{0}), -1);
+ seq.addInstruction(ConstantsUtil
+ .getInstructionInstance(CodeConstants.opc_istore, false, CodeConstants.GROUP_GENERAL, bytecode_version,
+ new int[]{var}), -1);
+
+ // build a separate block
+ BasicBlock newblock = new BasicBlock(++graph.last_id);
+ newblock.setSeq(seq);
+
+ // insert between block and dest
+ block.replaceSuccessor(dest, newblock);
+ newblock.addSuccessor(dest);
+ setCopy.add(newblock);
+ graph.getBlocks().addWithKey(newblock, newblock.id);
+
+ // exception ranges
+ // FIXME: special case synchronized
+
+ // copy exception edges and extend protected ranges
+ for (int j = 0; j < block.getSuccExceptions().size(); j++) {
+ BasicBlock hd = block.getSuccExceptions().get(j);
+ newblock.addSuccessorException(hd);
+
+ ExceptionRangeCFG range = graph.getExceptionRange(hd, block);
+ range.getProtectedRange().add(newblock);
+ }
+ }
+ }
+ }
+
+ // enable semaphor at the statement entrance
+ SimpleInstructionSequence seq = new SimpleInstructionSequence();
+ seq.addInstruction(
+ ConstantsUtil.getInstructionInstance(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{1}),
+ -1);
+ seq.addInstruction(
+ ConstantsUtil.getInstructionInstance(CodeConstants.opc_istore, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{var}),
+ -1);
+
+ BasicBlock newhead = new BasicBlock(++graph.last_id);
+ newhead.setSeq(seq);
+
+ insertBlockBefore(graph, head, newhead);
+
+ // initialize semaphor with false
+ seq = new SimpleInstructionSequence();
+ seq.addInstruction(
+ ConstantsUtil.getInstructionInstance(CodeConstants.opc_bipush, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{0}),
+ -1);
+ seq.addInstruction(
+ ConstantsUtil.getInstructionInstance(CodeConstants.opc_istore, false, CodeConstants.GROUP_GENERAL, bytecode_version, new int[]{var}),
+ -1);
+
+ BasicBlock newheadinit = new BasicBlock(++graph.last_id);
+ newheadinit.setSeq(seq);
+
+ insertBlockBefore(graph, newhead, newheadinit);
+
+ setCopy.add(newhead);
+ setCopy.add(newheadinit);
+
+ for (BasicBlock hd : new HashSet<BasicBlock>(newheadinit.getSuccExceptions())) {
+ ExceptionRangeCFG range = graph.getExceptionRange(hd, newheadinit);
+
+ if (setCopy.containsAll(range.getProtectedRange())) {
+ newheadinit.removeSuccessorException(hd);
+ range.getProtectedRange().remove(newheadinit);
+ }
+ }
+ }
+
+
+ private static void insertBlockBefore(ControlFlowGraph graph, BasicBlock oldblock, BasicBlock newblock) {
+
+ List<BasicBlock> lstTemp = new ArrayList<BasicBlock>();
+ lstTemp.addAll(oldblock.getPreds());
+ lstTemp.addAll(oldblock.getPredExceptions());
+
+ // replace predecessors
+ for (BasicBlock pred : lstTemp) {
+ pred.replaceSuccessor(oldblock, newblock);
+ }
+
+ // copy exception edges and extend protected ranges
+ for (BasicBlock hd : oldblock.getSuccExceptions()) {
+ newblock.addSuccessorException(hd);
+
+ ExceptionRangeCFG range = graph.getExceptionRange(hd, oldblock);
+ range.getProtectedRange().add(newblock);
+ }
+
+ // replace handler
+ for (ExceptionRangeCFG range : graph.getExceptions()) {
+ if (range.getHandler() == oldblock) {
+ range.setHandler(newblock);
+ }
+ }
+
+ newblock.addSuccessor(oldblock);
+ graph.getBlocks().addWithKey(newblock, newblock.id);
+ if (graph.getFirst() == oldblock) {
+ graph.setFirst(newblock);
+ }
+ }
+
+ private static HashSet<BasicBlock> getAllBasicBlocks(Statement stat) {
+
+ List<Statement> lst = new LinkedList<Statement>();
+ lst.add(stat);
+
+ int index = 0;
+ do {
+ Statement st = lst.get(index);
+
+ if (st.type == Statement.TYPE_BASICBLOCK) {
+ index++;
+ }
+ else {
+ lst.addAll(st.getStats());
+ lst.remove(index);
+ }
+ }
+ while (index < lst.size());
+
+ HashSet<BasicBlock> res = new HashSet<BasicBlock>();
+
+ for (Statement st : lst) {
+ res.add(((BasicBlockStatement)st).getBlock());
+ }
+
+ return res;
+ }
+
+
+ private boolean verifyFinallyEx(ControlFlowGraph graph, CatchAllStatement fstat, Record information) {
+
+ HashSet<BasicBlock> tryBlocks = getAllBasicBlocks(fstat.getFirst());
+ HashSet<BasicBlock> catchBlocks = getAllBasicBlocks(fstat.getHandler());
+
+ int finallytype = information.firstCode;
+ Map<BasicBlock, Boolean> mapLast = information.mapLast;
+
+ BasicBlock first = fstat.getHandler().getBasichead().getBlock();
+ boolean skippedFirst = false;
+
+ if (finallytype == 3) {
+ // empty finally
+ removeExceptionInstructionsEx(first, 3, finallytype);
+
+ if (mapLast.containsKey(first)) {
+ graph.getFinallyExits().add(first);
+ }
+
+ return true;
+ }
+ else {
+ if (first.getSeq().length() == 1 && finallytype > 0) {
+ BasicBlock firstsuc = first.getSuccs().get(0);
+ if (catchBlocks.contains(firstsuc)) {
+ first = firstsuc;
+ skippedFirst = true;
+ }
+ }
+ }
+
+ // identify start blocks
+ HashSet<BasicBlock> startBlocks = new HashSet<BasicBlock>();
+ for (BasicBlock block : tryBlocks) {
+ startBlocks.addAll(block.getSuccs());
+ }
+ // throw in the try body will point directly to the dummy exit
+ // so remove dummy exit
+ startBlocks.remove(graph.getLast());
+ startBlocks.removeAll(tryBlocks);
+
+ List<Area> lstAreas = new ArrayList<Area>();
+
+ for (BasicBlock start : startBlocks) {
+
+ Area arr = compareSubgraphsEx(graph, start, catchBlocks, first, finallytype, mapLast, skippedFirst);
+ if (arr == null) {
+ return false;
+ }
+
+ lstAreas.add(arr);
+ }
+
+ // try {
+ // DotExporter.toDotFile(graph, new File("c:\\Temp\\fern5.dot"), true);
+ // } catch(Exception ex){ex.printStackTrace();}
+
+ // delete areas
+ for (Area area : lstAreas) {
+ deleteArea(graph, area);
+ }
+
+ // try {
+ // DotExporter.toDotFile(graph, new File("c:\\Temp\\fern5.dot"), true);
+ // } catch(Exception ex){ex.printStackTrace();}
+
+ // INFO: empty basic blocks may remain in the graph!
+ for (Entry<BasicBlock, Boolean> entry : mapLast.entrySet()) {
+ BasicBlock last = entry.getKey();
+
+ if (entry.getValue()) {
+ removeExceptionInstructionsEx(last, 2, finallytype);
+ graph.getFinallyExits().add(last);
+ }
+ }
+
+ removeExceptionInstructionsEx(fstat.getHandler().getBasichead().getBlock(), 1, finallytype);
+
+ return true;
+ }
+
+ private static class Area {
+ private final BasicBlock start;
+ private final Set<BasicBlock> sample;
+ private final BasicBlock next;
+
+ private Area(BasicBlock start, Set<BasicBlock> sample, BasicBlock next) {
+ this.start = start;
+ this.sample = sample;
+ this.next = next;
+ }
+ }
+
+ private Area compareSubgraphsEx(ControlFlowGraph graph,
+ BasicBlock startSample,
+ HashSet<BasicBlock> catchBlocks,
+ BasicBlock startCatch,
+ int finallytype,
+ Map<BasicBlock, Boolean> mapLast,
+ boolean skippedFirst) {
+
+ class BlockStackEntry {
+ public BasicBlock blockCatch;
+ public BasicBlock blockSample;
+
+ // TODO: correct handling (merging) of multiple paths
+ public List<int[]> lstStoreVars;
+
+ public BlockStackEntry(BasicBlock blockCatch, BasicBlock blockSample, List<int[]> lstStoreVars) {
+ this.blockCatch = blockCatch;
+ this.blockSample = blockSample;
+ this.lstStoreVars = new ArrayList<int[]>(lstStoreVars);
+ }
+ }
+
+ List<BlockStackEntry> stack = new LinkedList<BlockStackEntry>();
+
+ Set<BasicBlock> setSample = new HashSet<BasicBlock>();
+
+ Map<String, BasicBlock[]> mapNext = new HashMap<String, BasicBlock[]>();
+
+ stack.add(new BlockStackEntry(startCatch, startSample, new ArrayList<int[]>()));
+
+ while (!stack.isEmpty()) {
+
+ BlockStackEntry entry = stack.remove(0);
+ BasicBlock blockCatch = entry.blockCatch;
+ BasicBlock blockSample = entry.blockSample;
+
+ boolean isFirstBlock = !skippedFirst && blockCatch == startCatch;
+ boolean isLastBlock = mapLast.containsKey(blockCatch);
+ boolean isTrueLastBlock = isLastBlock && mapLast.get(blockCatch);
+
+ if (!compareBasicBlocksEx(graph, blockCatch, blockSample, (isFirstBlock ? 1 : 0) | (isTrueLastBlock ? 2 : 0), finallytype,
+ entry.lstStoreVars)) {
+ return null;
+ }
+
+ if (blockSample.getSuccs().size() != blockCatch.getSuccs().size()) {
+ return null;
+ }
+
+ setSample.add(blockSample);
+
+ // direct successors
+ for (int i = 0; i < blockCatch.getSuccs().size(); i++) {
+ BasicBlock sucCatch = blockCatch.getSuccs().get(i);
+ BasicBlock sucSample = blockSample.getSuccs().get(i);
+
+ if (catchBlocks.contains(sucCatch) && !setSample.contains(sucSample)) {
+ stack.add(new BlockStackEntry(sucCatch, sucSample, entry.lstStoreVars));
+ }
+ }
+
+
+ // exception successors
+ if (isLastBlock && blockSample.getSeq().isEmpty()) {
+ // do nothing, blockSample will be removed anyway
+ }
+ else {
+ if (blockCatch.getSuccExceptions().size() == blockSample.getSuccExceptions().size()) {
+ for (int i = 0; i < blockCatch.getSuccExceptions().size(); i++) {
+ BasicBlock sucCatch = blockCatch.getSuccExceptions().get(i);
+ BasicBlock sucSample = blockSample.getSuccExceptions().get(i);
+
+ String excCatch = graph.getExceptionRange(sucCatch, blockCatch).getUniqueExceptionsString();
+ String excSample = graph.getExceptionRange(sucSample, blockSample).getUniqueExceptionsString();
+
+ // FIXME: compare handlers if possible
+ boolean equalexc = excCatch == null ? excSample == null : excCatch.equals(excSample);
+
+ if (equalexc) {
+ if (catchBlocks.contains(sucCatch) && !setSample.contains(sucSample)) {
+
+ List<int[]> lst = entry.lstStoreVars;
+
+ if (sucCatch.getSeq().length() > 0 && sucSample.getSeq().length() > 0) {
+ Instruction instrCatch = sucCatch.getSeq().getInstr(0);
+ Instruction instrSample = sucSample.getSeq().getInstr(0);
+
+ if (instrCatch.opcode == CodeConstants.opc_astore &&
+ instrSample.opcode == CodeConstants.opc_astore) {
+ lst = new ArrayList<int[]>(lst);
+ lst.add(new int[]{instrCatch.getOperand(0), instrSample.getOperand(0)});
+ }
+ }
+
+ stack.add(new BlockStackEntry(sucCatch, sucSample, lst));
+ }
+ }
+ else {
+ return null;
+ }
+ }
+ }
+ else {
+ return null;
+ }
+ }
+
+ if (isLastBlock) {
+ Set<BasicBlock> setSuccs = new HashSet<BasicBlock>(blockSample.getSuccs());
+ setSuccs.removeAll(setSample);
+
+ for (BlockStackEntry stackent : stack) {
+ setSuccs.remove(stackent.blockSample);
+ }
+
+ for (BasicBlock succ : setSuccs) {
+ if (graph.getLast() != succ) { // FIXME: why?
+ mapNext.put(blockSample.id + "#" + succ.id, new BasicBlock[]{blockSample, succ, isTrueLastBlock ? succ : null});
+ }
+ }
+ }
+ }
+
+ return new Area(startSample, setSample, getUniqueNext(graph, new HashSet<BasicBlock[]>(mapNext.values())));
+ }
+
+ private static BasicBlock getUniqueNext(ControlFlowGraph graph, Set<BasicBlock[]> setNext) {
+
+ // precondition: there is at most one true exit path in a finally statement
+
+ BasicBlock next = null;
+ boolean multiple = false;
+
+ for (BasicBlock[] arr : setNext) {
+
+ if (arr[2] != null) {
+ next = arr[1];
+ multiple = false;
+ break;
+ }
+ else {
+ if (next == null) {
+ next = arr[1];
+ }
+ else if (next != arr[1]) {
+ multiple = true;
+ }
+
+ if (arr[1].getPreds().size() == 1) {
+ next = arr[1];
+ }
+ }
+ }
+
+ if (multiple) { // TODO: generic solution
+ for (BasicBlock[] arr : setNext) {
+ BasicBlock block = arr[1];
+
+ if (block != next) {
+ if (InterpreterUtil.equalSets(next.getSuccs(), block.getSuccs())) {
+ InstructionSequence seqNext = next.getSeq();
+ InstructionSequence seqBlock = block.getSeq();
+
+ if (seqNext.length() == seqBlock.length()) {
+ for (int i = 0; i < seqNext.length(); i++) {
+ Instruction instrNext = seqNext.getInstr(i);
+ Instruction instrBlock = seqBlock.getInstr(i);
+
+ if (instrNext.opcode != instrBlock.opcode || instrNext.wide != instrBlock.wide
+ || instrNext.operandsCount() != instrBlock.operandsCount()) {
+ return null;
+ }
+
+ for (int j = 0; j < instrNext.getOperands().length; j++) {
+ if (instrNext.getOperand(j) != instrBlock.getOperand(j)) {
+ return null;
+ }
+ }
+ }
+ }
+ else {
+ return null;
+ }
+ }
+ else {
+ return null;
+ }
+ }
+ }
+
+ // try {
+ // DotExporter.toDotFile(graph, new File("c:\\Temp\\fern5.dot"), true);
+ // } catch(IOException ex) {
+ // ex.printStackTrace();
+ // }
+
+ for (BasicBlock[] arr : setNext) {
+ if (arr[1] != next) {
+ // FIXME: exception edge possible?
+ arr[0].removeSuccessor(arr[1]);
+ arr[0].addSuccessor(next);
+ }
+ }
+
+ DeadCodeHelper.removeDeadBlocks(graph);
+ }
+
+ return next;
+ }
+
+ private boolean compareBasicBlocksEx(ControlFlowGraph graph,
+ BasicBlock pattern,
+ BasicBlock sample,
+ int type,
+ int finallytype,
+ List<int[]> lstStoreVars) {
+
+ InstructionSequence seqPattern = pattern.getSeq();
+ InstructionSequence seqSample = sample.getSeq();
+
+ if (type != 0) {
+ seqPattern = seqPattern.clone();
+
+ if ((type & 1) > 0) { // first
+ if (finallytype > 0) {
+ seqPattern.removeInstruction(0);
+ }
+ }
+
+ if ((type & 2) > 0) { // last
+ if (finallytype == 0 || finallytype == 2) {
+ seqPattern.removeInstruction(seqPattern.length() - 1);
+ }
+
+ if (finallytype == 2) {
+ seqPattern.removeInstruction(seqPattern.length() - 1);
+ }
+ }
+ }
+
+ if (seqPattern.length() > seqSample.length()) {
+ return false;
+ }
+
+ for (int i = 0; i < seqPattern.length(); i++) {
+ Instruction instrPattern = seqPattern.getInstr(i);
+ Instruction instrSample = seqSample.getInstr(i);
+
+ // compare instructions with respect to jumps
+ if (!equalInstructions(instrPattern, instrSample, lstStoreVars)) {
+ return false;
+ }
+ }
+
+ if (seqPattern.length() < seqSample.length()) { // split in two blocks
+
+ SimpleInstructionSequence seq = new SimpleInstructionSequence();
+ for (int i = seqSample.length() - 1; i >= seqPattern.length(); i--) {
+ seq.addInstruction(0, seqSample.getInstr(i), -1);
+ seqSample.removeInstruction(i);
+ }
+
+ BasicBlock newblock = new BasicBlock(++graph.last_id);
+ newblock.setSeq(seq);
+
+ List<BasicBlock> lstTemp = new ArrayList<BasicBlock>();
+ lstTemp.addAll(sample.getSuccs());
+
+ // move successors
+ for (BasicBlock suc : lstTemp) {
+ sample.removeSuccessor(suc);
+ newblock.addSuccessor(suc);
+ }
+
+ sample.addSuccessor(newblock);
+
+ graph.getBlocks().addWithKey(newblock, newblock.id);
+
+ Set<BasicBlock> setFinallyExits = graph.getFinallyExits();
+ if (setFinallyExits.contains(sample)) {
+ setFinallyExits.remove(sample);
+ setFinallyExits.add(newblock);
+ }
+
+ // copy exception edges and extend protected ranges
+ for (int j = 0; j < sample.getSuccExceptions().size(); j++) {
+ BasicBlock hd = sample.getSuccExceptions().get(j);
+ newblock.addSuccessorException(hd);
+
+ ExceptionRangeCFG range = graph.getExceptionRange(hd, sample);
+ range.getProtectedRange().add(newblock);
+ }
+ }
+
+ return true;
+ }
+
+ public boolean equalInstructions(Instruction first, Instruction second, List<int[]> lstStoreVars) {
+ if (first.opcode != second.opcode || first.wide != second.wide
+ || first.operandsCount() != second.operandsCount()) {
+ return false;
+ }
+
+ if (first.group != CodeConstants.GROUP_JUMP && first.getOperands() != null) { // FIXME: switch comparison
+ for (int i = 0; i < first.getOperands().length; i++) {
+
+ int firstOp = first.getOperand(i);
+ int secondOp = second.getOperand(i);
+
+ if (firstOp != secondOp) {
+
+ // a-load/store instructions
+ if (first.opcode == CodeConstants.opc_aload || first.opcode == CodeConstants.opc_astore) {
+ for (int[] arr : lstStoreVars) {
+ if (arr[0] == firstOp && arr[1] == secondOp) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ private static void deleteArea(ControlFlowGraph graph, Area area) {
+
+ BasicBlock start = area.start;
+ BasicBlock next = area.next;
+
+ if (start == next) {
+ return;
+ }
+
+ if (next == null) {
+ // dummy exit block
+ next = graph.getLast();
+ }
+
+ // collect common exception ranges of predecessors and successors
+ Set<BasicBlock> setCommonExceptionHandlers = new HashSet<BasicBlock>(next.getSuccExceptions());
+ for (BasicBlock pred : start.getPreds()) {
+ setCommonExceptionHandlers.retainAll(pred.getSuccExceptions());
+ }
+
+ boolean is_outside_range = false;
+
+ Set<BasicBlock> setPredecessors = new HashSet<BasicBlock>(start.getPreds());
+
+ // replace start with next
+ for (BasicBlock pred : setPredecessors) {
+ pred.replaceSuccessor(start, next);
+ }
+
+ Set<BasicBlock> setBlocks = area.sample;
+
+ Set<ExceptionRangeCFG> setCommonRemovedExceptionRanges = null;
+
+ // remove all the blocks inbetween
+ for (BasicBlock block : setBlocks) {
+
+ // artificial basic blocks (those resulted from splitting)
+ // can belong to more than one area
+ if (graph.getBlocks().containsKey(block.id)) {
+
+ if (!block.getSuccExceptions().containsAll(setCommonExceptionHandlers)) {
+ is_outside_range = true;
+ }
+
+ Set<ExceptionRangeCFG> setRemovedExceptionRanges = new HashSet<ExceptionRangeCFG>();
+ for (BasicBlock handler : block.getSuccExceptions()) {
+ setRemovedExceptionRanges.add(graph.getExceptionRange(handler, block));
+ }
+
+ if (setCommonRemovedExceptionRanges == null) {
+ setCommonRemovedExceptionRanges = setRemovedExceptionRanges;
+ }
+ else {
+ setCommonRemovedExceptionRanges.retainAll(setRemovedExceptionRanges);
+ }
+
+ // shift extern edges on splitted blocks
+ if (block.getSeq().isEmpty() && block.getSuccs().size() == 1) {
+ BasicBlock succs = block.getSuccs().get(0);
+ for (BasicBlock pred : new ArrayList<BasicBlock>(block.getPreds())) {
+ if (!setBlocks.contains(pred)) {
+ pred.replaceSuccessor(block, succs);
+ }
+ }
+
+ if (graph.getFirst() == block) {
+ graph.setFirst(succs);
+ }
+ }
+
+ graph.removeBlock(block);
+ }
+ }
+
+ if (is_outside_range) {
+
+ // new empty block
+ BasicBlock emptyblock = new BasicBlock(++graph.last_id);
+ emptyblock.setSeq(new SimpleInstructionSequence());
+ graph.getBlocks().addWithKey(emptyblock, emptyblock.id);
+
+ // add to ranges if necessary
+ if (setCommonRemovedExceptionRanges != null) {
+ for (ExceptionRangeCFG range : setCommonRemovedExceptionRanges) {
+ emptyblock.addSuccessorException(range.getHandler());
+ range.getProtectedRange().add(emptyblock);
+ }
+ }
+
+ // insert between predecessors and next
+ emptyblock.addSuccessor(next);
+ for (BasicBlock pred : setPredecessors) {
+ pred.replaceSuccessor(next, emptyblock);
+ }
+ }
+ }
+
+ private static void removeExceptionInstructionsEx(BasicBlock block, int blocktype, int finallytype) {
+
+ InstructionSequence seq = block.getSeq();
+
+ if (finallytype == 3) { // empty finally handler
+ for (int i = seq.length() - 1; i >= 0; i--) {
+ seq.removeInstruction(i);
+ }
+ }
+ else {
+ if ((blocktype & 1) > 0) { // first
+ if (finallytype == 2 || finallytype == 1) { // astore or pop
+ seq.removeInstruction(0);
+ }
+ }
+
+ if ((blocktype & 2) > 0) { // last
+ if (finallytype == 2 || finallytype == 0) {
+ seq.removeInstruction(seq.length() - 1);
+ }
+
+ if (finallytype == 2) { // astore
+ seq.removeInstruction(seq.length() - 1);
+ }
+ }
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/IdeaNotNullHelper.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/IdeaNotNullHelper.java
new file mode 100644
index 000000000000..0f5141a7aa52
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/IdeaNotNullHelper.java
@@ -0,0 +1,336 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.IfStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.SequenceStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+import org.jetbrains.java.decompiler.struct.StructMethod;
+import org.jetbrains.java.decompiler.struct.attr.StructAnnotationAttribute;
+import org.jetbrains.java.decompiler.struct.attr.StructAnnotationParameterAttribute;
+import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute;
+import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
+import org.jetbrains.java.decompiler.util.VBStyleCollection;
+
+import java.util.List;
+
+public class IdeaNotNullHelper {
+
+
+ public static boolean removeHardcodedChecks(Statement root, StructMethod mt) {
+
+ boolean checks_removed = false;
+
+ // parameter @NotNull annotations
+ while (findAndRemoveParameterCheck(root, mt)) { // iterate until nothing found. Each invocation removes one parameter check.
+ checks_removed = true;
+ }
+
+ // method @NotNull annotation
+ while (findAndRemoveReturnCheck(root, mt)) { // iterate until nothing found. Each invocation handles one method exit check.
+ checks_removed = true;
+ }
+
+ return checks_removed;
+ }
+
+ private static boolean findAndRemoveParameterCheck(Statement stat, StructMethod mt) {
+
+ Statement st = stat.getFirst();
+ while (st.type == Statement.TYPE_SEQUENCE) {
+ st = st.getFirst();
+ }
+
+ if (st.type == Statement.TYPE_IF) {
+
+ IfStatement ifstat = (IfStatement)st;
+ Statement ifbranch = ifstat.getIfstat();
+
+ Exprent if_condition = ifstat.getHeadexprent().getCondition();
+
+ boolean is_notnull_check = false;
+
+ // TODO: FUNCTION_NE also possible if reversed order (in theory)
+ if (ifbranch != null &&
+ if_condition.type == Exprent.EXPRENT_FUNCTION &&
+ ((FunctionExprent)if_condition).getFunctype() == FunctionExprent.FUNCTION_EQ &&
+ ifbranch.type == Statement.TYPE_BASICBLOCK &&
+ ifbranch.getExprents().size() == 1 &&
+ ifbranch.getExprents().get(0).type == Exprent.EXPRENT_EXIT) {
+
+ FunctionExprent func = (FunctionExprent)if_condition;
+ Exprent first_param = func.getLstOperands().get(0);
+ Exprent second_param = func.getLstOperands().get(1);
+
+ if (second_param.type == Exprent.EXPRENT_CONST &&
+ second_param.getExprType().type == CodeConstants.TYPE_NULL) { // TODO: reversed parameter order
+ if (first_param.type == Exprent.EXPRENT_VAR) {
+ VarExprent var = (VarExprent)first_param;
+
+ boolean thisvar = !mt.hasModifier(CodeConstants.ACC_STATIC);
+
+ MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
+ VBStyleCollection<StructGeneralAttribute, String> attributes = mt.getAttributes();
+
+ // parameter annotations
+ StructAnnotationParameterAttribute param_annotations = (StructAnnotationParameterAttribute)attributes
+ .getWithKey(StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS);
+ if (param_annotations != null) {
+
+ List<List<AnnotationExprent>> param_annotations_lists = param_annotations.getParamAnnotations();
+ int method_param_number = md.params.length;
+
+ int index = thisvar ? 1 : 0;
+ for (int i = 0; i < method_param_number; i++) {
+
+ if (index == var.getIndex()) {
+ if (param_annotations_lists.size() >= method_param_number - i) {
+ int shift = method_param_number -
+ param_annotations_lists
+ .size(); // NOTE: workaround for compiler bug, count annotations starting with the last parameter
+
+ List<AnnotationExprent> annotations = param_annotations_lists.get(i - shift);
+
+ for (AnnotationExprent ann : annotations) {
+ if (ann.getClassname().equals("org/jetbrains/annotations/NotNull")) {
+ is_notnull_check = true;
+ }
+ }
+ }
+
+ break;
+ }
+
+ index += md.params[i].stack_size;
+ }
+ }
+ }
+ }
+ }
+
+ if (!is_notnull_check) {
+ return false;
+ }
+
+ removeParameterCheck(stat, mt);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ private static void removeParameterCheck(Statement stat, StructMethod mt) {
+
+ Statement st = stat.getFirst();
+ while (st.type == Statement.TYPE_SEQUENCE) {
+ st = st.getFirst();
+ }
+
+ IfStatement ifstat = (IfStatement)st;
+
+ if (ifstat.getElsestat() == null) { // if
+ // TODO:
+ }
+ else { // if - else
+
+ StatEdge ifedge = ifstat.getIfEdge();
+ StatEdge elseedge = ifstat.getElseEdge();
+
+ Statement ifbranch = ifstat.getIfstat();
+ Statement elsebranch = ifstat.getElsestat();
+
+ ifstat.getFirst().removeSuccessor(ifedge);
+ ifstat.getFirst().removeSuccessor(elseedge);
+
+ ifstat.getStats().removeWithKey(ifbranch.id);
+ ifstat.getStats().removeWithKey(elsebranch.id);
+
+ if (!ifbranch.getAllSuccessorEdges().isEmpty()) {
+ ifbranch.removeSuccessor(ifbranch.getAllSuccessorEdges().get(0));
+ }
+
+ ifstat.getParent().replaceStatement(ifstat, elsebranch);
+ ifstat.getParent().setAllParent();
+ }
+ }
+
+ private static boolean findAndRemoveReturnCheck(Statement stat, StructMethod mt) {
+
+ VBStyleCollection<StructGeneralAttribute, String> attributes = mt.getAttributes();
+
+ boolean is_notnull_check = false;
+
+ // method annotation, refers to the return value
+ StructAnnotationAttribute attr =
+ (StructAnnotationAttribute)attributes.getWithKey(StructGeneralAttribute.ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS);
+ if (attr != null) {
+ List<AnnotationExprent> annotations = attr.getAnnotations();
+
+ for (AnnotationExprent ann : annotations) {
+ if (ann.getClassname().equals("org/jetbrains/annotations/NotNull")) {
+ is_notnull_check = true;
+ }
+ }
+ }
+
+ if (is_notnull_check) {
+ return removeReturnCheck(stat, mt);
+ }
+
+ return false;
+ }
+
+
+ private static boolean removeReturnCheck(Statement stat, StructMethod mt) {
+
+ Statement parent = stat.getParent();
+
+ if (parent != null && parent.type == Statement.TYPE_IF && stat.type == Statement.TYPE_BASICBLOCK && stat.getExprents().size() == 1) {
+ Exprent exprent = stat.getExprents().get(0);
+ if (exprent.type == Exprent.EXPRENT_EXIT) {
+ ExitExprent exit_exprent = (ExitExprent)exprent;
+ if (exit_exprent.getExittype() == ExitExprent.EXIT_RETURN) {
+ Exprent exprent_value = exit_exprent.getValue();
+ //if(exprent_value.type == Exprent.EXPRENT_VAR) {
+ // VarExprent var_value = (VarExprent)exprent_value;
+
+ IfStatement ifparent = (IfStatement)parent;
+ Exprent if_condition = ifparent.getHeadexprent().getCondition();
+
+ if (ifparent.getElsestat() == stat && if_condition.type == Exprent.EXPRENT_FUNCTION &&
+ ((FunctionExprent)if_condition).getFunctype() == FunctionExprent.FUNCTION_EQ) { // TODO: reversed order possible (in theory)
+
+ FunctionExprent func = (FunctionExprent)if_condition;
+ Exprent first_param = func.getLstOperands().get(0);
+ Exprent second_param = func.getLstOperands().get(1);
+
+ StatEdge ifedge = ifparent.getIfEdge();
+ StatEdge elseedge = ifparent.getElseEdge();
+
+ Statement ifbranch = ifparent.getIfstat();
+ Statement elsebranch = ifparent.getElsestat();
+
+ if (second_param.type == Exprent.EXPRENT_CONST &&
+ second_param.getExprType().type == CodeConstants.TYPE_NULL) { // TODO: reversed parameter order
+ //if(first_param.type == Exprent.EXPRENT_VAR && ((VarExprent)first_param).getIndex() == var_value.getIndex()) {
+ if (first_param.equals(exprent_value)) { // TODO: check for absence of side effects like method invocations etc.
+ if (ifbranch.type == Statement.TYPE_BASICBLOCK &&
+ ifbranch.getExprents().size() == 1 &&
+ // TODO: special check for IllegalStateException
+ ifbranch.getExprents().get(0).type == Exprent.EXPRENT_EXIT) {
+
+ ifparent.getFirst().removeSuccessor(ifedge);
+ ifparent.getFirst().removeSuccessor(elseedge);
+
+ ifparent.getStats().removeWithKey(ifbranch.id);
+ ifparent.getStats().removeWithKey(elsebranch.id);
+
+ if (!ifbranch.getAllSuccessorEdges().isEmpty()) {
+ ifbranch.removeSuccessor(ifbranch.getAllSuccessorEdges().get(0));
+ }
+
+ if (!ifparent.getFirst().getExprents().isEmpty()) {
+ elsebranch.getExprents().addAll(0, ifparent.getFirst().getExprents());
+ }
+
+ ifparent.getParent().replaceStatement(ifparent, elsebranch);
+ ifparent.getParent().setAllParent();
+
+ return true;
+ }
+ }
+ }
+ }
+ //}
+ }
+ }
+ }
+ else if (parent != null &&
+ parent.type == Statement.TYPE_SEQUENCE &&
+ stat.type == Statement.TYPE_BASICBLOCK &&
+ stat.getExprents().size() == 1) {
+ Exprent exprent = stat.getExprents().get(0);
+ if (exprent.type == Exprent.EXPRENT_EXIT) {
+ ExitExprent exit_exprent = (ExitExprent)exprent;
+ if (exit_exprent.getExittype() == ExitExprent.EXIT_RETURN) {
+ Exprent exprent_value = exit_exprent.getValue();
+
+ SequenceStatement sequence = (SequenceStatement)parent;
+ int sequence_stats_number = sequence.getStats().size();
+
+ if (sequence_stats_number > 1 &&
+ sequence.getStats().getLast() == stat &&
+ sequence.getStats().get(sequence_stats_number - 2).type == Statement.TYPE_IF) {
+
+ IfStatement ifstat = (IfStatement)sequence.getStats().get(sequence_stats_number - 2);
+ Exprent if_condition = ifstat.getHeadexprent().getCondition();
+
+ if (ifstat.iftype == IfStatement.IFTYPE_IF && if_condition.type == Exprent.EXPRENT_FUNCTION &&
+ ((FunctionExprent)if_condition).getFunctype() == FunctionExprent.FUNCTION_EQ) { // TODO: reversed order possible (in theory)
+
+ FunctionExprent func = (FunctionExprent)if_condition;
+ Exprent first_param = func.getLstOperands().get(0);
+ Exprent second_param = func.getLstOperands().get(1);
+
+ Statement ifbranch = ifstat.getIfstat();
+
+ if (second_param.type == Exprent.EXPRENT_CONST &&
+ second_param.getExprType().type == CodeConstants.TYPE_NULL) { // TODO: reversed parameter order
+ if (first_param.equals(exprent_value)) { // TODO: check for absence of side effects like method invocations etc.
+ if (ifbranch.type == Statement.TYPE_BASICBLOCK &&
+ ifbranch.getExprents().size() == 1 &&
+ // TODO: special check for IllegalStateException
+ ifbranch.getExprents().get(0).type == Exprent.EXPRENT_EXIT) {
+
+ ifstat.removeSuccessor(ifstat.getAllSuccessorEdges().get(0)); // remove 'else' edge
+
+ if (!ifstat.getFirst().getExprents().isEmpty()) {
+ stat.getExprents().addAll(0, ifstat.getFirst().getExprents());
+ }
+
+ for (StatEdge edge : ifstat.getAllPredecessorEdges()) {
+
+ ifstat.removePredecessor(edge);
+ edge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, edge, stat);
+ stat.addPredecessor(edge);
+ }
+
+ sequence.getStats().removeWithKey(ifstat.id);
+ sequence.setFirst(sequence.getStats().get(0));
+
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ for (Statement st : stat.getStats()) {
+ if (removeReturnCheck(st, mt)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/IfHelper.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/IfHelper.java
new file mode 100644
index 000000000000..b1a955cfd528
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/IfHelper.java
@@ -0,0 +1,750 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler;
+
+import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.FunctionExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.IfExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.IfStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.SequenceStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+
+
+public class IfHelper {
+
+
+ public static boolean mergeAllIfs(RootStatement root) {
+
+ boolean res = mergeAllIfsRec(root, new HashSet<Integer>());
+
+ if (res) {
+ SequenceHelper.condenseSequences(root);
+ }
+
+ return res;
+ }
+
+
+ private static boolean mergeAllIfsRec(Statement stat, HashSet<Integer> setReorderedIfs) {
+
+ boolean res = false;
+
+ if (stat.getExprents() == null) {
+
+ while (true) {
+
+ boolean changed = false;
+
+ for (Statement st : stat.getStats()) {
+
+ res |= mergeAllIfsRec(st, setReorderedIfs);
+
+ // collapse composed if's
+ if (changed = mergeIfs(st, setReorderedIfs)) {
+ break;
+ }
+ }
+
+ res |= changed;
+
+ if (!changed) {
+ break;
+ }
+ }
+ }
+
+ return res;
+ }
+
+
+ public static boolean mergeIfs(Statement statement, HashSet<Integer> setReorderedIfs) {
+
+ if (statement.type != Statement.TYPE_IF && statement.type != Statement.TYPE_SEQUENCE) {
+ return false;
+ }
+
+ boolean res = false;
+
+ while (true) {
+
+ boolean updated = false;
+
+ List<Statement> lst = new ArrayList<Statement>();
+ if (statement.type == Statement.TYPE_IF) {
+ lst.add(statement);
+ }
+ else {
+ lst.addAll(statement.getStats());
+ }
+
+ boolean stsingle = (lst.size() == 1);
+
+ for (Statement stat : lst) {
+
+ if (stat.type == Statement.TYPE_IF) {
+ IfNode rtnode = buildGraph((IfStatement)stat, stsingle);
+
+ if (rtnode == null) {
+ continue;
+ }
+
+ if (updated = collapseIfIf(rtnode)) {
+ break;
+ }
+
+ if (!setReorderedIfs.contains(stat.id)) {
+
+ if (updated = collapseIfElse(rtnode)) {
+ break;
+ }
+
+ if (updated = collapseElse(rtnode)) {
+ break;
+ }
+ }
+
+ if (updated = reorderIf((IfStatement)stat)) {
+ setReorderedIfs.add(stat.id);
+ break;
+ }
+ }
+ }
+
+ if (!updated) {
+ break;
+ }
+
+ res |= updated;
+ }
+
+ return res;
+ }
+
+ private static boolean collapseIfIf(IfNode rtnode) {
+
+ if (rtnode.edgetypes.get(0) == 0) {
+ IfNode ifbranch = rtnode.succs.get(0);
+ if (ifbranch.succs.size() == 2) {
+
+ // if-if branch
+ if (ifbranch.succs.get(1).value == rtnode.succs.get(1).value) {
+
+ IfStatement ifparent = (IfStatement)rtnode.value;
+ IfStatement ifchild = (IfStatement)ifbranch.value;
+ Statement ifinner = ifbranch.succs.get(0).value;
+
+ if (ifchild.getFirst().getExprents().isEmpty()) {
+
+ ifparent.getFirst().removeSuccessor(ifparent.getIfEdge());
+ ifchild.removeSuccessor(ifchild.getAllSuccessorEdges().get(0));
+ ifparent.getStats().removeWithKey(ifchild.id);
+
+ if (ifbranch.edgetypes.get(0).intValue() == 1) { // target null
+
+ ifparent.setIfstat(null);
+
+ StatEdge ifedge = ifchild.getIfEdge();
+
+ ifchild.getFirst().removeSuccessor(ifedge);
+ ifedge.setSource(ifparent.getFirst());
+
+ if (ifedge.closure == ifchild) {
+ ifedge.closure = null;
+ }
+ ifparent.getFirst().addSuccessor(ifedge);
+
+ ifparent.setIfEdge(ifedge);
+ }
+ else {
+ ifchild.getFirst().removeSuccessor(ifchild.getIfEdge());
+
+ StatEdge ifedge = new StatEdge(StatEdge.TYPE_REGULAR, ifparent.getFirst(), ifinner);
+ ifparent.getFirst().addSuccessor(ifedge);
+ ifparent.setIfEdge(ifedge);
+ ifparent.setIfstat(ifinner);
+
+ ifparent.getStats().addWithKey(ifinner, ifinner.id);
+ ifinner.setParent(ifparent);
+
+ if (!ifinner.getAllSuccessorEdges().isEmpty()) {
+ StatEdge edge = ifinner.getAllSuccessorEdges().get(0);
+ if (edge.closure == ifchild) {
+ edge.closure = null;
+ }
+ }
+ }
+
+ // merge if conditions
+ IfExprent statexpr = ifparent.getHeadexprent();
+
+ List<Exprent> lstOperands = new ArrayList<Exprent>();
+ lstOperands.add(statexpr.getCondition());
+ lstOperands.add(ifchild.getHeadexprent().getCondition());
+
+ statexpr.setCondition(new FunctionExprent(FunctionExprent.FUNCTION_CADD, lstOperands));
+
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private static boolean collapseIfElse(IfNode rtnode) {
+
+ if (rtnode.edgetypes.get(0).intValue() == 0) {
+ IfNode ifbranch = rtnode.succs.get(0);
+ if (ifbranch.succs.size() == 2) {
+
+ // if-else branch
+ if (ifbranch.succs.get(0).value == rtnode.succs.get(1).value) {
+
+ IfStatement ifparent = (IfStatement)rtnode.value;
+ IfStatement ifchild = (IfStatement)ifbranch.value;
+
+ if (ifchild.getFirst().getExprents().isEmpty()) {
+
+ ifparent.getFirst().removeSuccessor(ifparent.getIfEdge());
+ ifchild.getFirst().removeSuccessor(ifchild.getIfEdge());
+ ifparent.getStats().removeWithKey(ifchild.id);
+
+ if (ifbranch.edgetypes.get(1).intValue() == 1 &&
+ ifbranch.edgetypes.get(0).intValue() == 1) { // target null
+
+ ifparent.setIfstat(null);
+
+ StatEdge ifedge = ifchild.getAllSuccessorEdges().get(0);
+
+ ifchild.removeSuccessor(ifedge);
+ ifedge.setSource(ifparent.getFirst());
+ ifparent.getFirst().addSuccessor(ifedge);
+
+ ifparent.setIfEdge(ifedge);
+ }
+ else {
+ throw new RuntimeException("inconsistent if structure!");
+ }
+
+ // merge if conditions
+ IfExprent statexpr = ifparent.getHeadexprent();
+
+ List<Exprent> lstOperands = new ArrayList<Exprent>();
+ lstOperands.add(statexpr.getCondition());
+ lstOperands.add(new FunctionExprent(FunctionExprent.FUNCTION_BOOLNOT,
+ Arrays.asList(new Exprent[]{ifchild.getHeadexprent().getCondition()})));
+ statexpr.setCondition(new FunctionExprent(FunctionExprent.FUNCTION_CADD, lstOperands));
+
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+
+ private static boolean collapseElse(IfNode rtnode) {
+
+ if (rtnode.edgetypes.get(1).intValue() == 0) {
+ IfNode elsebranch = rtnode.succs.get(1);
+ if (elsebranch.succs.size() == 2) {
+
+ // else-if or else-else branch
+ int path = elsebranch.succs.get(1).value == rtnode.succs.get(0).value ? 2 :
+ (elsebranch.succs.get(0).value == rtnode.succs.get(0).value ? 1 : 0);
+
+ if (path > 0) {
+
+ IfStatement firstif = (IfStatement)rtnode.value;
+ IfStatement secondif = (IfStatement)elsebranch.value;
+ Statement parent = firstif.getParent();
+
+ if (secondif.getFirst().getExprents().isEmpty()) {
+
+ firstif.getFirst().removeSuccessor(firstif.getIfEdge());
+
+ // remove first if
+ firstif.removeAllSuccessors(secondif);
+
+ for (StatEdge edge : firstif.getAllPredecessorEdges()) {
+ if (!firstif.containsStatementStrict(edge.getSource())) {
+ firstif.removePredecessor(edge);
+ edge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, edge, secondif);
+ secondif.addPredecessor(edge);
+ }
+ }
+
+ parent.getStats().removeWithKey(firstif.id);
+ if (parent.getFirst() == firstif) {
+ parent.setFirst(secondif);
+ }
+
+ // merge if conditions
+ IfExprent statexpr = secondif.getHeadexprent();
+
+ List<Exprent> lstOperands = new ArrayList<Exprent>();
+ lstOperands.add(firstif.getHeadexprent().getCondition());
+
+ if (path == 2) {
+ lstOperands.set(0, new FunctionExprent(FunctionExprent.FUNCTION_BOOLNOT,
+ Arrays.asList(new Exprent[]{lstOperands.get(0)})));
+ }
+
+ lstOperands.add(statexpr.getCondition());
+
+ statexpr
+ .setCondition(new FunctionExprent(path == 1 ? FunctionExprent.FUNCTION_COR : FunctionExprent.FUNCTION_CADD, lstOperands));
+
+ if (secondif.getFirst().getExprents().isEmpty() &&
+ !firstif.getFirst().getExprents().isEmpty()) {
+
+ secondif.replaceStatement(secondif.getFirst(), firstif.getFirst());
+ }
+
+ return true;
+ }
+ }
+ }
+ else if (elsebranch.succs.size() == 1) {
+
+ if (elsebranch.succs.get(0).value == rtnode.succs.get(0).value) {
+
+ IfStatement firstif = (IfStatement)rtnode.value;
+ Statement second = elsebranch.value;
+
+ firstif.removeAllSuccessors(second);
+
+ for (StatEdge edge : second.getAllSuccessorEdges()) {
+ second.removeSuccessor(edge);
+ edge.setSource(firstif);
+ firstif.addSuccessor(edge);
+ }
+
+ StatEdge ifedge = firstif.getIfEdge();
+ firstif.getFirst().removeSuccessor(ifedge);
+
+ second.addSuccessor(new StatEdge(ifedge.getType(), second, ifedge.getDestination(), ifedge.closure));
+
+ StatEdge newifedge = new StatEdge(StatEdge.TYPE_REGULAR, firstif.getFirst(), second);
+ firstif.getFirst().addSuccessor(newifedge);
+ firstif.setIfstat(second);
+
+ firstif.getStats().addWithKey(second, second.id);
+ second.setParent(firstif);
+
+ firstif.getParent().getStats().removeWithKey(second.id);
+
+ // negate the if condition
+ IfExprent statexpr = firstif.getHeadexprent();
+ statexpr
+ .setCondition(new FunctionExprent(FunctionExprent.FUNCTION_BOOLNOT, Arrays.asList(new Exprent[]{statexpr.getCondition()})));
+
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+
+ private static IfNode buildGraph(IfStatement stat, boolean stsingle) {
+
+ if (stat.iftype == IfStatement.IFTYPE_IFELSE) {
+ return null;
+ }
+
+ IfNode res = new IfNode(stat);
+
+ // if branch
+ Statement ifchild = stat.getIfstat();
+ if (ifchild == null) {
+ StatEdge edge = stat.getIfEdge();
+ res.addChild(new IfNode(edge.getDestination()), 1);
+ }
+ else {
+ IfNode ifnode = new IfNode(ifchild);
+ res.addChild(ifnode, 0);
+ if (ifchild.type == Statement.TYPE_IF && ((IfStatement)ifchild).iftype == IfStatement.IFTYPE_IF) {
+ IfStatement stat2 = (IfStatement)ifchild;
+ Statement ifchild2 = stat2.getIfstat();
+ if (ifchild2 == null) {
+ StatEdge edge = stat2.getIfEdge();
+ ifnode.addChild(new IfNode(edge.getDestination()), 1);
+ }
+ else {
+ ifnode.addChild(new IfNode(ifchild2), 0);
+ }
+ }
+
+ if (!ifchild.getAllSuccessorEdges().isEmpty()) {
+ ifnode.addChild(new IfNode(ifchild.getAllSuccessorEdges().get(0).getDestination()), 1);
+ }
+ }
+
+ // else branch
+ StatEdge edge = stat.getAllSuccessorEdges().get(0);
+ Statement elsechild = edge.getDestination();
+ IfNode elsenode = new IfNode(elsechild);
+
+ if (stsingle || edge.getType() != StatEdge.TYPE_REGULAR) {
+ res.addChild(elsenode, 1);
+ }
+ else {
+ res.addChild(elsenode, 0);
+ if (elsechild.type == Statement.TYPE_IF && ((IfStatement)elsechild).iftype == IfStatement.IFTYPE_IF) {
+ IfStatement stat2 = (IfStatement)elsechild;
+ Statement ifchild2 = stat2.getIfstat();
+ if (ifchild2 == null) {
+ elsenode.addChild(new IfNode(stat2.getIfEdge().getDestination()), 1);
+ }
+ else {
+ elsenode.addChild(new IfNode(ifchild2), 0);
+ }
+ }
+
+ if (!elsechild.getAllSuccessorEdges().isEmpty()) {
+ elsenode.addChild(new IfNode(elsechild.getAllSuccessorEdges().get(0).getDestination()), 1);
+ }
+ }
+
+ return res;
+ }
+
+
+ // FIXME: rewrite the entire method!!! keep in mind finally exits!!
+ private static boolean reorderIf(IfStatement ifstat) {
+
+ if (ifstat.iftype == IfStatement.IFTYPE_IFELSE) {
+ return false;
+ }
+
+ boolean ifdirect = false, elsedirect = false;
+ boolean noifstat = false, noelsestat = false;
+ boolean ifdirectpath = false, elsedirectpath = false;
+
+ Statement parent = ifstat.getParent();
+ Statement from = parent.type == Statement.TYPE_SEQUENCE ? parent : ifstat;
+
+ Statement next = getNextStatement(from);
+
+ if (ifstat.getIfstat() == null) {
+ noifstat = true;
+
+ if (ifstat.getIfEdge().getType() == StatEdge.TYPE_FINALLYEXIT) {
+ ifdirect = true;
+ }
+ else {
+ ifdirect = MergeHelper.isDirectPath(from, ifstat.getIfEdge().getDestination());
+ }
+ }
+ else {
+ List<StatEdge> lstSuccs = ifstat.getIfstat().getAllSuccessorEdges();
+ if (!lstSuccs.isEmpty() && lstSuccs.get(0).getType() == StatEdge.TYPE_FINALLYEXIT) {
+ ifdirect = true;
+ }
+ else {
+ ifdirect = hasDirectEndEdge(ifstat.getIfstat(), from);
+ }
+ }
+
+ Statement last = parent.type == Statement.TYPE_SEQUENCE ? parent.getStats().getLast() : ifstat;
+ noelsestat = (last == ifstat);
+
+ if (!last.getAllSuccessorEdges().isEmpty() && last.getAllSuccessorEdges().get(0).getType() == StatEdge.TYPE_FINALLYEXIT) {
+ elsedirect = true;
+ }
+ else {
+ elsedirect = hasDirectEndEdge(last, from);
+ }
+
+ if (!noelsestat && existsPath(ifstat, ifstat.getAllSuccessorEdges().get(0).getDestination())) {
+ return false;
+ }
+
+ if (!ifdirect && !noifstat) {
+ ifdirectpath = existsPath(ifstat, next);
+ }
+
+ if (!elsedirect && !noelsestat) {
+ SequenceStatement sequence = (SequenceStatement)parent;
+
+ for (int i = sequence.getStats().size() - 1; i >= 0; i--) {
+ Statement sttemp = sequence.getStats().get(i);
+ if (sttemp == ifstat) {
+ break;
+ }
+ else {
+ if (elsedirectpath = existsPath(sttemp, next)) {
+ break;
+ }
+ }
+ }
+ }
+
+ if ((ifdirect || ifdirectpath) && (elsedirect || elsedirectpath) && !noifstat && !noelsestat) { // if - then - else
+
+ SequenceStatement sequence = (SequenceStatement)parent;
+
+ // build and cut the new else statement
+ List<Statement> lst = new ArrayList<Statement>();
+ for (int i = sequence.getStats().size() - 1; i >= 0; i--) {
+ Statement sttemp = sequence.getStats().get(i);
+ if (sttemp == ifstat) {
+ break;
+ }
+ else {
+ lst.add(0, sttemp);
+ }
+ }
+
+ Statement stelse;
+ if (lst.size() == 1) {
+ stelse = lst.get(0);
+ }
+ else {
+ stelse = new SequenceStatement(lst);
+ stelse.setAllParent();
+ }
+
+ ifstat.removeSuccessor(ifstat.getAllSuccessorEdges().get(0));
+ for (Statement st : lst) {
+ sequence.getStats().removeWithKey(st.id);
+ }
+
+ StatEdge elseedge = new StatEdge(StatEdge.TYPE_REGULAR, ifstat.getFirst(), stelse);
+ ifstat.getFirst().addSuccessor(elseedge);
+ ifstat.setElsestat(stelse);
+ ifstat.setElseEdge(elseedge);
+
+ ifstat.getStats().addWithKey(stelse, stelse.id);
+ stelse.setParent(ifstat);
+
+ // if(next.type != Statement.TYPE_DUMMYEXIT && (ifdirect || elsedirect)) {
+ // StatEdge breakedge = new StatEdge(StatEdge.TYPE_BREAK, ifstat, next);
+ // sequence.addLabeledEdge(breakedge);
+ // ifstat.addSuccessor(breakedge);
+ // }
+
+ ifstat.iftype = IfStatement.IFTYPE_IFELSE;
+ }
+ else if (ifdirect && (!elsedirect || (noifstat && !noelsestat))) { // if - then
+
+ // negate the if condition
+ IfExprent statexpr = ifstat.getHeadexprent();
+ statexpr.setCondition(new FunctionExprent(FunctionExprent.FUNCTION_BOOLNOT, Arrays.asList(new Exprent[]{statexpr.getCondition()})));
+
+ if (noelsestat) {
+ StatEdge ifedge = ifstat.getIfEdge();
+ StatEdge elseedge = ifstat.getAllSuccessorEdges().get(0);
+
+ if (noifstat) {
+ ifstat.getFirst().removeSuccessor(ifedge);
+ ifstat.removeSuccessor(elseedge);
+
+ ifedge.setSource(ifstat);
+ elseedge.setSource(ifstat.getFirst());
+
+ ifstat.addSuccessor(ifedge);
+ ifstat.getFirst().addSuccessor(elseedge);
+
+ ifstat.setIfEdge(elseedge);
+ }
+ else {
+ Statement ifbranch = ifstat.getIfstat();
+ SequenceStatement newseq = new SequenceStatement(Arrays.asList(ifstat, ifbranch));
+
+ ifstat.getFirst().removeSuccessor(ifedge);
+ ifstat.getStats().removeWithKey(ifbranch.id);
+ ifstat.setIfstat(null);
+
+ ifstat.removeSuccessor(elseedge);
+ elseedge.setSource(ifstat.getFirst());
+ ifstat.getFirst().addSuccessor(elseedge);
+
+ ifstat.setIfEdge(elseedge);
+
+ ifstat.getParent().replaceStatement(ifstat, newseq);
+ newseq.setAllParent();
+
+ ifstat.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, ifstat, ifbranch));
+ }
+ }
+ else {
+
+ SequenceStatement sequence = (SequenceStatement)parent;
+
+ // build and cut the new else statement
+ List<Statement> lst = new ArrayList<Statement>();
+ for (int i = sequence.getStats().size() - 1; i >= 0; i--) {
+ Statement sttemp = sequence.getStats().get(i);
+ if (sttemp == ifstat) {
+ break;
+ }
+ else {
+ lst.add(0, sttemp);
+ }
+ }
+
+ Statement stelse;
+ if (lst.size() == 1) {
+ stelse = lst.get(0);
+ }
+ else {
+ stelse = new SequenceStatement(lst);
+ stelse.setAllParent();
+ }
+
+ ifstat.removeSuccessor(ifstat.getAllSuccessorEdges().get(0));
+ for (Statement st : lst) {
+ sequence.getStats().removeWithKey(st.id);
+ }
+
+ if (noifstat) {
+ StatEdge ifedge = ifstat.getIfEdge();
+
+ ifstat.getFirst().removeSuccessor(ifedge);
+ ifedge.setSource(ifstat);
+ ifstat.addSuccessor(ifedge);
+ }
+ else {
+ Statement ifbranch = ifstat.getIfstat();
+
+ ifstat.getFirst().removeSuccessor(ifstat.getIfEdge());
+ ifstat.getStats().removeWithKey(ifbranch.id);
+
+ ifstat.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, ifstat, ifbranch));
+
+ sequence.getStats().addWithKey(ifbranch, ifbranch.id);
+ ifbranch.setParent(sequence);
+ }
+
+ StatEdge newifedge = new StatEdge(StatEdge.TYPE_REGULAR, ifstat.getFirst(), stelse);
+ ifstat.getFirst().addSuccessor(newifedge);
+ ifstat.setIfstat(stelse);
+ ifstat.setIfEdge(newifedge);
+
+ ifstat.getStats().addWithKey(stelse, stelse.id);
+ stelse.setParent(ifstat);
+ }
+ }
+ else {
+ return false;
+ }
+
+ return true;
+ }
+
+ private static boolean hasDirectEndEdge(Statement stat, Statement from) {
+
+ for (StatEdge edge : stat.getAllSuccessorEdges()) {
+ if (MergeHelper.isDirectPath(from, edge.getDestination())) {
+ return true;
+ }
+ }
+
+ if (stat.getExprents() == null) {
+ switch (stat.type) {
+ case Statement.TYPE_SEQUENCE:
+ return hasDirectEndEdge(stat.getStats().getLast(), from);
+ case Statement.TYPE_CATCHALL:
+ case Statement.TYPE_TRYCATCH:
+ for (Statement st : stat.getStats()) {
+ if (hasDirectEndEdge(st, from)) {
+ return true;
+ }
+ }
+ break;
+ case Statement.TYPE_IF:
+ IfStatement ifstat = (IfStatement)stat;
+ if (ifstat.iftype == IfStatement.IFTYPE_IFELSE) {
+ return hasDirectEndEdge(ifstat.getIfstat(), from) ||
+ hasDirectEndEdge(ifstat.getElsestat(), from);
+ }
+ break;
+ case Statement.TYPE_SYNCRONIZED:
+ return hasDirectEndEdge(stat.getStats().get(1), from);
+ case Statement.TYPE_SWITCH:
+ for (Statement st : stat.getStats()) {
+ if (hasDirectEndEdge(st, from)) {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+
+ private static Statement getNextStatement(Statement stat) {
+
+ Statement parent = stat.getParent();
+ switch (parent.type) {
+ case Statement.TYPE_ROOT:
+ return ((RootStatement)parent).getDummyExit();
+ case Statement.TYPE_DO:
+ return parent;
+ case Statement.TYPE_SEQUENCE:
+ SequenceStatement sequence = (SequenceStatement)parent;
+ if (sequence.getStats().getLast() != stat) {
+ for (int i = sequence.getStats().size() - 1; i >= 0; i--) {
+ if (sequence.getStats().get(i) == stat) {
+ return sequence.getStats().get(i + 1);
+ }
+ }
+ }
+ }
+
+ return getNextStatement(parent);
+ }
+
+ private static boolean existsPath(Statement from, Statement to) {
+
+ for (StatEdge edge : to.getAllPredecessorEdges()) {
+ if (from.containsStatementStrict(edge.getSource())) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private static class IfNode {
+ public Statement value;
+
+ public List<IfNode> succs = new ArrayList<IfNode>();
+ public List<Integer> edgetypes = new ArrayList<Integer>();
+
+ public IfNode(Statement value) {
+ this.value = value;
+ }
+
+ public void addChild(IfNode child, int type) {
+ succs.add(child);
+ edgetypes.add(new Integer(type));
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/InlineSingleBlockHelper.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/InlineSingleBlockHelper.java
new file mode 100644
index 000000000000..adeda024151b
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/InlineSingleBlockHelper.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler;
+
+import org.jetbrains.java.decompiler.modules.decompiler.stats.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class InlineSingleBlockHelper {
+
+
+ public static boolean inlineSingleBlocks(RootStatement root) {
+
+ boolean res = inlineSingleBlocksRec(root);
+
+ if (res) {
+ SequenceHelper.condenseSequences(root);
+ }
+
+ return res;
+ }
+
+ private static boolean inlineSingleBlocksRec(Statement stat) {
+
+ boolean res = false;
+
+ for (Statement st : stat.getStats()) {
+ res |= inlineSingleBlocksRec(st);
+ }
+
+ if (stat.type == Statement.TYPE_SEQUENCE) {
+
+ SequenceStatement seq = (SequenceStatement)stat;
+ for (int i = 1; i < seq.getStats().size(); i++) {
+ if (isInlineable(seq, i)) {
+ inlineBlock(seq, i);
+ return true;
+ }
+ }
+ }
+
+ return res;
+ }
+
+ private static void inlineBlock(SequenceStatement seq, int index) {
+
+ Statement first = seq.getStats().get(index);
+ Statement pre = seq.getStats().get(index - 1);
+ pre.removeSuccessor(pre.getAllSuccessorEdges().get(0)); // single regular edge
+
+ StatEdge edge = first.getPredecessorEdges(StatEdge.TYPE_BREAK).get(0);
+ Statement source = edge.getSource();
+ Statement parent = source.getParent();
+ source.removeSuccessor(edge);
+
+ List<Statement> lst = new ArrayList<Statement>();
+ for (int i = seq.getStats().size() - 1; i >= index; i--) {
+ lst.add(0, seq.getStats().remove(i));
+ }
+
+ if (parent.type == Statement.TYPE_IF && ((IfStatement)parent).iftype == IfStatement.IFTYPE_IF &&
+ source == parent.getFirst()) {
+ IfStatement ifparent = (IfStatement)parent;
+ SequenceStatement block = new SequenceStatement(lst);
+ block.setAllParent();
+
+ StatEdge newedge = new StatEdge(StatEdge.TYPE_REGULAR, source, block);
+ source.addSuccessor(newedge);
+ ifparent.setIfEdge(newedge);
+ ifparent.setIfstat(block);
+
+ ifparent.getStats().addWithKey(block, block.id);
+ block.setParent(ifparent);
+ }
+ else {
+ lst.add(0, source);
+
+ SequenceStatement block = new SequenceStatement(lst);
+ block.setAllParent();
+
+ parent.replaceStatement(source, block);
+
+ // LabelHelper.lowContinueLabels not applicable because of forward continue edges
+ // LabelHelper.lowContinueLabels(block, new HashSet<StatEdge>());
+ // do it by hand
+ for (StatEdge prededge : block.getPredecessorEdges(StatEdge.TYPE_CONTINUE)) {
+
+ block.removePredecessor(prededge);
+ prededge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, prededge, source);
+ source.addPredecessor(prededge);
+
+ source.addLabeledEdge(prededge);
+ }
+
+
+ if (parent.type == Statement.TYPE_SWITCH) {
+ ((SwitchStatement)parent).sortEdgesAndNodes();
+ }
+
+ source.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, source, first));
+ }
+ }
+
+ private static boolean isInlineable(SequenceStatement seq, int index) {
+
+ Statement first = seq.getStats().get(index);
+ Statement pre = seq.getStats().get(index - 1);
+
+ if (pre.hasBasicSuccEdge()) {
+ return false;
+ }
+
+
+ List<StatEdge> lst = first.getPredecessorEdges(StatEdge.TYPE_BREAK);
+
+ if (lst.size() == 1) {
+ StatEdge edge = lst.get(0);
+
+ if (sameCatchRanges(edge)) {
+ if (edge.explicit) {
+ return true;
+ }
+ else {
+ for (int i = index; i < seq.getStats().size(); i++) {
+ if (!noExitLabels(seq.getStats().get(i), seq)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+ // FIXME: count labels properly
+ }
+
+ return false;
+ }
+
+ private static boolean sameCatchRanges(StatEdge edge) {
+
+ Statement from = edge.getSource();
+ Statement to = edge.getDestination();
+
+ while (true) {
+
+ Statement parent = from.getParent();
+ if (parent.containsStatementStrict(to)) {
+ break;
+ }
+
+ if (parent.type == Statement.TYPE_TRYCATCH ||
+ parent.type == Statement.TYPE_CATCHALL) {
+ if (parent.getFirst() == from) {
+ return false;
+ }
+ }
+ else if (parent.type == Statement.TYPE_SYNCRONIZED) {
+ if (parent.getStats().get(1) == from) {
+ return false;
+ }
+ }
+
+ from = parent;
+ }
+
+ return true;
+ }
+
+ private static boolean noExitLabels(Statement block, Statement sequence) {
+
+ for (StatEdge edge : block.getAllSuccessorEdges()) {
+ if (edge.getType() != StatEdge.TYPE_REGULAR && edge.getDestination().type != Statement.TYPE_DUMMYEXIT) {
+ if (!sequence.containsStatementStrict(edge.getDestination())) {
+ return false;
+ }
+ }
+ }
+
+ for (Statement st : block.getStats()) {
+ if (!noExitLabels(st, sequence)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public static boolean isBreakEdgeLabeled(Statement source, Statement closure) {
+
+ if (closure.type == Statement.TYPE_DO || closure.type == Statement.TYPE_SWITCH) {
+
+ Statement parent = source.getParent();
+
+ if (parent == closure) {
+ return false;
+ }
+ else {
+ return parent.type == Statement.TYPE_DO || parent.type == Statement.TYPE_SWITCH ||
+ isBreakEdgeLabeled(parent, closure);
+ }
+ }
+ else {
+ return true;
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/LabelHelper.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/LabelHelper.java
new file mode 100644
index 000000000000..1f4b5eea0e22
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/LabelHelper.java
@@ -0,0 +1,506 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler;
+
+import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.*;
+
+import java.util.*;
+import java.util.Map.Entry;
+
+
+public class LabelHelper {
+
+
+ public static void cleanUpEdges(RootStatement root) {
+
+ resetAllEdges(root);
+
+ removeNonImmediateEdges(root);
+
+ liftClosures(root);
+
+ lowContinueLabels(root, new HashSet<StatEdge>());
+
+ lowClosures(root);
+ }
+
+ public static void identifyLabels(RootStatement root) {
+
+ setExplicitEdges(root);
+
+ hideDefaultSwitchEdges(root);
+
+ processStatementLabel(root);
+
+ setRetEdgesUnlabeled(root);
+ }
+
+ private static void liftClosures(Statement stat) {
+
+ for (StatEdge edge : stat.getAllSuccessorEdges()) {
+ switch (edge.getType()) {
+ case StatEdge.TYPE_CONTINUE:
+ if (edge.getDestination() != edge.closure) {
+ edge.getDestination().addLabeledEdge(edge);
+ }
+ break;
+ case StatEdge.TYPE_BREAK:
+ Statement dest = edge.getDestination();
+ if (dest.type != Statement.TYPE_DUMMYEXIT) {
+ Statement parent = dest.getParent();
+
+ List<Statement> lst = new ArrayList<Statement>();
+ if (parent.type == Statement.TYPE_SEQUENCE) {
+ lst.addAll(parent.getStats());
+ }
+ else if (parent.type == Statement.TYPE_SWITCH) {
+ lst.addAll(((SwitchStatement)parent).getCaseStatements());
+ }
+
+ for (int i = 0; i < lst.size(); i++) {
+ if (lst.get(i) == dest) {
+ lst.get(i - 1).addLabeledEdge(edge);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ for (Statement st : stat.getStats()) {
+ liftClosures(st);
+ }
+ }
+
+ private static void removeNonImmediateEdges(Statement stat) {
+
+ for (Statement st : stat.getStats()) {
+ removeNonImmediateEdges(st);
+ }
+
+ if (!stat.hasBasicSuccEdge()) {
+ for (StatEdge edge : stat.getSuccessorEdges(StatEdge.TYPE_CONTINUE | StatEdge.TYPE_BREAK)) {
+ stat.removeSuccessor(edge);
+ }
+ }
+ }
+
+ public static void lowContinueLabels(Statement stat, HashSet<StatEdge> edges) {
+
+ boolean ok = (stat.type != Statement.TYPE_DO);
+ if (!ok) {
+ DoStatement dostat = (DoStatement)stat;
+ ok = dostat.getLooptype() == DoStatement.LOOP_DO ||
+ dostat.getLooptype() == DoStatement.LOOP_WHILE ||
+ (dostat.getLooptype() == DoStatement.LOOP_FOR && dostat.getIncExprent() == null);
+ }
+
+ if (ok) {
+ edges.addAll(stat.getPredecessorEdges(StatEdge.TYPE_CONTINUE));
+ }
+
+ if (ok && stat.type == Statement.TYPE_DO) {
+ for (StatEdge edge : edges) {
+ if (stat.containsStatementStrict(edge.getSource())) {
+
+ edge.getDestination().removePredecessor(edge);
+ edge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, edge, stat);
+ stat.addPredecessor(edge);
+
+ stat.addLabeledEdge(edge);
+ }
+ }
+ }
+
+ for (Statement st : stat.getStats()) {
+ if (st == stat.getFirst()) {
+ lowContinueLabels(st, edges);
+ }
+ else {
+ lowContinueLabels(st, new HashSet<StatEdge>());
+ }
+ }
+ }
+
+ public static void lowClosures(Statement stat) {
+
+ for (StatEdge edge : new ArrayList<StatEdge>(stat.getLabelEdges())) {
+
+ if (edge.getType() == StatEdge.TYPE_BREAK) { // FIXME: ?
+ for (Statement st : stat.getStats()) {
+ if (st.containsStatementStrict(edge.getSource())) {
+ if (MergeHelper.isDirectPath(st, edge.getDestination())) {
+ st.addLabeledEdge(edge);
+ }
+ }
+ }
+ }
+ }
+
+ for (Statement st : stat.getStats()) {
+ lowClosures(st);
+ }
+ }
+
+ private static void resetAllEdges(Statement stat) {
+
+ for (Statement st : stat.getStats()) {
+ resetAllEdges(st);
+ }
+
+ for (StatEdge edge : stat.getAllSuccessorEdges()) {
+ edge.explicit = true;
+ edge.labeled = true;
+ }
+ }
+
+ private static void setRetEdgesUnlabeled(RootStatement root) {
+ Statement exit = root.getDummyExit();
+ for (StatEdge edge : exit.getAllPredecessorEdges()) {
+ List<Exprent> lst = edge.getSource().getExprents();
+ if (edge.getType() == StatEdge.TYPE_FINALLYEXIT || (lst != null && !lst.isEmpty() &&
+ lst.get(lst.size() - 1).type == Exprent.EXPRENT_EXIT)) {
+ edge.labeled = false;
+ }
+ }
+ }
+
+ private static HashMap<Statement, List<StatEdge>> setExplicitEdges(Statement stat) {
+
+ HashMap<Statement, List<StatEdge>> mapEdges = new HashMap<Statement, List<StatEdge>>();
+
+ if (stat.getExprents() != null) {
+ return mapEdges;
+ }
+
+
+ switch (stat.type) {
+ case Statement.TYPE_TRYCATCH:
+ case Statement.TYPE_CATCHALL:
+
+ for (Statement st : stat.getStats()) {
+ HashMap<Statement, List<StatEdge>> mapEdges1 = setExplicitEdges(st);
+ processEdgesWithNext(st, mapEdges1, null);
+
+ if (stat.type == Statement.TYPE_TRYCATCH || st == stat.getFirst()) { // edges leaving a finally catch block are always explicit
+ // merge the maps
+ if (mapEdges1 != null) {
+ for (Entry<Statement, List<StatEdge>> entr : mapEdges1.entrySet()) {
+ if (mapEdges.containsKey(entr.getKey())) {
+ mapEdges.get(entr.getKey()).addAll(entr.getValue());
+ }
+ else {
+ mapEdges.put(entr.getKey(), entr.getValue());
+ }
+ }
+ }
+ }
+ }
+
+ break;
+ case Statement.TYPE_DO:
+ mapEdges = setExplicitEdges(stat.getFirst());
+ processEdgesWithNext(stat.getFirst(), mapEdges, stat);
+ break;
+ case Statement.TYPE_IF:
+ IfStatement ifstat = (IfStatement)stat;
+ // head statement is a basic block
+ if (ifstat.getIfstat() == null) { // empty if
+ processEdgesWithNext(ifstat.getFirst(), mapEdges, null);
+ }
+ else {
+ mapEdges = setExplicitEdges(ifstat.getIfstat());
+ processEdgesWithNext(ifstat.getIfstat(), mapEdges, null);
+
+ HashMap<Statement, List<StatEdge>> mapEdges1 = null;
+ if (ifstat.getElsestat() != null) {
+ mapEdges1 = setExplicitEdges(ifstat.getElsestat());
+ processEdgesWithNext(ifstat.getElsestat(), mapEdges1, null);
+ }
+
+ // merge the maps
+ if (mapEdges1 != null) {
+ for (Entry<Statement, List<StatEdge>> entr : mapEdges1.entrySet()) {
+ if (mapEdges.containsKey(entr.getKey())) {
+ mapEdges.get(entr.getKey()).addAll(entr.getValue());
+ }
+ else {
+ mapEdges.put(entr.getKey(), entr.getValue());
+ }
+ }
+ }
+ }
+ break;
+ case Statement.TYPE_ROOT:
+ mapEdges = setExplicitEdges(stat.getFirst());
+ processEdgesWithNext(stat.getFirst(), mapEdges, ((RootStatement)stat).getDummyExit());
+ break;
+ case Statement.TYPE_SEQUENCE:
+ int index = 0;
+ while (index < stat.getStats().size() - 1) {
+ Statement st = stat.getStats().get(index);
+ processEdgesWithNext(st, setExplicitEdges(st), stat.getStats().get(index + 1));
+ index++;
+ }
+
+ Statement st = stat.getStats().get(index);
+ mapEdges = setExplicitEdges(st);
+ processEdgesWithNext(st, mapEdges, null);
+ break;
+ case Statement.TYPE_SWITCH:
+ SwitchStatement swst = (SwitchStatement)stat;
+
+ for (int i = 0; i < swst.getCaseStatements().size() - 1; i++) {
+ Statement stt = swst.getCaseStatements().get(i);
+ Statement stnext = swst.getCaseStatements().get(i + 1);
+
+ if (stnext.getExprents() != null && stnext.getExprents().isEmpty()) {
+ stnext = stnext.getAllSuccessorEdges().get(0).getDestination();
+ }
+ processEdgesWithNext(stt, setExplicitEdges(stt), stnext);
+ }
+
+ int last = swst.getCaseStatements().size() - 1;
+ if (last >= 0) { // empty switch possible
+ Statement stlast = swst.getCaseStatements().get(last);
+ if (stlast.getExprents() != null && stlast.getExprents().isEmpty()) {
+ StatEdge edge = stlast.getAllSuccessorEdges().get(0);
+ mapEdges.put(edge.getDestination(), new ArrayList<StatEdge>(Arrays.asList(new StatEdge[]{edge})));
+ }
+ else {
+ mapEdges = setExplicitEdges(stlast);
+ processEdgesWithNext(stlast, mapEdges, null);
+ }
+ }
+
+ break;
+ case Statement.TYPE_SYNCRONIZED:
+ SynchronizedStatement synstat = (SynchronizedStatement)stat;
+
+ processEdgesWithNext(synstat.getFirst(), setExplicitEdges(stat.getFirst()), synstat.getBody()); // FIXME: basic block?
+ mapEdges = setExplicitEdges(synstat.getBody());
+ processEdgesWithNext(synstat.getBody(), mapEdges, null);
+ }
+
+
+ return mapEdges;
+ }
+
+ private static void processEdgesWithNext(Statement stat, HashMap<Statement, List<StatEdge>> mapEdges, Statement next) {
+
+ StatEdge statedge = null;
+
+ List<StatEdge> lstSuccs = stat.getAllSuccessorEdges();
+ if (!lstSuccs.isEmpty()) {
+ statedge = lstSuccs.get(0);
+
+ if (statedge.getDestination() == next) {
+ statedge.explicit = false;
+ statedge = null;
+ }
+ else {
+ next = statedge.getDestination();
+ }
+ }
+
+ // no next for a do statement
+ if (stat.type == Statement.TYPE_DO && ((DoStatement)stat).getLooptype() == DoStatement.LOOP_DO) {
+ next = null;
+ }
+
+ if (next == null) {
+ if (mapEdges.size() == 1) {
+ List<StatEdge> lstEdges = mapEdges.values().iterator().next();
+ if (lstEdges.size() > 1 && mapEdges.keySet().iterator().next().type != Statement.TYPE_DUMMYEXIT) {
+ StatEdge edge_example = lstEdges.get(0);
+
+ Statement closure = stat.getParent();
+ if (!closure.containsStatementStrict(edge_example.closure)) {
+ closure = edge_example.closure;
+ }
+
+ StatEdge newedge = new StatEdge(edge_example.getType(), stat, edge_example.getDestination(), closure);
+ stat.addSuccessor(newedge);
+
+ for (StatEdge edge : lstEdges) {
+ edge.explicit = false;
+ }
+
+ mapEdges.put(newedge.getDestination(), new ArrayList<StatEdge>(Arrays.asList(new StatEdge[]{newedge})));
+ }
+ }
+ }
+ else {
+
+ boolean implfound = false;
+
+ for (Entry<Statement, List<StatEdge>> entr : mapEdges.entrySet()) {
+ if (entr.getKey() == next) {
+ for (StatEdge edge : entr.getValue()) {
+ edge.explicit = false;
+ }
+ implfound = true;
+ break;
+ }
+ }
+
+ if (stat.getAllSuccessorEdges().isEmpty() && !implfound) {
+ List<StatEdge> lstEdges = null;
+ for (Entry<Statement, List<StatEdge>> entr : mapEdges.entrySet()) {
+ if (entr.getKey().type != Statement.TYPE_DUMMYEXIT &&
+ (lstEdges == null || entr.getValue().size() > lstEdges.size())) {
+ lstEdges = entr.getValue();
+ }
+ }
+
+ if (lstEdges != null && lstEdges.size() > 1) {
+ StatEdge edge_example = lstEdges.get(0);
+
+ Statement closure = stat.getParent();
+ if (!closure.containsStatementStrict(edge_example.closure)) {
+ closure = edge_example.closure;
+ }
+
+ StatEdge newedge = new StatEdge(edge_example.getType(), stat, edge_example.getDestination(), closure);
+ stat.addSuccessor(newedge);
+
+ for (StatEdge edge : lstEdges) {
+ edge.explicit = false;
+ }
+ }
+ }
+
+ mapEdges.clear();
+ }
+
+ if (statedge != null) {
+ mapEdges.put(statedge.getDestination(), new ArrayList<StatEdge>(Arrays.asList(new StatEdge[]{statedge})));
+ }
+ }
+
+ private static void hideDefaultSwitchEdges(Statement stat) {
+
+ if (stat.type == Statement.TYPE_SWITCH) {
+ SwitchStatement swst = (SwitchStatement)stat;
+
+ int last = swst.getCaseStatements().size() - 1;
+ if (last >= 0) { // empty switch possible
+ Statement stlast = swst.getCaseStatements().get(last);
+
+ if (stlast.getExprents() != null && stlast.getExprents().isEmpty()) {
+ if (!stlast.getAllSuccessorEdges().get(0).explicit) {
+ List<StatEdge> lstEdges = swst.getCaseEdges().get(last);
+ lstEdges.remove(swst.getDefault_edge());
+
+ if (lstEdges.isEmpty()) {
+ swst.getCaseStatements().remove(last);
+ swst.getCaseEdges().remove(last);
+ }
+ }
+ }
+ }
+ }
+
+ for (Statement st : stat.getStats()) {
+ hideDefaultSwitchEdges(st);
+ }
+ }
+
+ private static void processStatementLabel(Statement stat) {
+ processStatementLabel(stat, new HashSet<Statement>(), new HashSet<Statement>());
+ }
+
+ private static void processStatementLabel(Statement stat, Set<Statement> setBreak, Set<Statement> setContinue) {
+ if (stat.getExprents() == null) {
+ for (Statement st : stat.getStats()) {
+ processStatementLabel(st, setBreak, setContinue);
+ }
+
+ boolean shieldtype = (stat.type == Statement.TYPE_DO || stat.type == Statement.TYPE_SWITCH);
+
+ for (StatEdge edge : stat.getLabelEdges()) {
+ if (edge.explicit) {
+ if (shieldtype && ((edge.getType() == StatEdge.TYPE_BREAK && setBreak.contains(edge.getSource())) ||
+ (edge.getType() == StatEdge.TYPE_CONTINUE && setContinue.contains(edge.getSource())))) {
+ edge.labeled = false;
+ }
+ }
+ }
+
+ switch (stat.type) {
+ case Statement.TYPE_DO:
+ setContinue.clear();
+ case Statement.TYPE_SWITCH:
+ setBreak.clear();
+ }
+ }
+
+ setBreak.add(stat);
+ setContinue.add(stat);
+ }
+
+ public static void replaceContinueWithBreak(Statement stat) {
+
+ if (stat.type == Statement.TYPE_DO) {
+
+ List<StatEdge> lst = stat.getPredecessorEdges(StatEdge.TYPE_CONTINUE);
+
+ for (StatEdge edge : lst) {
+
+ if (edge.explicit) {
+ Statement minclosure = getMinContinueClosure(edge);
+
+ if (minclosure != edge.closure &&
+ !InlineSingleBlockHelper.isBreakEdgeLabeled(edge.getSource(), minclosure)) {
+ edge.getSource().changeEdgeType(Statement.DIRECTION_FORWARD, edge, StatEdge.TYPE_BREAK);
+ edge.labeled = false;
+ minclosure.addLabeledEdge(edge);
+ }
+ }
+ }
+ }
+
+ for (Statement st : stat.getStats()) {
+ replaceContinueWithBreak(st);
+ }
+ }
+
+ private static Statement getMinContinueClosure(StatEdge edge) {
+
+ Statement closure = edge.closure;
+ while (true) {
+
+ boolean found = false;
+
+ for (Statement st : closure.getStats()) {
+ if (st.containsStatementStrict(edge.getSource())) {
+ if (MergeHelper.isDirectPath(st, edge.getDestination())) {
+ closure = st;
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (!found) {
+ break;
+ }
+ }
+
+ return closure;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/LoopExtractHelper.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/LoopExtractHelper.java
new file mode 100644
index 000000000000..d5c9e8f20aee
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/LoopExtractHelper.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler;
+
+import org.jetbrains.java.decompiler.modules.decompiler.stats.DoStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.IfStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.SequenceStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Set;
+
+
+public class LoopExtractHelper {
+
+
+ public static boolean extractLoops(Statement root) {
+
+ boolean res = (extractLoopsRec(root) != 0);
+
+ if (res) {
+ SequenceHelper.condenseSequences(root);
+ }
+
+ return res;
+ }
+
+
+ private static int extractLoopsRec(Statement stat) {
+
+ boolean res = false;
+
+ while (true) {
+
+ boolean updated = false;
+
+ for (Statement st : stat.getStats()) {
+ int extr = extractLoopsRec(st);
+ res |= (extr != 0);
+
+ if (extr == 2) {
+ updated = true;
+ break;
+ }
+ }
+
+ if (!updated) {
+ break;
+ }
+ }
+
+ if (stat.type == Statement.TYPE_DO) {
+ if (extractLoop((DoStatement)stat)) {
+ return 2;
+ }
+ }
+
+ return res ? 1 : 0;
+ }
+
+
+ private static boolean extractLoop(DoStatement stat) {
+
+ if (stat.getLooptype() != DoStatement.LOOP_DO) {
+ return false;
+ }
+
+ for (StatEdge edge : stat.getLabelEdges()) {
+ if (edge.getType() != StatEdge.TYPE_CONTINUE && edge.getDestination().type != Statement.TYPE_DUMMYEXIT) {
+ return false;
+ }
+ }
+
+ if (!extractLastIf(stat)) {
+ return extractFirstIf(stat);
+ }
+ else {
+ return true;
+ }
+ }
+
+ private static boolean extractLastIf(DoStatement stat) {
+
+ // search for an if condition at the end of the loop
+ Statement last = stat.getFirst();
+ while (last.type == Statement.TYPE_SEQUENCE) {
+ last = last.getStats().getLast();
+ }
+
+ if (last.type == Statement.TYPE_IF) {
+ IfStatement lastif = (IfStatement)last;
+ if (lastif.iftype == IfStatement.IFTYPE_IF && lastif.getIfstat() != null) {
+ Statement ifstat = lastif.getIfstat();
+ StatEdge elseedge = lastif.getAllSuccessorEdges().get(0);
+
+ if (elseedge.getType() == StatEdge.TYPE_CONTINUE && elseedge.closure == stat) {
+
+ Set<Statement> set = stat.getNeighboursSet(StatEdge.TYPE_CONTINUE, Statement.DIRECTION_BACKWARD);
+ set.remove(last);
+
+ if (set.isEmpty()) { // no direct continues in a do{}while loop
+ if (isExternStatement(stat, ifstat, ifstat)) {
+ extractIfBlock(stat, lastif);
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ private static boolean extractFirstIf(DoStatement stat) {
+
+ // search for an if condition at the entrance of the loop
+ Statement first = stat.getFirst();
+ while (first.type == Statement.TYPE_SEQUENCE) {
+ first = first.getFirst();
+ }
+
+ // found an if statement
+ if (first.type == Statement.TYPE_IF) {
+ IfStatement firstif = (IfStatement)first;
+
+ if (firstif.getFirst().getExprents().isEmpty()) {
+
+ if (firstif.iftype == IfStatement.IFTYPE_IF && firstif.getIfstat() != null) {
+ Statement ifstat = firstif.getIfstat();
+
+ if (isExternStatement(stat, ifstat, ifstat)) {
+ extractIfBlock(stat, firstif);
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+
+ private static boolean isExternStatement(DoStatement loop, Statement block, Statement stat) {
+
+ for (StatEdge edge : stat.getAllSuccessorEdges()) {
+ if (loop.containsStatement(edge.getDestination()) &&
+ !block.containsStatement(edge.getDestination())) {
+ return false;
+ }
+ }
+
+ for (Statement st : stat.getStats()) {
+ if (!isExternStatement(loop, block, st)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+
+ private static void extractIfBlock(DoStatement loop, IfStatement ifstat) {
+
+ Statement target = ifstat.getIfstat();
+ StatEdge ifedge = ifstat.getIfEdge();
+
+ ifstat.setIfstat(null);
+ ifedge.getSource().changeEdgeType(Statement.DIRECTION_FORWARD, ifedge, StatEdge.TYPE_BREAK);
+ ifedge.closure = loop;
+ ifstat.getStats().removeWithKey(target.id);
+
+ loop.addLabeledEdge(ifedge);
+
+ SequenceStatement block = new SequenceStatement(Arrays.asList(loop, target));
+ loop.getParent().replaceStatement(loop, block);
+ block.setAllParent();
+
+ loop.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, loop, target));
+
+ for (StatEdge edge : new ArrayList<StatEdge>(block.getLabelEdges())) {
+ if (edge.getType() == StatEdge.TYPE_CONTINUE || edge == ifedge) {
+ loop.addLabeledEdge(edge);
+ }
+ }
+
+ for (StatEdge edge : block.getPredecessorEdges(StatEdge.TYPE_CONTINUE)) {
+ if (loop.containsStatementStrict(edge.getSource())) {
+ block.removePredecessor(edge);
+ edge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, edge, loop);
+ loop.addPredecessor(edge);
+ }
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/LowBreakHelper.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/LowBreakHelper.java
new file mode 100644
index 000000000000..67e9248d0f83
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/LowBreakHelper.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler;
+
+import org.jetbrains.java.decompiler.modules.decompiler.stats.IfStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.SynchronizedStatement;
+
+import java.util.List;
+
+public class LowBreakHelper {
+
+ public static void lowBreakLabels(Statement root) {
+
+ lowBreakLabelsRec(root);
+
+ liftBreakLabels(root);
+ }
+
+ private static void lowBreakLabelsRec(Statement stat) {
+
+ while (true) {
+
+ boolean found = false;
+
+ for (StatEdge edge : stat.getLabelEdges()) {
+ if (edge.getType() == StatEdge.TYPE_BREAK) {
+ Statement minclosure = getMinClosure(stat, edge.getSource());
+ if (minclosure != stat) {
+ minclosure.addLabeledEdge(edge);
+ edge.labeled = isBreakEdgeLabeled(edge.getSource(), minclosure);
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (!found) {
+ break;
+ }
+ }
+
+ for (Statement st : stat.getStats()) {
+ lowBreakLabelsRec(st);
+ }
+ }
+
+ public static boolean isBreakEdgeLabeled(Statement source, Statement closure) {
+
+ if (closure.type == Statement.TYPE_DO || closure.type == Statement.TYPE_SWITCH) {
+
+ Statement parent = source.getParent();
+
+ if (parent == closure) {
+ return false;
+ }
+ else {
+ return isBreakEdgeLabeled(parent, closure) ||
+ (parent.type == Statement.TYPE_DO || parent.type == Statement.TYPE_SWITCH);
+ }
+ }
+ else {
+ return true;
+ }
+ }
+
+ public static Statement getMinClosure(Statement closure, Statement source) {
+
+ while (true) {
+
+ Statement newclosure = null;
+
+ switch (closure.type) {
+ case Statement.TYPE_SEQUENCE:
+ Statement last = closure.getStats().getLast();
+
+ if (isOkClosure(closure, source, last)) {
+ newclosure = last;
+ }
+ break;
+ case Statement.TYPE_IF:
+ IfStatement ifclosure = (IfStatement)closure;
+ if (isOkClosure(closure, source, ifclosure.getIfstat())) {
+ newclosure = ifclosure.getIfstat();
+ }
+ else if (isOkClosure(closure, source, ifclosure.getElsestat())) {
+ newclosure = ifclosure.getElsestat();
+ }
+ break;
+ case Statement.TYPE_TRYCATCH:
+ for (Statement st : closure.getStats()) {
+ if (isOkClosure(closure, source, st)) {
+ newclosure = st;
+ break;
+ }
+ }
+ break;
+ case Statement.TYPE_SYNCRONIZED:
+ Statement body = ((SynchronizedStatement)closure).getBody();
+
+ if (isOkClosure(closure, source, body)) {
+ newclosure = body;
+ }
+ }
+
+ if (newclosure == null) {
+ break;
+ }
+
+ closure = newclosure;
+ }
+
+ return closure;
+ }
+
+ private static boolean isOkClosure(Statement closure, Statement source, Statement stat) {
+
+ boolean ok = false;
+
+ if (stat != null && stat.containsStatementStrict(source)) {
+
+ List<StatEdge> lst = stat.getAllSuccessorEdges();
+
+ ok = lst.isEmpty();
+ if (!ok) {
+ StatEdge edge = lst.get(0);
+ ok = (edge.closure == closure && edge.getType() == StatEdge.TYPE_BREAK);
+ }
+ }
+
+ return ok;
+ }
+
+
+ private static void liftBreakLabels(Statement stat) {
+
+ for (Statement st : stat.getStats()) {
+ liftBreakLabels(st);
+ }
+
+
+ while (true) {
+
+ boolean found = false;
+
+ for (StatEdge edge : stat.getLabelEdges()) {
+ if (edge.explicit && edge.labeled && edge.getType() == StatEdge.TYPE_BREAK) {
+
+ Statement newclosure = getMaxBreakLift(stat, edge);
+
+ if (newclosure != null) {
+ newclosure.addLabeledEdge(edge);
+ edge.labeled = isBreakEdgeLabeled(edge.getSource(), newclosure);
+
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (!found) {
+ break;
+ }
+ }
+ }
+
+ private static Statement getMaxBreakLift(Statement stat, StatEdge edge) {
+
+ Statement closure = null;
+ Statement newclosure = stat;
+
+ while ((newclosure = getNextBreakLift(newclosure, edge)) != null) {
+ closure = newclosure;
+ }
+
+ return closure;
+ }
+
+ private static Statement getNextBreakLift(Statement stat, StatEdge edge) {
+
+ Statement closure = stat.getParent();
+
+ while (closure != null && !closure.containsStatementStrict(edge.getDestination())) {
+
+ boolean labeled = isBreakEdgeLabeled(edge.getSource(), closure);
+ if (closure.isLabeled() || !labeled) {
+ return closure;
+ }
+
+ closure = closure.getParent();
+ }
+
+ return null;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/MergeHelper.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/MergeHelper.java
new file mode 100644
index 000000000000..71d3d7991287
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/MergeHelper.java
@@ -0,0 +1,421 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler;
+
+import org.jetbrains.java.decompiler.code.cfg.BasicBlock;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.IfExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.*;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+public class MergeHelper {
+
+ public static void enhanceLoops(Statement root) {
+
+ while (enhanceLoopsRec(root)) ;
+
+ SequenceHelper.condenseSequences(root);
+ }
+
+ private static boolean enhanceLoopsRec(Statement stat) {
+
+ boolean res = false;
+
+ for (Statement st : stat.getStats()) {
+ if (st.getExprents() == null) {
+ res |= enhanceLoopsRec(st);
+ }
+ }
+
+ if (stat.type == Statement.TYPE_DO) {
+ res |= enhanceLoop((DoStatement)stat);
+ }
+
+ return res;
+ }
+
+ private static boolean enhanceLoop(DoStatement stat) {
+
+ int oldloop = stat.getLooptype();
+
+ switch (oldloop) {
+ case DoStatement.LOOP_DO:
+
+ // identify a while loop
+ if (matchWhile(stat)) {
+ // identify a for loop - subtype of while
+ matchFor(stat);
+ }
+ else {
+ // identify a do{}while loop
+ matchDoWhile(stat);
+ }
+
+ break;
+ case DoStatement.LOOP_WHILE:
+ matchFor(stat);
+ }
+
+ return (stat.getLooptype() != oldloop);
+ }
+
+ private static boolean matchDoWhile(DoStatement stat) {
+
+ // search for an if condition at the end of the loop
+ Statement last = stat.getFirst();
+ while (last.type == Statement.TYPE_SEQUENCE) {
+ last = last.getStats().getLast();
+ }
+
+ if (last.type == Statement.TYPE_IF) {
+ IfStatement lastif = (IfStatement)last;
+ if (lastif.iftype == IfStatement.IFTYPE_IF && lastif.getIfstat() == null) {
+ StatEdge ifedge = lastif.getIfEdge();
+ StatEdge elseedge = lastif.getAllSuccessorEdges().get(0);
+
+ if ((ifedge.getType() == StatEdge.TYPE_BREAK && elseedge.getType() == StatEdge.TYPE_CONTINUE && elseedge.closure == stat
+ && isDirectPath(stat, ifedge.getDestination())) ||
+ (ifedge.getType() == StatEdge.TYPE_CONTINUE && elseedge.getType() == StatEdge.TYPE_BREAK && ifedge.closure == stat
+ && isDirectPath(stat, elseedge.getDestination()))) {
+
+ Set<Statement> set = stat.getNeighboursSet(StatEdge.TYPE_CONTINUE, Statement.DIRECTION_BACKWARD);
+ set.remove(last);
+
+ if (!set.isEmpty()) {
+ return false;
+ }
+
+
+ stat.setLooptype(DoStatement.LOOP_DOWHILE);
+
+ IfExprent ifexpr = (IfExprent)lastif.getHeadexprent().copy();
+ if (ifedge.getType() == StatEdge.TYPE_BREAK) {
+ ifexpr.negateIf();
+ }
+ stat.setConditionExprent(ifexpr.getCondition());
+ lastif.getFirst().removeSuccessor(ifedge);
+ lastif.removeSuccessor(elseedge);
+
+ // remove empty if
+ if (lastif.getFirst().getExprents().isEmpty()) {
+ removeLastEmptyStatement(stat, lastif);
+ }
+ else {
+ lastif.setExprents(lastif.getFirst().getExprents());
+
+ StatEdge newedge = new StatEdge(StatEdge.TYPE_CONTINUE, lastif, stat);
+ lastif.addSuccessor(newedge);
+ stat.addLabeledEdge(newedge);
+ }
+
+ if (stat.getAllSuccessorEdges().isEmpty()) {
+ StatEdge edge = elseedge.getType() == StatEdge.TYPE_CONTINUE ? ifedge : elseedge;
+
+ edge.setSource(stat);
+ if (edge.closure == stat) {
+ edge.closure = stat.getParent();
+ }
+ stat.addSuccessor(edge);
+ }
+
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private static boolean matchWhile(DoStatement stat) {
+
+ // search for an if condition at the entrance of the loop
+ Statement first = stat.getFirst();
+ while (first.type == Statement.TYPE_SEQUENCE) {
+ first = first.getFirst();
+ }
+
+ // found an if statement
+ if (first.type == Statement.TYPE_IF) {
+ IfStatement firstif = (IfStatement)first;
+
+ if (firstif.getFirst().getExprents().isEmpty()) {
+
+ if (firstif.iftype == IfStatement.IFTYPE_IF) {
+ if (firstif.getIfstat() == null) {
+ StatEdge ifedge = firstif.getIfEdge();
+ if (isDirectPath(stat, ifedge.getDestination())) {
+ // exit condition identified
+ stat.setLooptype(DoStatement.LOOP_WHILE);
+
+ // negate condition (while header)
+ IfExprent ifexpr = (IfExprent)firstif.getHeadexprent().copy();
+ ifexpr.negateIf();
+ stat.setConditionExprent(ifexpr.getCondition());
+
+ // remove edges
+ firstif.getFirst().removeSuccessor(ifedge);
+ firstif.removeSuccessor(firstif.getAllSuccessorEdges().get(0));
+
+ if (stat.getAllSuccessorEdges().isEmpty()) {
+ ifedge.setSource(stat);
+ if (ifedge.closure == stat) {
+ ifedge.closure = stat.getParent();
+ }
+ stat.addSuccessor(ifedge);
+ }
+
+ // remove empty if statement as it is now part of the loop
+ if (firstif == stat.getFirst()) {
+ BasicBlockStatement bstat = new BasicBlockStatement(new BasicBlock(
+ DecompilerContext.getCounterContainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER)));
+ bstat.setExprents(new ArrayList<Exprent>());
+ stat.replaceStatement(firstif, bstat);
+ }
+ else {
+ // precondition: sequence must contain more than one statement!
+ Statement sequence = firstif.getParent();
+ sequence.getStats().removeWithKey(firstif.id);
+ sequence.setFirst(sequence.getStats().get(0));
+ }
+
+ return true;
+ }
+ }
+ else {
+ StatEdge elseedge = firstif.getAllSuccessorEdges().get(0);
+ if (isDirectPath(stat, elseedge.getDestination())) {
+ // exit condition identified
+ stat.setLooptype(DoStatement.LOOP_WHILE);
+
+ // no need to negate the while condition
+ stat.setConditionExprent(((IfExprent)firstif.getHeadexprent().copy()).getCondition());
+
+ // remove edges
+ StatEdge ifedge = firstif.getIfEdge();
+ firstif.getFirst().removeSuccessor(ifedge);
+ firstif.removeSuccessor(elseedge);
+
+ if (stat.getAllSuccessorEdges().isEmpty()) {
+
+ elseedge.setSource(stat);
+ if (elseedge.closure == stat) {
+ elseedge.closure = stat.getParent();
+ }
+ stat.addSuccessor(elseedge);
+ }
+
+ if (firstif.getIfstat() == null) {
+ BasicBlockStatement bstat = new BasicBlockStatement(new BasicBlock(
+ DecompilerContext.getCounterContainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER)));
+ bstat.setExprents(new ArrayList<Exprent>());
+
+ ifedge.setSource(bstat);
+ bstat.addSuccessor(ifedge);
+
+ stat.replaceStatement(firstif, bstat);
+ }
+ else {
+ // replace the if statement with its content
+ first.getParent().replaceStatement(first, firstif.getIfstat());
+
+ // lift closures
+ for (StatEdge prededge : elseedge.getDestination().getPredecessorEdges(StatEdge.TYPE_BREAK)) {
+ if (stat.containsStatementStrict(prededge.closure)) {
+ stat.addLabeledEdge(prededge);
+ }
+ }
+
+ LabelHelper.lowClosures(stat);
+ }
+
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ public static boolean isDirectPath(Statement stat, Statement endstat) {
+
+ Set<Statement> setStat = stat.getNeighboursSet(Statement.STATEDGE_DIRECT_ALL, Statement.DIRECTION_FORWARD);
+ if (setStat.isEmpty()) {
+ Statement parent = stat.getParent();
+ if (parent == null) {
+ return false;
+ }
+ else {
+ switch (parent.type) {
+ case Statement.TYPE_ROOT:
+ return endstat.type == Statement.TYPE_DUMMYEXIT;
+ case Statement.TYPE_DO:
+ return (endstat == parent);
+ case Statement.TYPE_SWITCH:
+ SwitchStatement swst = (SwitchStatement)parent;
+ for (int i = 0; i < swst.getCaseStatements().size() - 1; i++) {
+ Statement stt = swst.getCaseStatements().get(i);
+ if (stt == stat) {
+ Statement stnext = swst.getCaseStatements().get(i + 1);
+
+ if (stnext.getExprents() != null && stnext.getExprents().isEmpty()) {
+ stnext = stnext.getAllSuccessorEdges().get(0).getDestination();
+ }
+ return (endstat == stnext);
+ }
+ }
+ default:
+ return isDirectPath(parent, endstat);
+ }
+ }
+ }
+ else {
+ return setStat.contains(endstat);
+ }
+ }
+
+ private static boolean matchFor(DoStatement stat) {
+
+ Exprent lastDoExprent = null, initDoExprent = null;
+ Statement lastData = null, preData = null;
+
+ // get last exprent
+ lastData = getLastDirectData(stat.getFirst());
+ if (lastData == null || lastData.getExprents().isEmpty()) {
+ return false;
+ }
+
+ List<Exprent> lstExpr = lastData.getExprents();
+ lastDoExprent = lstExpr.get(lstExpr.size() - 1);
+
+ boolean issingle = false;
+ if (lstExpr.size() == 1) { // single exprent
+ if (lastData.getAllPredecessorEdges().size() > 1) { // break edges
+ issingle = true;
+ }
+ }
+
+ boolean haslast = issingle || (lastDoExprent.type == Exprent.EXPRENT_ASSIGNMENT ||
+ lastDoExprent.type == Exprent.EXPRENT_FUNCTION);
+
+ if (!haslast) {
+ return false;
+ }
+
+ boolean hasinit = false;
+
+ // search for an initializing exprent
+ Statement current = stat;
+ while (true) {
+ Statement parent = current.getParent();
+ if (parent == null) {
+ break;
+ }
+
+ if (parent.type == Statement.TYPE_SEQUENCE) {
+ if (current == parent.getFirst()) {
+ current = parent;
+ }
+ else {
+ preData = current.getNeighbours(StatEdge.TYPE_REGULAR, Statement.DIRECTION_BACKWARD).get(0);
+ preData = getLastDirectData(preData);
+ if (preData != null && !preData.getExprents().isEmpty()) {
+ initDoExprent = preData.getExprents().get(preData.getExprents().size() - 1);
+ if (initDoExprent.type == Exprent.EXPRENT_ASSIGNMENT) {
+ hasinit = true;
+ }
+ }
+ break;
+ }
+ }
+ else {
+ break;
+ }
+ }
+
+ if ((hasinit && haslast) || issingle) { // FIXME: issingle sufficient?
+
+ Set<Statement> set = stat.getNeighboursSet(StatEdge.TYPE_CONTINUE, Statement.DIRECTION_BACKWARD);
+ set.remove(lastData);
+
+ if (!set.isEmpty()) {
+ return false;
+ }
+
+ stat.setLooptype(DoStatement.LOOP_FOR);
+ if (hasinit) {
+ stat.setInitExprent(preData.getExprents().remove(preData.getExprents().size() - 1));
+ }
+ stat.setIncExprent(lastData.getExprents().remove(lastData.getExprents().size() - 1));
+ }
+
+ if (lastData.getExprents().isEmpty()) {
+ List<StatEdge> lst = lastData.getAllSuccessorEdges();
+ if (!lst.isEmpty()) {
+ lastData.removeSuccessor(lst.get(0));
+ }
+ removeLastEmptyStatement(stat, lastData);
+ }
+
+ return true;
+ }
+
+ private static void removeLastEmptyStatement(DoStatement dostat, Statement stat) {
+
+ if (stat == dostat.getFirst()) {
+ BasicBlockStatement bstat = new BasicBlockStatement(new BasicBlock(
+ DecompilerContext.getCounterContainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER)));
+ bstat.setExprents(new ArrayList<Exprent>());
+ dostat.replaceStatement(stat, bstat);
+ }
+ else {
+ for (StatEdge edge : stat.getAllPredecessorEdges()) {
+ edge.getSource().changeEdgeType(Statement.DIRECTION_FORWARD, edge, StatEdge.TYPE_CONTINUE);
+
+ stat.removePredecessor(edge);
+ edge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, edge, dostat);
+ dostat.addPredecessor(edge);
+
+ dostat.addLabeledEdge(edge);
+ }
+
+ // parent is a sequence statement
+ stat.getParent().getStats().removeWithKey(stat.id);
+ }
+ }
+
+ private static Statement getLastDirectData(Statement stat) {
+
+ if (stat.getExprents() != null) {
+ return stat;
+ }
+
+ switch (stat.type) {
+ case Statement.TYPE_SEQUENCE:
+ for (int i = stat.getStats().size() - 1; i >= 0; i--) {
+ Statement tmp = getLastDirectData(stat.getStats().get(i));
+ if (tmp == null || !tmp.getExprents().isEmpty()) {
+ return tmp;
+ }
+ }
+ }
+ return null;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/PPandMMHelper.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/PPandMMHelper.java
new file mode 100644
index 000000000000..aacb61f339ab
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/PPandMMHelper.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler;
+
+import org.jetbrains.java.decompiler.modules.decompiler.exps.AssignmentExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.ConstExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.FunctionExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectGraph;
+import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectNode;
+import org.jetbrains.java.decompiler.modules.decompiler.sforms.FlattenStatementsHelper;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+
+public class PPandMMHelper {
+
+ private boolean exprentReplaced;
+
+ public boolean findPPandMM(RootStatement root) {
+
+ FlattenStatementsHelper flatthelper = new FlattenStatementsHelper();
+ DirectGraph dgraph = flatthelper.buildDirectGraph(root);
+
+ LinkedList<DirectNode> stack = new LinkedList<DirectNode>();
+ stack.add(dgraph.first);
+
+ HashSet<DirectNode> setVisited = new HashSet<DirectNode>();
+
+ boolean res = false;
+
+ while (!stack.isEmpty()) {
+
+ DirectNode node = stack.removeFirst();
+
+ if (setVisited.contains(node)) {
+ continue;
+ }
+ setVisited.add(node);
+
+ res |= processExprentList(node.exprents);
+
+ stack.addAll(node.succs);
+ }
+
+ return res;
+ }
+
+ private boolean processExprentList(List<Exprent> lst) {
+
+ boolean result = false;
+
+ for (int i = 0; i < lst.size(); i++) {
+ Exprent exprent = lst.get(i);
+ exprentReplaced = false;
+
+ Exprent retexpr = processExprentRecursive(exprent);
+ if (retexpr != null) {
+ lst.set(i, retexpr);
+
+ result = true;
+ i--; // process the same exprent again
+ }
+
+ result |= exprentReplaced;
+ }
+
+ return result;
+ }
+
+ private Exprent processExprentRecursive(Exprent exprent) {
+
+ boolean replaced = true;
+ while (replaced) {
+ replaced = false;
+
+ for (Exprent expr : exprent.getAllExprents()) {
+ Exprent retexpr = processExprentRecursive(expr);
+ if (retexpr != null) {
+ exprent.replaceExprent(expr, retexpr);
+ replaced = true;
+ exprentReplaced = true;
+ break;
+ }
+ }
+ }
+
+ if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent as = (AssignmentExprent)exprent;
+
+ if (as.getRight().type == Exprent.EXPRENT_FUNCTION) {
+ FunctionExprent func = (FunctionExprent)as.getRight();
+
+ VarType midlayer = null;
+ if (func.getFunctype() >= FunctionExprent.FUNCTION_I2L &&
+ func.getFunctype() <= FunctionExprent.FUNCTION_I2S) {
+ midlayer = func.getSimpleCastType();
+ if (func.getLstOperands().get(0).type == Exprent.EXPRENT_FUNCTION) {
+ func = (FunctionExprent)func.getLstOperands().get(0);
+ }
+ else {
+ return null;
+ }
+ }
+
+ if (func.getFunctype() == FunctionExprent.FUNCTION_ADD ||
+ func.getFunctype() == FunctionExprent.FUNCTION_SUB) {
+ Exprent econd = func.getLstOperands().get(0);
+ Exprent econst = func.getLstOperands().get(1);
+
+ if (econst.type != Exprent.EXPRENT_CONST && econd.type == Exprent.EXPRENT_CONST &&
+ func.getFunctype() == FunctionExprent.FUNCTION_ADD) {
+ econd = econst;
+ econst = func.getLstOperands().get(0);
+ }
+
+ if (econst.type == Exprent.EXPRENT_CONST && ((ConstExprent)econst).hasValueOne()) {
+ Exprent left = as.getLeft();
+
+ VarType condtype = econd.getExprType();
+ if (left.equals(econd) && (midlayer == null || midlayer.equals(condtype))) {
+ FunctionExprent ret = new FunctionExprent(
+ func.getFunctype() == FunctionExprent.FUNCTION_ADD ? FunctionExprent.FUNCTION_PPI : FunctionExprent.FUNCTION_MMI,
+ Arrays.asList(new Exprent[]{econd}));
+ ret.setImplicitType(condtype);
+
+ exprentReplaced = true;
+ return ret;
+ }
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/PrimitiveExprsList.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/PrimitiveExprsList.java
new file mode 100644
index 000000000000..6dbc887e348b
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/PrimitiveExprsList.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler;
+
+import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class PrimitiveExprsList {
+
+ private List<Exprent> lstExprents = new ArrayList<Exprent>();
+
+ private ExprentStack stack = new ExprentStack();
+
+ public PrimitiveExprsList() {
+ }
+
+ public PrimitiveExprsList copyStack() {
+ PrimitiveExprsList prlst = new PrimitiveExprsList();
+ prlst.setStack(stack.clone());
+ return prlst;
+ }
+
+ public List<Exprent> getLstExprents() {
+ return lstExprents;
+ }
+
+ public ExprentStack getStack() {
+ return stack;
+ }
+
+ public void setStack(ExprentStack stack) {
+ this.stack = stack;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/SecondaryFunctionsHelper.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/SecondaryFunctionsHelper.java
new file mode 100644
index 000000000000..5643f228e024
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/SecondaryFunctionsHelper.java
@@ -0,0 +1,432 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.IfStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar;
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+
+public class SecondaryFunctionsHelper {
+
+ private static final int[] funcsnot = new int[]{
+ FunctionExprent.FUNCTION_NE,
+ FunctionExprent.FUNCTION_EQ,
+ FunctionExprent.FUNCTION_GE,
+ FunctionExprent.FUNCTION_LT,
+ FunctionExprent.FUNCTION_LE,
+ FunctionExprent.FUNCTION_GT,
+ FunctionExprent.FUNCTION_COR,
+ FunctionExprent.FUNCTION_CADD
+ };
+
+ private static final HashMap<Integer, Integer[]> mapNumComparisons = new HashMap<Integer, Integer[]>();
+
+ static {
+ mapNumComparisons.put(FunctionExprent.FUNCTION_EQ,
+ new Integer[]{FunctionExprent.FUNCTION_LT, FunctionExprent.FUNCTION_EQ, FunctionExprent.FUNCTION_GT});
+ mapNumComparisons.put(FunctionExprent.FUNCTION_NE,
+ new Integer[]{FunctionExprent.FUNCTION_GE, FunctionExprent.FUNCTION_NE, FunctionExprent.FUNCTION_LE});
+ mapNumComparisons.put(FunctionExprent.FUNCTION_GT, new Integer[]{FunctionExprent.FUNCTION_GE, FunctionExprent.FUNCTION_GT, null});
+ mapNumComparisons.put(FunctionExprent.FUNCTION_GE, new Integer[]{null, FunctionExprent.FUNCTION_GE, FunctionExprent.FUNCTION_GT});
+ mapNumComparisons.put(FunctionExprent.FUNCTION_LT, new Integer[]{null, FunctionExprent.FUNCTION_LT, FunctionExprent.FUNCTION_LE});
+ mapNumComparisons.put(FunctionExprent.FUNCTION_LE, new Integer[]{FunctionExprent.FUNCTION_LT, FunctionExprent.FUNCTION_LE, null});
+ }
+
+
+ public static boolean identifySecondaryFunctions(Statement stat) {
+
+ if (stat.getExprents() == null) {
+ // if(){;}else{...} -> if(!){...}
+ if (stat.type == Statement.TYPE_IF) {
+ IfStatement ifelsestat = (IfStatement)stat;
+ Statement ifstat = ifelsestat.getIfstat();
+
+ if (ifelsestat.iftype == IfStatement.IFTYPE_IFELSE && ifstat.getExprents() != null &&
+ ifstat.getExprents().isEmpty() && (ifstat.getAllSuccessorEdges().isEmpty() || !ifstat.getAllSuccessorEdges().get(0).explicit)) {
+
+ // move else to the if position
+ ifelsestat.getStats().removeWithKey(ifstat.id);
+
+ ifelsestat.iftype = IfStatement.IFTYPE_IF;
+ ifelsestat.setIfstat(ifelsestat.getElsestat());
+ ifelsestat.setElsestat(null);
+
+ if (ifelsestat.getAllSuccessorEdges().isEmpty() && !ifstat.getAllSuccessorEdges().isEmpty()) {
+ StatEdge endedge = ifstat.getAllSuccessorEdges().get(0);
+
+ ifstat.removeSuccessor(endedge);
+ endedge.setSource(ifelsestat);
+ if (endedge.closure != null) {
+ ifelsestat.getParent().addLabeledEdge(endedge);
+ }
+ ifelsestat.addSuccessor(endedge);
+ }
+
+ ifelsestat.getFirst().removeSuccessor(ifelsestat.getIfEdge());
+
+ ifelsestat.setIfEdge(ifelsestat.getElseEdge());
+ ifelsestat.setElseEdge(null);
+
+ // negate head expression
+ ifelsestat.setNegated(!ifelsestat.isNegated());
+ ifelsestat.getHeadexprentList().set(0, ((IfExprent)ifelsestat.getHeadexprent().copy()).negateIf());
+
+ return true;
+ }
+ }
+ }
+
+
+ boolean replaced = true;
+ while (replaced) {
+ replaced = false;
+
+ List<Object> lstObjects = new ArrayList<Object>(stat.getExprents() == null ? stat.getSequentialObjects() : stat.getExprents());
+
+ for (int i = 0; i < lstObjects.size(); i++) {
+ Object obj = lstObjects.get(i);
+
+ if (obj instanceof Statement) {
+ if (identifySecondaryFunctions((Statement)obj)) {
+ replaced = true;
+ break;
+ }
+ }
+ else if (obj instanceof Exprent) {
+ Exprent retexpr = identifySecondaryFunctions((Exprent)obj, true);
+ if (retexpr != null) {
+ if (stat.getExprents() == null) {
+ // only head expressions can be replaced!
+ stat.replaceExprent((Exprent)obj, retexpr);
+ }
+ else {
+ stat.getExprents().set(i, retexpr);
+ }
+ replaced = true;
+ break;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+
+ private static Exprent identifySecondaryFunctions(Exprent exprent, boolean statement_level) {
+
+ if (exprent.type == Exprent.EXPRENT_FUNCTION) {
+ FunctionExprent fexpr = (FunctionExprent)exprent;
+
+ switch (fexpr.getFunctype()) {
+ case FunctionExprent.FUNCTION_BOOLNOT:
+
+ Exprent retparam = propagateBoolNot(fexpr);
+
+ if (retparam != null) {
+ return retparam;
+ }
+
+ break;
+ case FunctionExprent.FUNCTION_EQ:
+ case FunctionExprent.FUNCTION_NE:
+ case FunctionExprent.FUNCTION_GT:
+ case FunctionExprent.FUNCTION_GE:
+ case FunctionExprent.FUNCTION_LT:
+ case FunctionExprent.FUNCTION_LE:
+ Exprent expr1 = fexpr.getLstOperands().get(0);
+ Exprent expr2 = fexpr.getLstOperands().get(1);
+
+ if (expr1.type == Exprent.EXPRENT_CONST) {
+ expr2 = expr1;
+ expr1 = fexpr.getLstOperands().get(1);
+ }
+
+ if (expr1.type == Exprent.EXPRENT_FUNCTION && expr2.type == Exprent.EXPRENT_CONST) {
+ FunctionExprent funcexpr = (FunctionExprent)expr1;
+ ConstExprent cexpr = (ConstExprent)expr2;
+
+ int functype = funcexpr.getFunctype();
+ if (functype == FunctionExprent.FUNCTION_LCMP || functype == FunctionExprent.FUNCTION_FCMPG ||
+ functype == FunctionExprent.FUNCTION_FCMPL || functype == FunctionExprent.FUNCTION_DCMPG ||
+ functype == FunctionExprent.FUNCTION_DCMPL) {
+
+ int desttype = -1;
+
+ Integer[] destcons = mapNumComparisons.get(fexpr.getFunctype());
+ if (destcons != null) {
+ int index = cexpr.getIntValue() + 1;
+ if (index >= 0 && index <= 2) {
+ Integer destcon = destcons[index];
+ if (destcon != null) {
+ desttype = destcon.intValue();
+ }
+ }
+ }
+
+ if (desttype >= 0) {
+ return new FunctionExprent(desttype, funcexpr.getLstOperands());
+ }
+ }
+ }
+ }
+ }
+
+
+ boolean replaced = true;
+ while (replaced) {
+ replaced = false;
+
+ for (Exprent expr : exprent.getAllExprents()) {
+ Exprent retexpr = identifySecondaryFunctions(expr, false);
+ if (retexpr != null) {
+ exprent.replaceExprent(expr, retexpr);
+ replaced = true;
+ break;
+ }
+ }
+ }
+
+ switch (exprent.type) {
+ case Exprent.EXPRENT_FUNCTION:
+ FunctionExprent fexpr = (FunctionExprent)exprent;
+ List<Exprent> lstOperands = fexpr.getLstOperands();
+
+ switch (fexpr.getFunctype()) {
+ case FunctionExprent.FUNCTION_XOR:
+ for (int i = 0; i < 2; i++) {
+ Exprent operand = lstOperands.get(i);
+ VarType operandtype = operand.getExprType();
+
+ if (operand.type == Exprent.EXPRENT_CONST &&
+ operandtype.type != CodeConstants.TYPE_BOOLEAN) {
+ ConstExprent cexpr = (ConstExprent)operand;
+ long val;
+ if (operandtype.type == CodeConstants.TYPE_LONG) {
+ val = ((Long)cexpr.getValue()).longValue();
+ }
+ else {
+ val = ((Integer)cexpr.getValue()).intValue();
+ }
+
+ if (val == -1) {
+ List<Exprent> lstBitNotOperand = new ArrayList<Exprent>();
+ lstBitNotOperand.add(lstOperands.get(1 - i));
+ return new FunctionExprent(FunctionExprent.FUNCTION_BITNOT, lstBitNotOperand);
+ }
+ }
+ }
+ break;
+ case FunctionExprent.FUNCTION_EQ:
+ case FunctionExprent.FUNCTION_NE:
+ if (lstOperands.get(0).getExprType().type == CodeConstants.TYPE_BOOLEAN &&
+ lstOperands.get(1).getExprType().type == CodeConstants.TYPE_BOOLEAN) {
+ for (int i = 0; i < 2; i++) {
+ if (lstOperands.get(i).type == Exprent.EXPRENT_CONST) {
+ ConstExprent cexpr = (ConstExprent)lstOperands.get(i);
+ int val = ((Integer)cexpr.getValue()).intValue();
+
+ if ((fexpr.getFunctype() == FunctionExprent.FUNCTION_EQ && val == 1) ||
+ (fexpr.getFunctype() == FunctionExprent.FUNCTION_NE && val == 0)) {
+ return lstOperands.get(1 - i);
+ }
+ else {
+ List<Exprent> lstNotOperand = new ArrayList<Exprent>();
+ lstNotOperand.add(lstOperands.get(1 - i));
+ return new FunctionExprent(FunctionExprent.FUNCTION_BOOLNOT, lstNotOperand);
+ }
+ }
+ }
+ }
+ break;
+ case FunctionExprent.FUNCTION_BOOLNOT:
+ if (lstOperands.get(0).type == Exprent.EXPRENT_CONST) {
+ int val = ((ConstExprent)lstOperands.get(0)).getIntValue();
+ if (val == 0) {
+ return new ConstExprent(VarType.VARTYPE_BOOLEAN, new Integer(1));
+ }
+ else {
+ return new ConstExprent(VarType.VARTYPE_BOOLEAN, new Integer(0));
+ }
+ }
+ break;
+ case FunctionExprent.FUNCTION_IIF:
+ Exprent expr1 = lstOperands.get(1);
+ Exprent expr2 = lstOperands.get(2);
+
+ if (expr1.type == Exprent.EXPRENT_CONST && expr2.type == Exprent.EXPRENT_CONST) {
+ ConstExprent cexpr1 = (ConstExprent)expr1;
+ ConstExprent cexpr2 = (ConstExprent)expr2;
+
+ if (cexpr1.getExprType().type == CodeConstants.TYPE_BOOLEAN &&
+ cexpr2.getExprType().type == CodeConstants.TYPE_BOOLEAN) {
+
+ if (cexpr1.getIntValue() == 0 && cexpr2.getIntValue() != 0) {
+ return new FunctionExprent(FunctionExprent.FUNCTION_BOOLNOT, Arrays.asList(new Exprent[]{lstOperands.get(0)}));
+ }
+ else if (cexpr1.getIntValue() != 0 && cexpr2.getIntValue() == 0) {
+ return lstOperands.get(0);
+ }
+ }
+ }
+ break;
+ case FunctionExprent.FUNCTION_LCMP:
+ case FunctionExprent.FUNCTION_FCMPL:
+ case FunctionExprent.FUNCTION_FCMPG:
+ case FunctionExprent.FUNCTION_DCMPL:
+ case FunctionExprent.FUNCTION_DCMPG:
+ int var = DecompilerContext.getCounterContainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER);
+ VarType type = lstOperands.get(0).getExprType();
+ VarProcessor processor = (VarProcessor)DecompilerContext.getProperty(DecompilerContext.CURRENT_VAR_PROCESSOR);
+
+ FunctionExprent iff = new FunctionExprent(FunctionExprent.FUNCTION_IIF, Arrays.asList(new Exprent[]{
+ new FunctionExprent(FunctionExprent.FUNCTION_LT, Arrays.asList(new Exprent[]{new VarExprent(var, type, processor),
+ ConstExprent.getZeroConstant(type.type)})),
+ new ConstExprent(VarType.VARTYPE_INT, new Integer(-1)),
+ new ConstExprent(VarType.VARTYPE_INT, new Integer(1))}));
+
+ FunctionExprent head = new FunctionExprent(FunctionExprent.FUNCTION_EQ, Arrays.asList(new Exprent[]{
+ new AssignmentExprent(new VarExprent(var, type, processor), new FunctionExprent(FunctionExprent.FUNCTION_SUB,
+ Arrays.asList(
+ new Exprent[]{lstOperands.get(0),
+ lstOperands.get(1)}))),
+ ConstExprent.getZeroConstant(type.type)}));
+
+ processor.setVarType(new VarVersionPaar(var, 0), type);
+
+ return new FunctionExprent(FunctionExprent.FUNCTION_IIF, Arrays.asList(new Exprent[]{
+ head, new ConstExprent(VarType.VARTYPE_INT, new Integer(0)), iff}));
+ }
+ break;
+ case Exprent.EXPRENT_ASSIGNMENT: // check for conditional assignment
+ AssignmentExprent asexpr = (AssignmentExprent)exprent;
+ Exprent right = asexpr.getRight();
+ Exprent left = asexpr.getLeft();
+
+ if (right.type == Exprent.EXPRENT_FUNCTION) {
+ FunctionExprent func = (FunctionExprent)right;
+
+ VarType midlayer = null;
+ if (func.getFunctype() >= FunctionExprent.FUNCTION_I2L &&
+ func.getFunctype() <= FunctionExprent.FUNCTION_I2S) {
+ right = func.getLstOperands().get(0);
+ midlayer = func.getSimpleCastType();
+ if (right.type == Exprent.EXPRENT_FUNCTION) {
+ func = (FunctionExprent)right;
+ }
+ else {
+ return null;
+ }
+ }
+
+ List<Exprent> lstFuncOperands = func.getLstOperands();
+
+ Exprent cond = null;
+
+ switch (func.getFunctype()) {
+ case FunctionExprent.FUNCTION_ADD:
+ case FunctionExprent.FUNCTION_AND:
+ case FunctionExprent.FUNCTION_OR:
+ case FunctionExprent.FUNCTION_XOR:
+ if (left.equals(lstFuncOperands.get(1))) {
+ cond = lstFuncOperands.get(0);
+ break;
+ }
+ case FunctionExprent.FUNCTION_SUB:
+ case FunctionExprent.FUNCTION_MUL:
+ case FunctionExprent.FUNCTION_DIV:
+ case FunctionExprent.FUNCTION_REM:
+ case FunctionExprent.FUNCTION_SHL:
+ case FunctionExprent.FUNCTION_SHR:
+ case FunctionExprent.FUNCTION_USHR:
+ if (left.equals(lstFuncOperands.get(0))) {
+ cond = lstFuncOperands.get(1);
+ }
+ }
+
+ if (cond != null && (midlayer == null || midlayer.equals(cond.getExprType()))) {
+ asexpr.setRight(cond);
+ asexpr.setCondtype(func.getFunctype());
+ }
+ }
+ break;
+ case Exprent.EXPRENT_INVOCATION:
+ if (!statement_level) { // simplify if exprent is a real expression. The opposite case is pretty absurd, can still happen however (and happened at least once).
+ Exprent retexpr = ConcatenationHelper.contractStringConcat(exprent);
+ if (!exprent.equals(retexpr)) {
+ return retexpr;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public static Exprent propagateBoolNot(Exprent exprent) {
+
+ if (exprent.type == Exprent.EXPRENT_FUNCTION) {
+ FunctionExprent fexpr = (FunctionExprent)exprent;
+
+ if (fexpr.getFunctype() == FunctionExprent.FUNCTION_BOOLNOT) {
+
+ Exprent param = fexpr.getLstOperands().get(0);
+
+ if (param.type == Exprent.EXPRENT_FUNCTION) {
+ FunctionExprent fparam = (FunctionExprent)param;
+
+ int ftype = fparam.getFunctype();
+ switch (ftype) {
+ case FunctionExprent.FUNCTION_BOOLNOT:
+ Exprent newexpr = fparam.getLstOperands().get(0);
+ Exprent retexpr = propagateBoolNot(newexpr);
+ return retexpr == null ? newexpr : retexpr;
+ case FunctionExprent.FUNCTION_CADD:
+ case FunctionExprent.FUNCTION_COR:
+ List<Exprent> operands = fparam.getLstOperands();
+ for (int i = 0; i < operands.size(); i++) {
+ Exprent newparam = new FunctionExprent(FunctionExprent.FUNCTION_BOOLNOT,
+ Arrays.asList(new Exprent[]{operands.get(i)}));
+
+ Exprent retparam = propagateBoolNot(newparam);
+ operands.set(i, retparam == null ? newparam : retparam);
+ }
+ case FunctionExprent.FUNCTION_EQ:
+ case FunctionExprent.FUNCTION_NE:
+ case FunctionExprent.FUNCTION_LT:
+ case FunctionExprent.FUNCTION_GE:
+ case FunctionExprent.FUNCTION_GT:
+ case FunctionExprent.FUNCTION_LE:
+ fparam.setFunctype(funcsnot[ftype - FunctionExprent.FUNCTION_EQ]);
+ return fparam;
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/SequenceHelper.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/SequenceHelper.java
new file mode 100644
index 000000000000..063d201f81f0
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/SequenceHelper.java
@@ -0,0 +1,327 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler;
+
+import org.jetbrains.java.decompiler.code.cfg.BasicBlock;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.BasicBlockStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.SequenceStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+
+
+public class SequenceHelper {
+
+
+ public static void condenseSequences(Statement root) {
+ condenseSequencesRec(root);
+ }
+
+ private static void condenseSequencesRec(Statement stat) {
+
+ if (stat.type == Statement.TYPE_SEQUENCE) {
+
+ List<Statement> lst = new ArrayList<Statement>();
+ lst.addAll(stat.getStats());
+
+ boolean unfolded = false;
+
+ // unfold blocks
+ for (int i = 0; i < lst.size(); i++) {
+ Statement st = lst.get(i);
+ if (st.type == Statement.TYPE_SEQUENCE) {
+
+ removeEmptyStatements((SequenceStatement)st);
+
+ if (i == lst.size() - 1 || isSequenceDisbandable(st, lst.get(i + 1))) {
+ // move predecessors
+ Statement first = st.getFirst();
+ for (StatEdge edge : st.getAllPredecessorEdges()) {
+ st.removePredecessor(edge);
+ edge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, edge, first);
+ first.addPredecessor(edge);
+ }
+
+ // move successors
+ Statement last = st.getStats().getLast();
+ if (last.getAllSuccessorEdges().isEmpty() && i < lst.size() - 1) {
+ last.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, last, lst.get(i + 1)));
+ }
+ else {
+ for (StatEdge edge : last.getAllSuccessorEdges()) {
+ if (i == lst.size() - 1) {
+ if (edge.closure == st) {
+ stat.addLabeledEdge(edge);
+ }
+ }
+ else {
+ edge.getSource().changeEdgeType(Statement.DIRECTION_FORWARD, edge, StatEdge.TYPE_REGULAR);
+ edge.closure.getLabelEdges().remove(edge);
+ edge.closure = null;
+ }
+ }
+ }
+
+ for (StatEdge edge : st.getAllSuccessorEdges()) {
+ st.removeSuccessor(edge);
+ }
+
+ for (StatEdge edge : new HashSet<StatEdge>(st.getLabelEdges())) {
+ if (edge.getSource() != last) {
+ last.addLabeledEdge(edge);
+ }
+ }
+
+ lst.remove(i);
+ lst.addAll(i, st.getStats());
+ i--;
+
+ unfolded = true;
+ }
+ }
+ }
+
+ if (unfolded) {
+ SequenceStatement sequence = new SequenceStatement(lst);
+ sequence.setAllParent();
+
+ stat.getParent().replaceStatement(stat, sequence);
+
+ stat = sequence;
+ }
+ }
+
+ // sequence consisting of one statement -> disband
+ if (stat.type == Statement.TYPE_SEQUENCE) {
+
+ removeEmptyStatements((SequenceStatement)stat);
+
+ if (stat.getStats().size() == 1) {
+
+ Statement st = stat.getFirst();
+
+ boolean ok = st.getAllSuccessorEdges().isEmpty();
+ if (!ok) {
+ StatEdge edge = st.getAllSuccessorEdges().get(0);
+
+ ok = stat.getAllSuccessorEdges().isEmpty();
+ if (!ok) {
+ StatEdge statedge = stat.getAllSuccessorEdges().get(0);
+ ok = (edge.getDestination() == statedge.getDestination());
+
+ if (ok) {
+ st.removeSuccessor(edge);
+ }
+ }
+ }
+
+ if (ok) {
+ stat.getParent().replaceStatement(stat, st);
+ stat = st;
+ }
+ }
+ }
+
+ // replace flat statements with synthetic basic blocks
+ outer:
+ while (true) {
+ for (Statement st : stat.getStats()) {
+ if ((st.getStats().isEmpty() || st.getExprents() != null) && st.type != Statement.TYPE_BASICBLOCK) {
+ destroyAndFlattenStatement(st);
+ continue outer;
+ }
+ }
+ break;
+ }
+
+ // recursion
+ for (int i = 0; i < stat.getStats().size(); i++) {
+ condenseSequencesRec(stat.getStats().get(i));
+ }
+ }
+
+ private static boolean isSequenceDisbandable(Statement block, Statement next) {
+
+ Statement last = block.getStats().getLast();
+ List<StatEdge> lstSuccs = last.getAllSuccessorEdges();
+ if (!lstSuccs.isEmpty()) {
+ if (lstSuccs.get(0).getDestination() != next) {
+ return false;
+ }
+ }
+
+ for (StatEdge edge : next.getPredecessorEdges(StatEdge.TYPE_BREAK)) {
+ if (last != edge.getSource() && !last.containsStatementStrict(edge.getSource())) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private static void removeEmptyStatements(SequenceStatement sequence) {
+
+ if (sequence.getStats().size() <= 1) {
+ return;
+ }
+
+ mergeFlatStatements(sequence);
+
+ while (true) {
+
+ boolean found = false;
+
+ for (Statement st : sequence.getStats()) {
+
+ if (st.getExprents() != null && st.getExprents().isEmpty()) {
+
+ if (st.getAllSuccessorEdges().isEmpty()) {
+ List<StatEdge> lstBreaks = st.getPredecessorEdges(StatEdge.TYPE_BREAK);
+
+ if (lstBreaks.isEmpty()) {
+ for (StatEdge edge : st.getAllPredecessorEdges()) {
+ edge.getSource().removeSuccessor(edge);
+ }
+ found = true;
+ }
+ }
+ else {
+ StatEdge sucedge = st.getAllSuccessorEdges().get(0);
+ if (sucedge.getType() != StatEdge.TYPE_FINALLYEXIT) {
+ st.removeSuccessor(sucedge);
+
+ for (StatEdge edge : st.getAllPredecessorEdges()) {
+ if (sucedge.getType() != StatEdge.TYPE_REGULAR) {
+ edge.getSource().changeEdgeType(Statement.DIRECTION_FORWARD, edge, sucedge.getType());
+ }
+
+ st.removePredecessor(edge);
+ edge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, edge, sucedge.getDestination());
+ sucedge.getDestination().addPredecessor(edge);
+
+ if (sucedge.closure != null) {
+ sucedge.closure.addLabeledEdge(edge);
+ }
+ }
+ found = true;
+ }
+ }
+
+ if (found) {
+ sequence.getStats().removeWithKey(st.id);
+ break;
+ }
+ }
+ }
+
+ if (!found) {
+ break;
+ }
+ }
+
+ sequence.setFirst(sequence.getStats().get(0));
+ }
+
+ private static void mergeFlatStatements(SequenceStatement sequence) {
+
+ while (true) {
+
+ Statement next = null;
+ Statement current = null;
+
+ boolean found = false;
+
+ for (int i = sequence.getStats().size() - 1; i >= 0; i--) {
+
+ next = current;
+ current = sequence.getStats().get(i);
+
+ if (next != null && current.getExprents() != null && !current.getExprents().isEmpty()) {
+ if (next.getExprents() != null) {
+ next.getExprents().addAll(0, current.getExprents());
+ current.getExprents().clear();
+ found = true;
+ }
+ else {
+ Statement first = getFirstExprentlist(next);
+ if (first != null) {
+ first.getExprents().addAll(0, current.getExprents());
+ current.getExprents().clear();
+ found = true;
+ }
+ }
+ }
+ }
+
+ if (!found) {
+ break;
+ }
+ }
+ }
+
+ private static Statement getFirstExprentlist(Statement stat) {
+
+ if (stat.getExprents() != null) {
+ return stat;
+ }
+
+ switch (stat.type) {
+ case Statement.TYPE_IF:
+ case Statement.TYPE_SEQUENCE:
+ case Statement.TYPE_SWITCH:
+ case Statement.TYPE_SYNCRONIZED:
+ return getFirstExprentlist(stat.getFirst());
+ }
+
+ return null;
+ }
+
+
+ public static void destroyAndFlattenStatement(Statement stat) {
+
+ destroyStatementContent(stat, false);
+
+ BasicBlockStatement bstat = new BasicBlockStatement(new BasicBlock(
+ DecompilerContext.getCounterContainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER)));
+ if (stat.getExprents() == null) {
+ bstat.setExprents(new ArrayList<Exprent>());
+ }
+ else {
+ bstat.setExprents(DecHelper.copyExprentList(stat.getExprents()));
+ }
+
+ stat.getParent().replaceStatement(stat, bstat);
+ }
+
+ public static void destroyStatementContent(Statement stat, boolean self) {
+
+ for (Statement st : stat.getStats()) {
+ destroyStatementContent(st, true);
+ }
+ stat.getStats().clear();
+
+ if (self) {
+ for (StatEdge edge : stat.getAllSuccessorEdges()) {
+ stat.removeSuccessor(edge);
+ }
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/SimplifyExprentsHelper.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/SimplifyExprentsHelper.java
new file mode 100644
index 000000000000..90ebe2f8218d
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/SimplifyExprentsHelper.java
@@ -0,0 +1,853 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
+import org.jetbrains.java.decompiler.modules.decompiler.sforms.SSAConstructorSparseEx;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.IfStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar;
+import org.jetbrains.java.decompiler.struct.StructClass;
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+import org.jetbrains.java.decompiler.util.FastSparseSetFactory.FastSparseSet;
+
+import java.util.*;
+import java.util.Map.Entry;
+
+public class SimplifyExprentsHelper {
+
+ private boolean firstInvocation;
+
+ public SimplifyExprentsHelper(boolean firstInvocation) {
+ this.firstInvocation = firstInvocation;
+ }
+
+ public boolean simplifyStackVarsStatement(Statement stat, HashSet<Integer> setReorderedIfs, SSAConstructorSparseEx ssa, StructClass cl) {
+
+ boolean res = false;
+
+ if (stat.getExprents() == null) {
+
+ while (true) {
+
+ boolean changed = false;
+
+ for (Statement st : stat.getStats()) {
+ res |= simplifyStackVarsStatement(st, setReorderedIfs, ssa, cl);
+
+ // collapse composed if's
+ if (changed = IfHelper.mergeIfs(st, setReorderedIfs)) {
+ break;
+ }
+
+ // collapse iff ?: statement
+ if (changed = buildIff(st, ssa)) {
+ break;
+ }
+ }
+
+ res |= changed;
+
+ if (!changed) {
+ break;
+ }
+ }
+ }
+ else {
+ res |= simplifyStackVarsExprents(stat.getExprents(), cl);
+ }
+
+ return res;
+ }
+
+ private boolean simplifyStackVarsExprents(List<Exprent> list, StructClass cl) {
+
+ boolean res = false;
+
+ int index = 0;
+
+ while (index < list.size()) {
+
+ Exprent current = list.get(index);
+
+ Exprent ret = isSimpleConstructorInvocation(current);
+ if (ret != null) {
+ list.set(index, ret);
+ res = true;
+
+ continue;
+ }
+
+ // lambda expression (Java 8)
+ ret = isLambda(current, cl);
+ if (ret != null) {
+ list.set(index, ret);
+ res = true;
+
+ continue;
+ }
+
+ // remove monitor exit
+ if (isMonitorExit(current)) {
+ list.remove(index);
+ res = true;
+
+ continue;
+ }
+
+ // trivial assignment of a stack variable
+ if (isTrivialStackAssignment(current)) {
+ list.remove(index);
+ res = true;
+
+ continue;
+ }
+
+ if (index == list.size() - 1) {
+ break;
+ }
+
+
+ Exprent next = list.get(index + 1);
+
+
+ // constructor invocation
+ if (isConstructorInvocationRemote(list, index)) {
+ list.remove(index);
+ res = true;
+
+ continue;
+ }
+
+ // remove getClass() invocation, which is part of a qualified new
+ if (DecompilerContext.getOption(IFernflowerPreferences.REMOVE_GET_CLASS_NEW)) {
+ if (isQualifiedNewGetClass(current, next)) {
+ list.remove(index);
+ res = true;
+
+ continue;
+ }
+ }
+
+ // direct initialization of an array
+ int arrcount = isArrayInitializer(list, index);
+ if (arrcount > 0) {
+ for (int i = 0; i < arrcount; i++) {
+ list.remove(index + 1);
+ }
+ res = true;
+
+ continue;
+ }
+
+ // add array initializer expression
+ if (addArrayInitializer(current, next)) {
+ list.remove(index + 1);
+ res = true;
+
+ continue;
+ }
+
+ // integer ++expr and --expr (except for vars!)
+ Exprent func = isPPIorMMI(current);
+ if (func != null) {
+ list.set(index, func);
+ res = true;
+
+ continue;
+ }
+
+ // expr++ and expr--
+ if (isIPPorIMM(current, next)) {
+ list.remove(index + 1);
+ res = true;
+
+ continue;
+ }
+
+ // assignment on stack
+ if (isStackAssignement(current, next)) {
+ list.remove(index + 1);
+ res = true;
+
+ continue;
+ }
+
+ if (!firstInvocation && isStackAssignement2(current, next)) {
+ list.remove(index + 1);
+ res = true;
+
+ continue;
+ }
+
+ index++;
+ }
+
+ return res;
+ }
+
+ private static boolean addArrayInitializer(Exprent first, Exprent second) {
+
+ if (first.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent as = (AssignmentExprent)first;
+
+ if (as.getRight().type == Exprent.EXPRENT_NEW && as.getLeft().type == Exprent.EXPRENT_VAR) {
+ NewExprent newex = (NewExprent)as.getRight();
+
+ if (!newex.getLstArrayElements().isEmpty()) {
+
+ VarExprent arrvar = (VarExprent)as.getLeft();
+
+ if (second.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent aas = (AssignmentExprent)second;
+ if (aas.getLeft().type == Exprent.EXPRENT_ARRAY) {
+ ArrayExprent arrex = (ArrayExprent)aas.getLeft();
+ if (arrex.getArray().type == Exprent.EXPRENT_VAR && arrvar.equals(arrex.getArray())
+ && arrex.getIndex().type == Exprent.EXPRENT_CONST) {
+
+ int constvalue = ((ConstExprent)arrex.getIndex()).getIntValue();
+
+ if (constvalue < newex.getLstArrayElements().size()) {
+ Exprent init = newex.getLstArrayElements().get(constvalue);
+ if (init.type == Exprent.EXPRENT_CONST) {
+ ConstExprent cinit = (ConstExprent)init;
+
+ VarType arrtype = newex.getNewtype().copy();
+ arrtype.decArrayDim();
+
+ ConstExprent defaultval = ExprProcessor.getDefaultArrayValue(arrtype);
+
+ if (cinit.equals(defaultval)) {
+
+ Exprent tempexpr = aas.getRight();
+
+ if (!tempexpr.containsExprent(arrvar)) {
+ newex.getLstArrayElements().set(constvalue, tempexpr);
+
+ if (tempexpr.type == Exprent.EXPRENT_NEW) {
+ NewExprent tempnewex = (NewExprent)tempexpr;
+ int dims = newex.getNewtype().arraydim;
+ if (dims > 1 && !tempnewex.getLstArrayElements().isEmpty()) {
+ tempnewex.setDirectArrayInit(true);
+ }
+ }
+
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+
+ private static int isArrayInitializer(List<Exprent> list, int index) {
+
+ Exprent current = list.get(index);
+ if (current.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent as = (AssignmentExprent)current;
+
+ if (as.getRight().type == Exprent.EXPRENT_NEW && as.getLeft().type == Exprent.EXPRENT_VAR) {
+ NewExprent newex = (NewExprent)as.getRight();
+
+ if (newex.getExprType().arraydim > 0 && newex.getLstDims().size() == 1 && newex.getLstArrayElements().isEmpty() &&
+ newex.getLstDims().get(0).type == Exprent.EXPRENT_CONST) {
+
+ int size = ((Integer)((ConstExprent)newex.getLstDims().get(0)).getValue()).intValue();
+ if (size == 0) {
+ return 0;
+ }
+
+ VarExprent arrvar = (VarExprent)as.getLeft();
+
+ HashMap<Integer, Exprent> mapInit = new HashMap<Integer, Exprent>();
+
+ int i = 1;
+ while (index + i < list.size() && i <= size) {
+ boolean found = false;
+
+ Exprent expr = list.get(index + i);
+ if (expr.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent aas = (AssignmentExprent)expr;
+ if (aas.getLeft().type == Exprent.EXPRENT_ARRAY) {
+ ArrayExprent arrex = (ArrayExprent)aas.getLeft();
+ if (arrex.getArray().type == Exprent.EXPRENT_VAR && arrvar.equals(arrex.getArray())
+ && arrex.getIndex().type == Exprent.EXPRENT_CONST) {
+
+ int constvalue = ((ConstExprent)arrex.getIndex())
+ .getIntValue(); // TODO: check for a number type. Failure extremely improbable, but nevertheless...
+
+ if (constvalue < size && !mapInit.containsKey(constvalue)) {
+
+ if (!aas.getRight().containsExprent(arrvar)) {
+ mapInit.put(constvalue, aas.getRight());
+ found = true;
+ }
+ }
+ }
+ }
+ }
+
+ if (!found) {
+ break;
+ }
+
+ i++;
+ }
+
+ double fraction = ((double)mapInit.size()) / size;
+
+ if ((arrvar.isStack() && fraction > 0) || (size <= 7 && fraction >= 0.3) ||
+ (size > 7 && fraction >= 0.7)) {
+
+ List<Exprent> lstRet = new ArrayList<Exprent>();
+
+ VarType arrtype = newex.getNewtype().copy();
+ arrtype.decArrayDim();
+
+ ConstExprent defaultval = ExprProcessor.getDefaultArrayValue(arrtype);
+
+ for (int j = 0; j < size; j++) {
+ lstRet.add(defaultval.copy());
+ }
+
+ int dims = newex.getNewtype().arraydim;
+ for (Entry<Integer, Exprent> ent : mapInit.entrySet()) {
+ Exprent tempexpr = ent.getValue();
+ lstRet.set(ent.getKey(), tempexpr);
+
+ if (tempexpr.type == Exprent.EXPRENT_NEW) {
+ NewExprent tempnewex = (NewExprent)tempexpr;
+ if (dims > 1 && !tempnewex.getLstArrayElements().isEmpty()) {
+ tempnewex.setDirectArrayInit(true);
+ }
+ }
+ }
+
+ newex.setLstArrayElements(lstRet);
+
+ return mapInit.size();
+ }
+ }
+ }
+ }
+
+ return 0;
+ }
+
+ private static boolean isTrivialStackAssignment(Exprent first) {
+
+ if (first.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent asf = (AssignmentExprent)first;
+
+ if (asf.getLeft().type == Exprent.EXPRENT_VAR && asf.getRight().type == Exprent.EXPRENT_VAR) {
+ VarExprent varleft = (VarExprent)asf.getLeft();
+ VarExprent varright = (VarExprent)asf.getRight();
+
+ if (varleft.getIndex() == varright.getIndex() && varleft.isStack() &&
+ varright.isStack()) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private static boolean isStackAssignement2(Exprent first, Exprent second) { // e.g. 1.4-style class invocation
+
+ if (first.type == Exprent.EXPRENT_ASSIGNMENT && second.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent asf = (AssignmentExprent)first;
+ AssignmentExprent ass = (AssignmentExprent)second;
+
+ if (asf.getLeft().type == Exprent.EXPRENT_VAR && ass.getRight().type == Exprent.EXPRENT_VAR &&
+ asf.getLeft().equals(ass.getRight()) && ((VarExprent)asf.getLeft()).isStack()) {
+ if (ass.getLeft().type != Exprent.EXPRENT_VAR || !((VarExprent)ass.getLeft()).isStack()) {
+ asf.setRight(new AssignmentExprent(ass.getLeft(), asf.getRight()));
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private static boolean isStackAssignement(Exprent first, Exprent second) {
+
+ if (first.type == Exprent.EXPRENT_ASSIGNMENT && second.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent asf = (AssignmentExprent)first;
+ AssignmentExprent ass = (AssignmentExprent)second;
+
+ while (true) {
+ if (asf.getRight().equals(ass.getRight())) {
+ if ((asf.getLeft().type == Exprent.EXPRENT_VAR && ((VarExprent)asf.getLeft()).isStack()) &&
+ (ass.getLeft().type != Exprent.EXPRENT_VAR || !((VarExprent)ass.getLeft()).isStack())) {
+
+ if (!ass.getLeft().containsExprent(asf.getLeft())) {
+ asf.setRight(ass);
+ return true;
+ }
+ }
+ }
+ if (asf.getRight().type == Exprent.EXPRENT_ASSIGNMENT) {
+ asf = (AssignmentExprent)asf.getRight();
+ }
+ else {
+ break;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private static Exprent isPPIorMMI(Exprent first) {
+
+ if (first.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent as = (AssignmentExprent)first;
+
+ if (as.getRight().type == Exprent.EXPRENT_FUNCTION) {
+ FunctionExprent func = (FunctionExprent)as.getRight();
+
+ if (func.getFunctype() == FunctionExprent.FUNCTION_ADD ||
+ func.getFunctype() == FunctionExprent.FUNCTION_SUB) {
+ Exprent econd = func.getLstOperands().get(0);
+ Exprent econst = func.getLstOperands().get(1);
+
+ if (econst.type != Exprent.EXPRENT_CONST && econd.type == Exprent.EXPRENT_CONST &&
+ func.getFunctype() == FunctionExprent.FUNCTION_ADD) {
+ econd = econst;
+ econst = func.getLstOperands().get(0);
+ }
+
+ if (econst.type == Exprent.EXPRENT_CONST && ((ConstExprent)econst).hasValueOne()) {
+ Exprent left = as.getLeft();
+
+ if (left.type != Exprent.EXPRENT_VAR && left.equals(econd)) {
+ FunctionExprent ret = new FunctionExprent(
+ func.getFunctype() == FunctionExprent.FUNCTION_ADD ? FunctionExprent.FUNCTION_PPI : FunctionExprent.FUNCTION_MMI,
+ Arrays.asList(new Exprent[]{econd}));
+ ret.setImplicitType(VarType.VARTYPE_INT);
+ return ret;
+ }
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private static boolean isIPPorIMM(Exprent first, Exprent second) {
+
+ if (first.type == Exprent.EXPRENT_ASSIGNMENT && second.type == Exprent.EXPRENT_FUNCTION) {
+ AssignmentExprent as = (AssignmentExprent)first;
+ FunctionExprent in = (FunctionExprent)second;
+
+ if ((in.getFunctype() == FunctionExprent.FUNCTION_MMI || in.getFunctype() == FunctionExprent.FUNCTION_PPI) &&
+ in.getLstOperands().get(0).equals(as.getRight())) {
+
+ if (in.getFunctype() == FunctionExprent.FUNCTION_MMI) {
+ in.setFunctype(FunctionExprent.FUNCTION_IMM);
+ }
+ else {
+ in.setFunctype(FunctionExprent.FUNCTION_IPP);
+ }
+ as.setRight(in);
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private static boolean isMonitorExit(Exprent first) {
+ if (first.type == Exprent.EXPRENT_MONITOR) {
+ MonitorExprent monexpr = (MonitorExprent)first;
+ if (monexpr.getMontype() == MonitorExprent.MONITOR_EXIT && monexpr.getValue().type == Exprent.EXPRENT_VAR
+ && !((VarExprent)monexpr.getValue()).isStack()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private static boolean isQualifiedNewGetClass(Exprent first, Exprent second) {
+
+ if (first.type == Exprent.EXPRENT_INVOCATION) {
+ InvocationExprent invexpr = (InvocationExprent)first;
+
+ if (!invexpr.isStatic() && invexpr.getInstance().type == Exprent.EXPRENT_VAR && invexpr.getName().equals("getClass") &&
+ invexpr.getStringDescriptor().equals("()Ljava/lang/Class;")) {
+
+ List<Exprent> lstExprents = second.getAllExprents();
+ lstExprents.add(second);
+
+ for (Exprent expr : lstExprents) {
+ if (expr.type == Exprent.EXPRENT_NEW) {
+ NewExprent nexpr = (NewExprent)expr;
+ if (nexpr.getConstructor() != null && !nexpr.getConstructor().getLstParameters().isEmpty() &&
+ nexpr.getConstructor().getLstParameters().get(0).equals(invexpr.getInstance())) {
+
+ String classname = nexpr.getNewtype().value;
+ ClassNode node = DecompilerContext.getClassProcessor().getMapRootClasses().get(classname);
+ if (node != null && node.type != ClassNode.CLASS_ROOT) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ // private static boolean isConstructorInvocationRemote(List<Exprent> list, int index) {
+ //
+ // Exprent current = list.get(index);
+ //
+ // if(current.type == Exprent.EXPRENT_ASSIGNMENT) {
+ // AssignmentExprent as = (AssignmentExprent)current;
+ //
+ // if(as.getLeft().type == Exprent.EXPRENT_VAR && as.getRight().type == Exprent.EXPRENT_NEW) {
+ //
+ // NewExprent newexpr = (NewExprent)as.getRight();
+ // VarType newtype = newexpr.getNewtype();
+ // VarVersionPaar leftPaar = new VarVersionPaar((VarExprent)as.getLeft());
+ //
+ // if(newtype.type == CodeConstants.TYPE_OBJECT && newtype.arraydim == 0 &&
+ // newexpr.getConstructor() == null) {
+ //
+ // Set<VarVersionPaar> setChangedVars = new HashSet<VarVersionPaar>();
+ //
+ // for(int i = index + 1; i < list.size(); i++) {
+ // Exprent remote = list.get(i);
+ //
+ // if(remote.type == Exprent.EXPRENT_INVOCATION) {
+ // InvocationExprent in = (InvocationExprent)remote;
+ //
+ // if(in.getFunctype() == InvocationExprent.TYP_INIT && in.getInstance().type == Exprent.EXPRENT_VAR
+ // && as.getLeft().equals(in.getInstance())) {
+ //
+ // Set<VarVersionPaar> setVars = remote.getAllVariables();
+ // setVars.remove(leftPaar);
+ // setVars.retainAll(setChangedVars);
+ //
+ // if(setVars.isEmpty()) {
+ //
+ // newexpr.setConstructor(in);
+ // in.setInstance(null);
+ //
+ // if(!setChangedVars.isEmpty()) { // some exprents inbetween
+ // list.add(index+1, as.copy());
+ // list.remove(i+1);
+ // } else {
+ // list.set(i, as.copy());
+ // }
+ //
+ // return true;
+ // }
+ // }
+ // }
+ //
+ // boolean isTempAssignment = false;
+ //
+ // if(remote.type == Exprent.EXPRENT_ASSIGNMENT) { // ugly solution
+ // AssignmentExprent asremote = (AssignmentExprent)remote;
+ // if(asremote.getLeft().type == Exprent.EXPRENT_VAR &&
+ // asremote.getRight().type == Exprent.EXPRENT_VAR) {
+ // setChangedVars.add(new VarVersionPaar((VarExprent)asremote.getLeft()));
+ // isTempAssignment = true;
+ // }
+ //
+ // // FIXME: needs to be rewritten
+ // // propagate (var = new X) forward to the <init> invokation and then reduce
+ //
+ //// if(asremote.getLeft().type == Exprent.EXPRENT_VAR) {
+ //// List<Exprent> lstRightExprents = asremote.getRight().getAllExprents(true);
+ //// lstRightExprents.add(asremote.getRight());
+ ////
+ //// Set<VarVersionPaar> setTempChangedVars = new HashSet<VarVersionPaar>();
+ //// boolean isTemp = true;
+ ////
+ //// for(Exprent expr : lstRightExprents) {
+ //// if(expr.type != Exprent.EXPRENT_VAR && expr.type != Exprent.EXPRENT_FIELD) {
+ //// isTemp = false;
+ //// break;
+ //// } else if(expr.type == Exprent.EXPRENT_VAR) {
+ //// setTempChangedVars.add(new VarVersionPaar((VarExprent)expr));
+ //// }
+ //// }
+ ////
+ //// if(isTemp) {
+ //// setChangedVars.addAll(setTempChangedVars);
+ //// isTempAssignment = true;
+ //// }
+ //// }
+ //// } else if(remote.type == Exprent.EXPRENT_FUNCTION) {
+ //// FunctionExprent fexpr = (FunctionExprent)remote;
+ //// if(fexpr.getFunctype() == FunctionExprent.FUNCTION_IPP || fexpr.getFunctype() == FunctionExprent.FUNCTION_IMM
+ //// || fexpr.getFunctype() == FunctionExprent.FUNCTION_PPI || fexpr.getFunctype() == FunctionExprent.FUNCTION_MMI) {
+ //// if(fexpr.getLstOperands().get(0).type == Exprent.EXPRENT_VAR) {
+ //// setChangedVars.add(new VarVersionPaar((VarExprent)fexpr.getLstOperands().get(0)));
+ //// isTempAssignment = true;
+ //// }
+ //// }
+ // }
+ //
+ // if(!isTempAssignment) {
+ // Set<VarVersionPaar> setVars = remote.getAllVariables();
+ // if(setVars.contains(leftPaar)) {
+ // return false;
+ // } else {
+ // setChangedVars.addAll(setVars);
+ // }
+ // }
+ // }
+ // }
+ // }
+ // }
+ //
+ // return false;
+ // }
+
+ // propagate (var = new X) forward to the <init> invokation
+ private static boolean isConstructorInvocationRemote(List<Exprent> list, int index) {
+
+ Exprent current = list.get(index);
+
+ if (current.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent as = (AssignmentExprent)current;
+
+ if (as.getLeft().type == Exprent.EXPRENT_VAR && as.getRight().type == Exprent.EXPRENT_NEW) {
+
+ NewExprent newexpr = (NewExprent)as.getRight();
+ VarType newtype = newexpr.getNewtype();
+ VarVersionPaar leftPaar = new VarVersionPaar((VarExprent)as.getLeft());
+
+ if (newtype.type == CodeConstants.TYPE_OBJECT && newtype.arraydim == 0 && newexpr.getConstructor() == null) {
+
+ for (int i = index + 1; i < list.size(); i++) {
+ Exprent remote = list.get(i);
+
+ // <init> invocation
+ if (remote.type == Exprent.EXPRENT_INVOCATION) {
+ InvocationExprent in = (InvocationExprent)remote;
+
+ if (in.getFunctype() == InvocationExprent.TYP_INIT &&
+ in.getInstance().type == Exprent.EXPRENT_VAR &&
+ as.getLeft().equals(in.getInstance())) {
+
+ newexpr.setConstructor(in);
+ in.setInstance(null);
+
+ list.set(i, as.copy());
+
+ return true;
+ }
+ }
+
+ // check for variable in use
+ Set<VarVersionPaar> setVars = remote.getAllVariables();
+ if (setVars.contains(leftPaar)) { // variable used somewhere in between -> exit, need a better reduced code
+ return false;
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private static Exprent isLambda(Exprent exprent, StructClass cl) {
+
+ List<Exprent> lst = exprent.getAllExprents();
+ for (Exprent expr : lst) {
+ Exprent ret = isLambda(expr, cl);
+ if (ret != null) {
+ exprent.replaceExprent(expr, ret);
+ }
+ }
+
+ if (exprent.type == Exprent.EXPRENT_INVOCATION) {
+ InvocationExprent in = (InvocationExprent)exprent;
+
+ if (in.getInvocationTyp() == InvocationExprent.INVOKE_DYNAMIC) {
+
+ String lambda_class_name = cl.qualifiedName + in.getInvokeDynamicClassSuffix();
+ ClassNode lambda_class = DecompilerContext.getClassProcessor().getMapRootClasses().get(lambda_class_name);
+
+ if (lambda_class != null) { // real lambda class found, replace invocation with an anonymous class
+
+ NewExprent newexp = new NewExprent(new VarType(lambda_class_name, true), null, 0);
+ newexp.setConstructor(in);
+ // note: we don't set the instance to null with in.setInstance(null) like it is done for a common constructor invokation
+ // lambda can also be a reference to a virtual method (e.g. String x; ...(x::toString);)
+ // in this case instance will hold the corresponding object
+
+ return newexp;
+ }
+ }
+ }
+
+ return null;
+ }
+
+
+ private static Exprent isSimpleConstructorInvocation(Exprent exprent) {
+
+ List<Exprent> lst = exprent.getAllExprents();
+ for (Exprent expr : lst) {
+ Exprent ret = isSimpleConstructorInvocation(expr);
+ if (ret != null) {
+ exprent.replaceExprent(expr, ret);
+ }
+ }
+
+ if (exprent.type == Exprent.EXPRENT_INVOCATION) {
+ InvocationExprent in = (InvocationExprent)exprent;
+ if (in.getFunctype() == InvocationExprent.TYP_INIT && in.getInstance().type == Exprent.EXPRENT_NEW) {
+ NewExprent newexp = (NewExprent)in.getInstance();
+ newexp.setConstructor(in);
+ in.setInstance(null);
+ return newexp;
+ }
+ }
+
+ return null;
+ }
+
+
+ private static boolean buildIff(Statement stat, SSAConstructorSparseEx ssa) {
+
+ if (stat.type == Statement.TYPE_IF && stat.getExprents() == null) {
+ IfStatement stif = (IfStatement)stat;
+ if (stif.iftype == IfStatement.IFTYPE_IFELSE) {
+ Statement ifstat = stif.getIfstat();
+ Statement elsestat = stif.getElsestat();
+
+ if (ifstat.getExprents() != null && ifstat.getExprents().size() == 1
+ && elsestat.getExprents() != null && elsestat.getExprents().size() == 1
+ && ifstat.getAllSuccessorEdges().size() == 1 && elsestat.getAllSuccessorEdges().size() == 1
+ && ifstat.getAllSuccessorEdges().get(0).getDestination() == elsestat.getAllSuccessorEdges().get(0).getDestination()) {
+
+ Exprent ifexpr = ifstat.getExprents().get(0);
+ Exprent elseexpr = elsestat.getExprents().get(0);
+
+ if (ifexpr.type == Exprent.EXPRENT_ASSIGNMENT && elseexpr.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent ifas = (AssignmentExprent)ifexpr;
+ AssignmentExprent elseas = (AssignmentExprent)elseexpr;
+
+ if (ifas.getLeft().type == Exprent.EXPRENT_VAR && elseas.getLeft().type == Exprent.EXPRENT_VAR) {
+ VarExprent ifvar = (VarExprent)ifas.getLeft();
+ VarExprent elsevar = (VarExprent)elseas.getLeft();
+
+ if (ifvar.getIndex() == elsevar.getIndex() && ifvar.isStack()) { // ifvar.getIndex() >= VarExprent.STACK_BASE) {
+
+ boolean found = false;
+
+ for (Entry<VarVersionPaar, FastSparseSet<Integer>> ent : ssa.getPhi().entrySet()) {
+ if (ent.getKey().var == ifvar.getIndex()) {
+ if (ent.getValue().contains(ifvar.getVersion()) && ent.getValue().contains(elsevar.getVersion())) {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (found) {
+ List<Exprent> data = new ArrayList<Exprent>();
+ data.addAll(stif.getFirst().getExprents());
+
+ data.add(new AssignmentExprent(ifvar, new FunctionExprent(FunctionExprent.FUNCTION_IIF,
+ Arrays.asList(new Exprent[]{
+ stif.getHeadexprent().getCondition(),
+ ifas.getRight(),
+ elseas.getRight()}))));
+ stif.setExprents(data);
+
+ if (stif.getAllSuccessorEdges().isEmpty()) {
+ StatEdge ifedge = ifstat.getAllSuccessorEdges().get(0);
+ StatEdge edge = new StatEdge(ifedge.getType(), stif, ifedge.getDestination());
+
+ stif.addSuccessor(edge);
+ if (ifedge.closure != null) {
+ ifedge.closure.addLabeledEdge(edge);
+ }
+ }
+
+ SequenceHelper.destroyAndFlattenStatement(stif);
+
+ return true;
+ }
+ }
+ }
+ }
+ else if (ifexpr.type == Exprent.EXPRENT_EXIT && elseexpr.type == Exprent.EXPRENT_EXIT) {
+ ExitExprent ifex = (ExitExprent)ifexpr;
+ ExitExprent elseex = (ExitExprent)elseexpr;
+
+ if (ifex.getExittype() == elseex.getExittype() && ifex.getValue() != null && elseex.getValue() != null &&
+ ifex.getExittype() == ExitExprent.EXIT_RETURN) {
+
+ // throw is dangerous, because of implicit casting to a common superclass
+ // e.g. throws IOException and throw true?new RuntimeException():new IOException(); won't work
+ if (ifex.getExittype() == ExitExprent.EXIT_THROW &&
+ !ifex.getValue().getExprType().equals(elseex.getValue().getExprType())) { // note: getExprType unreliable at this point!
+ return false;
+ }
+
+ List<Exprent> data = new ArrayList<Exprent>();
+ data.addAll(stif.getFirst().getExprents());
+
+ data.add(new ExitExprent(ifex.getExittype(), new FunctionExprent(FunctionExprent.FUNCTION_IIF,
+ Arrays.asList(new Exprent[]{
+ stif.getHeadexprent().getCondition(),
+ ifex.getValue(),
+ elseex.getValue()})), ifex.getRettype()));
+ stif.setExprents(data);
+
+ StatEdge retedge = ifstat.getAllSuccessorEdges().get(0);
+ stif.addSuccessor(new StatEdge(StatEdge.TYPE_BREAK, stif, retedge.getDestination(),
+ retedge.closure == stif ? stif.getParent() : retedge.closure));
+
+ SequenceHelper.destroyAndFlattenStatement(stif);
+
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/StackVarsProcessor.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/StackVarsProcessor.java
new file mode 100644
index 000000000000..109490cc8ef9
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/StackVarsProcessor.java
@@ -0,0 +1,735 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
+import org.jetbrains.java.decompiler.modules.decompiler.sforms.*;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.DoStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionEdge;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionNode;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionsGraph;
+import org.jetbrains.java.decompiler.struct.StructClass;
+import org.jetbrains.java.decompiler.struct.StructMethod;
+import org.jetbrains.java.decompiler.util.FastSparseSetFactory.FastSparseSet;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import org.jetbrains.java.decompiler.util.SFormsFastMapDirect;
+
+import java.util.*;
+import java.util.Map.Entry;
+
+
+public class StackVarsProcessor {
+
+ public void simplifyStackVars(RootStatement root, StructMethod mt, StructClass cl) {
+
+ HashSet<Integer> setReorderedIfs = new HashSet<Integer>();
+
+ SSAUConstructorSparseEx ssau = null;
+
+ while (true) {
+
+ boolean found = false;
+
+ // System.out.println("--------------- \r\n"+root.toJava());
+
+ SSAConstructorSparseEx ssa = new SSAConstructorSparseEx();
+ ssa.splitVariables(root, mt);
+
+ // System.out.println("--------------- \r\n"+root.toJava());
+
+
+ SimplifyExprentsHelper sehelper = new SimplifyExprentsHelper(ssau == null);
+ while (sehelper.simplifyStackVarsStatement(root, setReorderedIfs, ssa, cl)) {
+ // System.out.println("--------------- \r\n"+root.toJava());
+ found = true;
+ }
+
+
+ // System.out.println("=============== \r\n"+root.toJava());
+
+ setVersionsToNull(root);
+
+ SequenceHelper.condenseSequences(root);
+
+ ssau = new SSAUConstructorSparseEx();
+ ssau.splitVariables(root, mt);
+
+ // try {
+ // DotExporter.toDotFile(ssau.getSsuversions(), new File("c:\\Temp\\gr12_my.dot"));
+ // } catch(Exception ex) {
+ // ex.printStackTrace();
+ // }
+
+ // System.out.println("++++++++++++++++ \r\n"+root.toJava());
+
+
+ if (iterateStatements(root, ssau)) {
+ found = true;
+ }
+
+ // System.out.println("***************** \r\n"+root.toJava());
+
+ setVersionsToNull(root);
+
+ if (!found) {
+ break;
+ }
+ }
+
+ // remove unused assignments
+ ssau = new SSAUConstructorSparseEx();
+ ssau.splitVariables(root, mt);
+
+ // try {
+ // DotExporter.toDotFile(ssau.getSsuversions(), new File("c:\\Temp\\gr12_my.dot"));
+ // } catch(Exception ex) {
+ // ex.printStackTrace();
+ // }
+
+ iterateStatements(root, ssau);
+
+ // System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
+
+ setVersionsToNull(root);
+ }
+
+ private static void setVersionsToNull(Statement stat) {
+
+ if (stat.getExprents() == null) {
+ for (Object obj : stat.getSequentialObjects()) {
+ if (obj instanceof Statement) {
+ setVersionsToNull((Statement)obj);
+ }
+ else if (obj instanceof Exprent) {
+ setExprentVersionsToNull((Exprent)obj);
+ }
+ }
+ }
+ else {
+ for (Exprent exprent : stat.getExprents()) {
+ setExprentVersionsToNull(exprent);
+ }
+ }
+ }
+
+ private static void setExprentVersionsToNull(Exprent exprent) {
+
+ List<Exprent> lst = exprent.getAllExprents(true);
+ lst.add(exprent);
+
+ for (Exprent expr : lst) {
+ if (expr.type == Exprent.EXPRENT_VAR) {
+ ((VarExprent)expr).setVersion(0);
+ }
+ }
+ }
+
+
+ private boolean iterateStatements(RootStatement root, SSAUConstructorSparseEx ssa) {
+
+ FlattenStatementsHelper flatthelper = new FlattenStatementsHelper();
+ DirectGraph dgraph = flatthelper.buildDirectGraph(root);
+
+ boolean res = false;
+
+ HashSet<DirectNode> setVisited = new HashSet<DirectNode>();
+ LinkedList<DirectNode> stack = new LinkedList<DirectNode>();
+ LinkedList<HashMap<VarVersionPaar, Exprent>> stackMaps = new LinkedList<HashMap<VarVersionPaar, Exprent>>();
+
+ stack.add(dgraph.first);
+ stackMaps.add(new HashMap<VarVersionPaar, Exprent>());
+
+ while (!stack.isEmpty()) {
+
+ DirectNode nd = stack.removeFirst();
+ HashMap<VarVersionPaar, Exprent> mapVarValues = stackMaps.removeFirst();
+
+ if (setVisited.contains(nd)) {
+ continue;
+ }
+ setVisited.add(nd);
+
+ List<List<Exprent>> lstLists = new ArrayList<List<Exprent>>();
+
+ if (!nd.exprents.isEmpty()) {
+ lstLists.add(nd.exprents);
+ }
+
+ if (nd.succs.size() == 1) {
+ DirectNode ndsucc = nd.succs.get(0);
+ if (ndsucc.type == DirectNode.NODE_TAIL && !ndsucc.exprents.isEmpty()) {
+ lstLists.add(nd.succs.get(0).exprents);
+ nd = ndsucc;
+ }
+ }
+
+ for (int i = 0; i < lstLists.size(); i++) {
+ List<Exprent> lst = lstLists.get(i);
+
+ int index = 0;
+ while (index < lst.size()) {
+ Exprent next = null;
+ if (index == lst.size() - 1) {
+ if (i < lstLists.size() - 1) {
+ next = lstLists.get(i + 1).get(0);
+ }
+ }
+ else {
+ next = lst.get(index + 1);
+ }
+
+ int[] ret = iterateExprent(lst, index, next, mapVarValues, ssa);
+
+ //System.out.println("***************** \r\n"+root.toJava());
+
+ if (ret[0] >= 0) {
+ index = ret[0];
+ }
+ else {
+ index++;
+ }
+ res |= (ret[1] == 1);
+ }
+ }
+
+ for (DirectNode ndx : nd.succs) {
+ stack.add(ndx);
+ stackMaps.add(new HashMap<VarVersionPaar, Exprent>(mapVarValues));
+ }
+
+ // make sure the 3 special exprent lists in a loop (init, condition, increment) are not empty
+ // change loop type if necessary
+ if (nd.exprents.isEmpty() &&
+ (nd.type == DirectNode.NODE_INIT || nd.type == DirectNode.NODE_CONDITION || nd.type == DirectNode.NODE_INCREMENT)) {
+ nd.exprents.add(null);
+
+ if (nd.statement.type == Statement.TYPE_DO) {
+ DoStatement loop = (DoStatement)nd.statement;
+
+ if (loop.getLooptype() == DoStatement.LOOP_FOR &&
+ loop.getInitExprent() == null &&
+ loop.getIncExprent() == null) { // "downgrade" loop to 'while'
+ loop.setLooptype(DoStatement.LOOP_WHILE);
+ }
+ }
+ }
+ }
+
+ return res;
+ }
+
+
+ private static Exprent isReplaceableVar(Exprent exprent, HashMap<VarVersionPaar, Exprent> mapVarValues, SSAUConstructorSparseEx ssau) {
+
+ Exprent dest = null;
+
+ if (exprent.type == Exprent.EXPRENT_VAR) {
+ VarExprent var = (VarExprent)exprent;
+ dest = mapVarValues.get(new VarVersionPaar(var));
+ }
+
+ return dest;
+ }
+
+ private static void replaceSingleVar(Exprent parent, VarExprent var, Exprent dest, SSAUConstructorSparseEx ssau) {
+
+ parent.replaceExprent(var, dest);
+
+ // live sets
+ SFormsFastMapDirect livemap = ssau.getLiveVarVersionsMap(new VarVersionPaar(var));
+ HashSet<VarVersionPaar> setVars = getAllVersions(dest);
+
+ for (VarVersionPaar varpaar : setVars) {
+ VarVersionNode node = ssau.getSsuversions().nodes.getWithKey(varpaar);
+
+ for (Iterator<Entry<Integer, FastSparseSet<Integer>>> itent = node.live.entryList().iterator(); itent.hasNext(); ) {
+ Entry<Integer, FastSparseSet<Integer>> ent = itent.next();
+
+ Integer key = ent.getKey();
+
+ if (!livemap.containsKey(key)) {
+ itent.remove();
+ }
+ else {
+ FastSparseSet<Integer> set = ent.getValue();
+
+ set.complement(livemap.get(key));
+ if (set.isEmpty()) {
+ itent.remove();
+ }
+ }
+ }
+ }
+ }
+
+ private int[] iterateExprent(List<Exprent> lstExprents, int index, Exprent next, HashMap<VarVersionPaar,
+ Exprent> mapVarValues, SSAUConstructorSparseEx ssau) {
+
+ Exprent exprent = lstExprents.get(index);
+
+ int changed = 0;
+
+ for (Exprent expr : exprent.getAllExprents()) {
+ while (true) {
+ Object[] arr = iterateChildExprent(expr, exprent, next, mapVarValues, ssau);
+ Exprent retexpr = (Exprent)arr[0];
+ changed |= (Boolean)arr[1] ? 1 : 0;
+
+ boolean isReplaceable = (Boolean)arr[2];
+ if (retexpr != null) {
+ if (isReplaceable) {
+ replaceSingleVar(exprent, (VarExprent)expr, retexpr, ssau);
+ expr = retexpr;
+ }
+ else {
+ exprent.replaceExprent(expr, retexpr);
+ }
+ changed = 1;
+ }
+
+ if (!isReplaceable) {
+ break;
+ }
+ }
+ }
+
+ // no var on the highest level, so no replacing
+
+ VarExprent left = null;
+ Exprent right = null;
+
+ if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent as = (AssignmentExprent)exprent;
+ if (as.getLeft().type == Exprent.EXPRENT_VAR) {
+ left = (VarExprent)as.getLeft();
+ right = as.getRight();
+ }
+ }
+
+ if (left == null) {
+ return new int[]{-1, changed};
+ }
+
+ VarVersionPaar leftpaar = new VarVersionPaar(left);
+
+ List<VarVersionNode> usedVers = new ArrayList<VarVersionNode>();
+ boolean notdom = getUsedVersions(ssau, leftpaar, usedVers);
+
+ if (!notdom && usedVers.isEmpty()) {
+ if (left.isStack() && (right.type == Exprent.EXPRENT_INVOCATION ||
+ right.type == Exprent.EXPRENT_ASSIGNMENT || right.type == Exprent.EXPRENT_NEW)) {
+ if (right.type == Exprent.EXPRENT_NEW) {
+ // new Object(); permitted
+ NewExprent nexpr = (NewExprent)right;
+ if (nexpr.isAnonymous() || nexpr.getNewtype().arraydim > 0
+ || nexpr.getNewtype().type != CodeConstants.TYPE_OBJECT) {
+ return new int[]{-1, changed};
+ }
+ }
+
+ lstExprents.set(index, right);
+ return new int[]{index + 1, 1};
+ }
+ else if (right.type == Exprent.EXPRENT_VAR) {
+ lstExprents.remove(index);
+ return new int[]{index, 1};
+ }
+ else {
+ return new int[]{-1, changed};
+ }
+ }
+
+ int useflags = right.getExprentUse();
+
+ // stack variables only
+ if (!left.isStack() &&
+ (right.type != Exprent.EXPRENT_VAR || ((VarExprent)right).isStack())) { // special case catch(... ex)
+ return new int[]{-1, changed};
+ }
+
+ if ((useflags & Exprent.MULTIPLE_USES) == 0 && (notdom || usedVers.size() > 1)) {
+ return new int[]{-1, changed};
+ }
+
+ HashMap<Integer, HashSet<VarVersionPaar>> mapVars = getAllVarVersions(leftpaar, right, ssau);
+
+ boolean isSelfReference = mapVars.containsKey(leftpaar.var);
+ if (isSelfReference && notdom) {
+ return new int[]{-1, changed};
+ }
+
+ HashSet<VarVersionPaar> setNextVars = next == null ? null : getAllVersions(next);
+
+ // FIXME: fix the entire method!
+ if (right.type != Exprent.EXPRENT_CONST &&
+ right.type != Exprent.EXPRENT_VAR &&
+ setNextVars != null &&
+ mapVars.containsKey(leftpaar.var)) {
+ for (VarVersionNode usedvar : usedVers) {
+ if (!setNextVars.contains(new VarVersionPaar(usedvar.var, usedvar.version))) {
+ return new int[]{-1, changed};
+ }
+ }
+ }
+
+ mapVars.remove(leftpaar.var);
+
+ boolean vernotreplaced = false;
+ boolean verreplaced = false;
+
+
+ HashSet<VarVersionPaar> setTempUsedVers = new HashSet<VarVersionPaar>();
+
+ for (VarVersionNode usedvar : usedVers) {
+ VarVersionPaar usedver = new VarVersionPaar(usedvar.var, usedvar.version);
+ if (isVersionToBeReplaced(usedver, mapVars, ssau, leftpaar) &&
+ (right.type == Exprent.EXPRENT_CONST || right.type == Exprent.EXPRENT_VAR || right.type == Exprent.EXPRENT_FIELD
+ || setNextVars == null || setNextVars.contains(usedver))) {
+
+ setTempUsedVers.add(usedver);
+ verreplaced = true;
+ }
+ else {
+ vernotreplaced = true;
+ }
+ }
+
+ if (isSelfReference && vernotreplaced) {
+ return new int[]{-1, changed};
+ }
+ else {
+ for (VarVersionPaar usedver : setTempUsedVers) {
+ Exprent copy = right.copy();
+ if (right.type == Exprent.EXPRENT_FIELD && ssau.getMapFieldVars().containsKey(right.id)) {
+ ssau.getMapFieldVars().put(copy.id, ssau.getMapFieldVars().get(right.id));
+ }
+
+ mapVarValues.put(usedver, copy);
+ }
+ }
+
+ if (!notdom && !vernotreplaced) {
+ // remove assignment
+ lstExprents.remove(index);
+ return new int[]{index, 1};
+ }
+ else if (verreplaced) {
+ return new int[]{index + 1, changed};
+ }
+ else {
+ return new int[]{-1, changed};
+ }
+ }
+
+ private static HashSet<VarVersionPaar> getAllVersions(Exprent exprent) {
+
+ HashSet<VarVersionPaar> res = new HashSet<VarVersionPaar>();
+
+ List<Exprent> listTemp = new ArrayList<Exprent>(exprent.getAllExprents(true));
+ listTemp.add(exprent);
+
+ for (Exprent expr : listTemp) {
+ if (expr.type == Exprent.EXPRENT_VAR) {
+ VarExprent var = (VarExprent)expr;
+ res.add(new VarVersionPaar(var));
+ }
+ }
+
+ return res;
+ }
+
+ private static Object[] iterateChildExprent(Exprent exprent,
+ Exprent parent,
+ Exprent next,
+ HashMap<VarVersionPaar, Exprent> mapVarValues,
+ SSAUConstructorSparseEx ssau) {
+
+ boolean changed = false;
+
+ for (Exprent expr : exprent.getAllExprents()) {
+ while (true) {
+ Object[] arr = iterateChildExprent(expr, parent, next, mapVarValues, ssau);
+ Exprent retexpr = (Exprent)arr[0];
+ changed |= (Boolean)arr[1];
+
+ boolean isReplaceable = (Boolean)arr[2];
+ if (retexpr != null) {
+ if (isReplaceable) {
+ replaceSingleVar(exprent, (VarExprent)expr, retexpr, ssau);
+ expr = retexpr;
+ }
+ else {
+ exprent.replaceExprent(expr, retexpr);
+ }
+ changed = true;
+ }
+
+ if (!isReplaceable) {
+ break;
+ }
+ }
+ }
+
+ Exprent dest = isReplaceableVar(exprent, mapVarValues, ssau);
+ if (dest != null) {
+ return new Object[]{dest, true, true};
+ }
+
+
+ VarExprent left = null;
+ Exprent right = null;
+
+ if (exprent.type == Exprent.EXPRENT_ASSIGNMENT) {
+ AssignmentExprent as = (AssignmentExprent)exprent;
+ if (as.getLeft().type == Exprent.EXPRENT_VAR) {
+ left = (VarExprent)as.getLeft();
+ right = as.getRight();
+ }
+ }
+
+ if (left == null) {
+ return new Object[]{null, changed, false};
+ }
+
+ boolean isHeadSynchronized = false;
+ if (next == null && parent.type == Exprent.EXPRENT_MONITOR) {
+ MonitorExprent monexpr = (MonitorExprent)parent;
+ if (monexpr.getMontype() == MonitorExprent.MONITOR_ENTER && exprent.equals(monexpr.getValue())) {
+ isHeadSynchronized = true;
+ }
+ }
+
+ // stack variable or synchronized head exprent
+ if (!left.isStack() && !isHeadSynchronized) {
+ return new Object[]{null, changed, false};
+ }
+
+ VarVersionPaar leftpaar = new VarVersionPaar(left);
+
+ List<VarVersionNode> usedVers = new ArrayList<VarVersionNode>();
+ boolean notdom = getUsedVersions(ssau, leftpaar, usedVers);
+
+ if (!notdom && usedVers.isEmpty()) {
+ return new Object[]{right, changed, false};
+ }
+
+ // stack variables only
+ if (!left.isStack()) {
+ return new Object[]{null, changed, false};
+ }
+
+ int useflags = right.getExprentUse();
+
+ if ((useflags & Exprent.BOTH_FLAGS) != Exprent.BOTH_FLAGS) {
+ return new Object[]{null, changed, false};
+ }
+
+ HashMap<Integer, HashSet<VarVersionPaar>> mapVars = getAllVarVersions(leftpaar, right, ssau);
+
+ if (mapVars.containsKey(leftpaar.var) && notdom) {
+ return new Object[]{null, changed, false};
+ }
+
+
+ mapVars.remove(leftpaar.var);
+
+ HashSet<VarVersionPaar> setAllowedVars = getAllVersions(parent);
+ if (next != null) {
+ setAllowedVars.addAll(getAllVersions(next));
+ }
+
+ boolean vernotreplaced = false;
+
+ HashSet<VarVersionPaar> setTempUsedVers = new HashSet<VarVersionPaar>();
+
+ for (VarVersionNode usedvar : usedVers) {
+ VarVersionPaar usedver = new VarVersionPaar(usedvar.var, usedvar.version);
+ if (isVersionToBeReplaced(usedver, mapVars, ssau, leftpaar) &&
+ (right.type == Exprent.EXPRENT_VAR || setAllowedVars.contains(usedver))) {
+
+ setTempUsedVers.add(usedver);
+ }
+ else {
+ vernotreplaced = true;
+ }
+ }
+
+ if (!notdom && !vernotreplaced) {
+
+ for (VarVersionPaar usedver : setTempUsedVers) {
+ Exprent copy = right.copy();
+ if (right.type == Exprent.EXPRENT_FIELD && ssau.getMapFieldVars().containsKey(right.id)) {
+ ssau.getMapFieldVars().put(copy.id, ssau.getMapFieldVars().get(right.id));
+ }
+
+ mapVarValues.put(usedver, copy);
+ }
+
+ // remove assignment
+ return new Object[]{right, changed, false};
+ }
+
+ return new Object[]{null, changed, false};
+ }
+
+ private static boolean getUsedVersions(SSAUConstructorSparseEx ssa, VarVersionPaar var, List<VarVersionNode> res) {
+
+ VarVersionsGraph ssuversions = ssa.getSsuversions();
+ VarVersionNode varnode = ssuversions.nodes.getWithKey(var);
+
+ HashSet<VarVersionNode> setVisited = new HashSet<VarVersionNode>();
+
+ HashSet<VarVersionNode> setNotDoms = new HashSet<VarVersionNode>();
+
+ LinkedList<VarVersionNode> stack = new LinkedList<VarVersionNode>();
+ stack.add(varnode);
+
+ while (!stack.isEmpty()) {
+
+ VarVersionNode nd = stack.remove(0);
+ setVisited.add(nd);
+
+ if (nd != varnode && (nd.flags & VarVersionNode.FLAG_PHANTOM_FINEXIT) == 0) {
+ res.add(nd);
+ }
+
+ for (VarVersionEdge edge : nd.succs) {
+ VarVersionNode succ = edge.dest;
+
+ if (!setVisited.contains(edge.dest)) {
+
+ boolean isDominated = true;
+ for (VarVersionEdge prededge : succ.preds) {
+ if (!setVisited.contains(prededge.source)) {
+ isDominated = false;
+ break;
+ }
+ }
+
+ if (isDominated) {
+ stack.add(succ);
+ }
+ else {
+ setNotDoms.add(succ);
+ }
+ }
+ }
+ }
+
+ setNotDoms.removeAll(setVisited);
+
+ return !setNotDoms.isEmpty();
+ }
+
+ private static boolean isVersionToBeReplaced(VarVersionPaar usedvar,
+ HashMap<Integer, HashSet<VarVersionPaar>> mapVars,
+ SSAUConstructorSparseEx ssau,
+ VarVersionPaar leftpaar) {
+
+ VarVersionsGraph ssuversions = ssau.getSsuversions();
+
+ SFormsFastMapDirect mapLiveVars = ssau.getLiveVarVersionsMap(usedvar);
+ if (mapLiveVars == null) {
+ // dummy version, predecessor of a phi node
+ return false;
+ }
+
+ // compare protected ranges
+ if (!InterpreterUtil.equalObjects(ssau.getMapVersionFirstRange().get(leftpaar),
+ ssau.getMapVersionFirstRange().get(usedvar))) {
+ return false;
+ }
+
+ for (Entry<Integer, HashSet<VarVersionPaar>> ent : mapVars.entrySet()) {
+ FastSparseSet<Integer> liveverset = mapLiveVars.get(ent.getKey());
+ if (liveverset == null) {
+ return false;
+ }
+
+ HashSet<VarVersionNode> domset = new HashSet<VarVersionNode>();
+ for (VarVersionPaar verpaar : ent.getValue()) {
+ domset.add(ssuversions.nodes.getWithKey(verpaar));
+ }
+
+ boolean isdom = false;
+
+ for (Integer livever : liveverset) {
+ VarVersionNode node = ssuversions.nodes.getWithKey(new VarVersionPaar(ent.getKey().intValue(), livever.intValue()));
+
+ if (ssuversions.isDominatorSet(node, domset)) {
+ isdom = true;
+ break;
+ }
+ }
+
+ if (!isdom) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private static HashMap<Integer, HashSet<VarVersionPaar>> getAllVarVersions(VarVersionPaar leftvar,
+ Exprent exprent,
+ SSAUConstructorSparseEx ssau) {
+
+ HashMap<Integer, HashSet<VarVersionPaar>> map = new HashMap<Integer, HashSet<VarVersionPaar>>();
+ SFormsFastMapDirect mapLiveVars = ssau.getLiveVarVersionsMap(leftvar);
+
+ List<Exprent> lst = exprent.getAllExprents(true);
+ lst.add(exprent);
+
+ for (Exprent expr : lst) {
+ if (expr.type == Exprent.EXPRENT_VAR) {
+ int varindex = ((VarExprent)expr).getIndex();
+ if (leftvar.var != varindex) {
+ if (mapLiveVars.containsKey(varindex)) {
+ HashSet<VarVersionPaar> verset = new HashSet<VarVersionPaar>();
+ for (Integer vers : mapLiveVars.get(varindex)) {
+ verset.add(new VarVersionPaar(varindex, vers.intValue()));
+ }
+ map.put(varindex, verset);
+ }
+ else {
+ throw new RuntimeException("inkonsistent live map!");
+ }
+ }
+ else {
+ map.put(varindex, null);
+ }
+ }
+ else if (expr.type == Exprent.EXPRENT_FIELD) {
+ if (ssau.getMapFieldVars().containsKey(expr.id)) {
+ int varindex = ssau.getMapFieldVars().get(expr.id);
+ if (mapLiveVars.containsKey(varindex)) {
+ HashSet<VarVersionPaar> verset = new HashSet<VarVersionPaar>();
+ for (Integer vers : mapLiveVars.get(varindex)) {
+ verset.add(new VarVersionPaar(varindex, vers.intValue()));
+ }
+ map.put(varindex, verset);
+ }
+ }
+ }
+ }
+
+ return map;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/StatEdge.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/StatEdge.java
new file mode 100644
index 000000000000..26d427b93770
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/StatEdge.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler;
+
+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class StatEdge {
+
+ public static final int TYPE_ALL = 0xFF;
+
+ public static final int TYPE_REGULAR = 1;
+ public static final int TYPE_EXCEPTION = 2;
+ public static final int TYPE_BREAK = 4;
+ public static final int TYPE_CONTINUE = 8;
+ public static final int TYPE_FINALLYEXIT = 32;
+
+ public static final int[] TYPES = new int[]{
+ TYPE_REGULAR,
+ TYPE_EXCEPTION,
+ TYPE_BREAK,
+ TYPE_CONTINUE,
+ TYPE_FINALLYEXIT
+ };
+
+ private int type;
+
+ private Statement source;
+
+ private Statement destination;
+
+ private List<String> exceptions;
+
+ public Statement closure;
+
+ public boolean labeled = true;
+
+ public boolean explicit = true;
+
+ public StatEdge(int type, Statement source, Statement destination, Statement closure) {
+ this(type, source, destination);
+ this.closure = closure;
+ }
+
+ public StatEdge(int type, Statement source, Statement destination) {
+ this.type = type;
+ this.source = source;
+ this.destination = destination;
+ }
+
+ public StatEdge(Statement source, Statement destination, List<String> exceptions) {
+ this(TYPE_EXCEPTION, source, destination);
+ if (exceptions != null) {
+ this.exceptions = new ArrayList<String>(exceptions);
+ }
+ }
+
+ public int getType() {
+ return type;
+ }
+
+ public void setType(int type) {
+ this.type = type;
+ }
+
+ public Statement getSource() {
+ return source;
+ }
+
+ public void setSource(Statement source) {
+ this.source = source;
+ }
+
+ public Statement getDestination() {
+ return destination;
+ }
+
+ public void setDestination(Statement destination) {
+ this.destination = destination;
+ }
+
+ public List<String> getExceptions() {
+ return this.exceptions;
+ }
+
+ // public void setException(String exception) {
+ // this.exception = exception;
+ // }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/StrongConnectivityHelper.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/StrongConnectivityHelper.java
new file mode 100644
index 000000000000..23f778daea97
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/StrongConnectivityHelper.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler;
+
+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+import org.jetbrains.java.decompiler.util.ListStack;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+
+// --------------------------------------------------------------------
+// Algorithm
+// --------------------------------------------------------------------
+// DFS(G)
+// {
+// make a new vertex x with edges x->v for all v
+// initialize a counter N to zero
+// initialize list L to empty
+// build directed tree T, initially a single vertex {x}
+// visit(x)
+// }
+//
+// visit(p)
+// {
+// add p to L
+// dfsnum(p) = N
+// increment N
+// low(p) = dfsnum(p)
+// for each edge p->q
+// if q is not already in T
+// {
+// add p->q to T
+// visit(q)
+// low(p) = min(low(p), low(q))
+// } else low(p) = min(low(p), dfsnum(q))
+//
+// if low(p)=dfsnum(p)
+// {
+// output "component:"
+// repeat
+// remove last element v from L
+// output v
+// remove v from G
+// until v=p
+// }
+// }
+// --------------------------------------------------------------------
+
+public class StrongConnectivityHelper {
+
+ private ListStack<Statement> lstack;
+
+ private int ncounter;
+
+ private HashSet<Statement> tset;
+ private HashMap<Statement, Integer> dfsnummap;
+ private HashMap<Statement, Integer> lowmap;
+
+ private List<List<Statement>> components;
+
+ private HashSet<Statement> setProcessed;
+
+ // *****************************************************************************
+ // constructors
+ // *****************************************************************************
+
+ public StrongConnectivityHelper() {
+ }
+
+ public StrongConnectivityHelper(Statement stat) {
+ findComponents(stat);
+ }
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public List<List<Statement>> findComponents(Statement stat) {
+
+ components = new ArrayList<List<Statement>>();
+ setProcessed = new HashSet<Statement>();
+
+ visitTree(stat.getFirst());
+
+ for (Statement st : stat.getStats()) {
+ if (!setProcessed.contains(st) && st.getPredecessorEdges(Statement.STATEDGE_DIRECT_ALL).isEmpty()) {
+ visitTree(st);
+ }
+ }
+
+ // should not find any more nodes! FIXME: ??
+ for (Statement st : stat.getStats()) {
+ if (!setProcessed.contains(st)) {
+ visitTree(st);
+ }
+ }
+
+ return components;
+ }
+
+ public static boolean isExitComponent(List<Statement> lst) {
+
+ HashSet<Statement> set = new HashSet<Statement>();
+ for (Statement stat : lst) {
+ set.addAll(stat.getNeighbours(StatEdge.TYPE_REGULAR, Statement.DIRECTION_FORWARD));
+ }
+ set.removeAll(lst);
+
+ return (set.size() == 0);
+ }
+
+ public static List<Statement> getExitReps(List<List<Statement>> lst) {
+
+ List<Statement> res = new ArrayList<Statement>();
+
+ for (List<Statement> comp : lst) {
+ if (isExitComponent(comp)) {
+ res.add(comp.get(0));
+ }
+ }
+
+ return res;
+ }
+
+ // *****************************************************************************
+ // private methods
+ // *****************************************************************************
+
+ private void visitTree(Statement stat) {
+ lstack = new ListStack<Statement>();
+ ncounter = 0;
+ tset = new HashSet<Statement>();
+ dfsnummap = new HashMap<Statement, Integer>();
+ lowmap = new HashMap<Statement, Integer>();
+
+ visit(stat);
+
+ setProcessed.addAll(tset);
+ setProcessed.add(stat);
+ }
+
+ private void visit(Statement stat) {
+
+ lstack.push(stat);
+ dfsnummap.put(stat, ncounter);
+ lowmap.put(stat, ncounter);
+ ncounter++;
+
+ List<Statement> lstSuccs = stat.getNeighbours(StatEdge.TYPE_REGULAR, Statement.DIRECTION_FORWARD); // TODO: set?
+ lstSuccs.removeAll(setProcessed);
+
+ for (int i = 0; i < lstSuccs.size(); i++) {
+ Statement succ = lstSuccs.get(i);
+ int secvalue;
+
+ if (tset.contains(succ)) {
+ secvalue = dfsnummap.get(succ);
+ }
+ else {
+ tset.add(succ);
+ visit(succ);
+ secvalue = lowmap.get(succ);
+ }
+ lowmap.put(stat, Math.min(lowmap.get(stat), secvalue));
+ }
+
+
+ if (lowmap.get(stat).intValue() == dfsnummap.get(stat).intValue()) {
+ List<Statement> lst = new ArrayList<Statement>();
+ Statement v;
+ do {
+ v = lstack.pop();
+ lst.add(v);
+ }
+ while (v != stat);
+ components.add(lst);
+ }
+ }
+
+
+ // *****************************************************************************
+ // getter and setter methods
+ // *****************************************************************************
+
+ public List<List<Statement>> getComponents() {
+ return components;
+ }
+
+ public void setComponents(List<List<Statement>> components) {
+ this.components = components;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/DominatorEngine.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/DominatorEngine.java
new file mode 100644
index 000000000000..aeab0d2cf948
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/DominatorEngine.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.decompose;
+
+import org.jetbrains.java.decompiler.modules.decompiler.StatEdge;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+import org.jetbrains.java.decompiler.util.VBStyleCollection;
+
+import java.util.List;
+
+public class DominatorEngine {
+
+ private Statement statement;
+
+ private VBStyleCollection<Integer, Integer> colOrderedIDoms = new VBStyleCollection<Integer, Integer>();
+
+
+ public DominatorEngine(Statement statement) {
+ this.statement = statement;
+ }
+
+ public void initialize() {
+ calcIDoms();
+ }
+
+ private void orderStatements() {
+
+ for (Statement stat : statement.getReversePostOrderList()) {
+ colOrderedIDoms.addWithKey(null, stat.id);
+ }
+ }
+
+ private static Integer getCommonIDom(Integer key1, Integer key2, VBStyleCollection<Integer, Integer> orderedIDoms) {
+
+ if (key1 == null) {
+ return key2;
+ }
+ else if (key2 == null) {
+ return key1;
+ }
+
+ int index1 = orderedIDoms.getIndexByKey(key1);
+ int index2 = orderedIDoms.getIndexByKey(key2);
+
+ while (index1 != index2) {
+ if (index1 > index2) {
+ key1 = orderedIDoms.getWithKey(key1);
+ index1 = orderedIDoms.getIndexByKey(key1);
+ }
+ else {
+ key2 = orderedIDoms.getWithKey(key2);
+ index2 = orderedIDoms.getIndexByKey(key2);
+ }
+ }
+
+ return key1;
+ }
+
+ private void calcIDoms() {
+
+ orderStatements();
+
+ colOrderedIDoms.putWithKey(statement.getFirst().id, statement.getFirst().id);
+
+ // exclude first statement
+ List<Integer> lstIds = colOrderedIDoms.getLstKeys().subList(1, colOrderedIDoms.getLstKeys().size());
+
+ while (true) {
+
+ boolean changed = false;
+
+ for (Integer id : lstIds) {
+
+ Statement stat = statement.getStats().getWithKey(id);
+ Integer idom = null;
+
+ for (StatEdge edge : stat.getAllPredecessorEdges()) {
+ if (colOrderedIDoms.getWithKey(edge.getSource().id) != null) {
+ idom = getCommonIDom(idom, edge.getSource().id, colOrderedIDoms);
+ }
+ }
+
+ Integer oldidom = colOrderedIDoms.putWithKey(idom, id);
+ if (!idom.equals(oldidom)) {
+ changed = true;
+ }
+ }
+
+ if (!changed) {
+ break;
+ }
+ }
+ }
+
+ public VBStyleCollection<Integer, Integer> getOrderedIDoms() {
+ return colOrderedIDoms;
+ }
+
+ public boolean isDominator(Integer node, Integer dom) {
+
+ while (!node.equals(dom)) {
+
+ Integer idom = colOrderedIDoms.getWithKey(node);
+
+ if (idom.equals(node)) {
+ return false; // root node
+ }
+ else {
+ node = idom;
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/DominatorTreeExceptionFilter.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/DominatorTreeExceptionFilter.java
new file mode 100644
index 000000000000..c11d5bf0c67e
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/DominatorTreeExceptionFilter.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.decompose;
+
+import org.jetbrains.java.decompiler.modules.decompiler.StatEdge;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+import org.jetbrains.java.decompiler.util.VBStyleCollection;
+
+import java.util.*;
+import java.util.Map.Entry;
+
+public class DominatorTreeExceptionFilter {
+
+ private Statement statement;
+
+ // idom, nodes
+ private Map<Integer, Set<Integer>> mapTreeBranches = new HashMap<Integer, Set<Integer>>();
+
+ // handler, range nodes
+ private Map<Integer, Set<Integer>> mapExceptionRanges = new HashMap<Integer, Set<Integer>>();
+
+ // handler, head dom
+ private Map<Integer, Integer> mapExceptionDoms = new HashMap<Integer, Integer>();
+
+ // statement, handler, exit nodes
+ private Map<Integer, Map<Integer, Integer>> mapExceptionRangeUniqueExit = new HashMap<Integer, Map<Integer, Integer>>();
+
+ private DominatorEngine domEngine;
+
+ public DominatorTreeExceptionFilter(Statement statement) {
+ this.statement = statement;
+ }
+
+ public void initialize() {
+
+ domEngine = new DominatorEngine(statement);
+ domEngine.initialize();
+
+ buildDominatorTree();
+
+ buildExceptionRanges();
+
+ buildFilter(statement.getFirst().id);
+
+ // free resources
+ mapTreeBranches.clear();
+ mapExceptionRanges.clear();
+ }
+
+ public boolean acceptStatementPair(Integer head, Integer exit) {
+
+ Map<Integer, Integer> filter = mapExceptionRangeUniqueExit.get(head);
+ for (Entry<Integer, Integer> entry : filter.entrySet()) {
+ if (!head.equals(mapExceptionDoms.get(entry.getKey()))) {
+ Integer filterExit = entry.getValue();
+ if (filterExit.intValue() == -1 || !filterExit.equals(exit)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ private void buildDominatorTree() {
+
+ VBStyleCollection<Integer, Integer> orderedIDoms = domEngine.getOrderedIDoms();
+
+ List<Integer> lstKeys = orderedIDoms.getLstKeys();
+ for (int index = lstKeys.size() - 1; index >= 0; index--) {
+ Integer key = lstKeys.get(index);
+ Integer idom = orderedIDoms.get(index);
+
+ Set<Integer> set = mapTreeBranches.get(idom);
+ if (set == null) {
+ mapTreeBranches.put(idom, set = new HashSet<Integer>());
+ }
+ set.add(key);
+ }
+
+ Integer firstid = statement.getFirst().id;
+ mapTreeBranches.get(firstid).remove(firstid);
+ }
+
+ private void buildExceptionRanges() {
+
+ for (Statement stat : statement.getStats()) {
+ List<Statement> lstPreds = stat.getNeighbours(StatEdge.TYPE_EXCEPTION, Statement.DIRECTION_BACKWARD);
+ if (!lstPreds.isEmpty()) {
+
+ Set<Integer> set = new HashSet<Integer>();
+
+ for (Statement st : lstPreds) {
+ set.add(st.id);
+ }
+
+ mapExceptionRanges.put(stat.id, set);
+ }
+ }
+
+ mapExceptionDoms = buildExceptionDoms(statement.getFirst().id);
+ }
+
+ private Map<Integer, Integer> buildExceptionDoms(Integer id) {
+
+ Map<Integer, Integer> map = new HashMap<Integer, Integer>();
+
+ Set<Integer> children = mapTreeBranches.get(id);
+ if (children != null) {
+ for (Integer childid : children) {
+ Map<Integer, Integer> mapChild = buildExceptionDoms(childid);
+ for (Integer handler : mapChild.keySet()) {
+ map.put(handler, map.containsKey(handler) ? id : mapChild.get(handler));
+ }
+ }
+ }
+
+ for (Entry<Integer, Set<Integer>> entry : mapExceptionRanges.entrySet()) {
+ if (entry.getValue().contains(id)) {
+ map.put(entry.getKey(), id);
+ }
+ }
+
+ return map;
+ }
+
+
+ private void buildFilter(Integer id) {
+
+ Map<Integer, Integer> map = new HashMap<Integer, Integer>();
+
+ Set<Integer> children = mapTreeBranches.get(id);
+ if (children != null) {
+ for (Integer childid : children) {
+
+ buildFilter(childid);
+
+ Map<Integer, Integer> mapChild = mapExceptionRangeUniqueExit.get(childid);
+
+ for (Entry<Integer, Set<Integer>> entry : mapExceptionRanges.entrySet()) {
+
+ Integer handler = entry.getKey();
+ Set<Integer> range = entry.getValue();
+
+ if (range.contains(id)) {
+
+ Integer exit = null;
+
+ if (!range.contains(childid)) {
+ exit = childid;
+ }
+ else {
+ // exit = map.containsKey(handler)?-1:mapChild.get(handler); FIXME: Eclipse bug?
+ exit = map.containsKey(handler) ? new Integer(-1) : mapChild.get(handler);
+ }
+
+ if (exit != null) {
+ map.put(handler, exit);
+ }
+ }
+ }
+ }
+ }
+
+ mapExceptionRangeUniqueExit.put(id, map);
+ }
+
+ public DominatorEngine getDomEngine() {
+ return domEngine;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/FastExtendedPostdominanceHelper.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/FastExtendedPostdominanceHelper.java
new file mode 100644
index 000000000000..f029016e5efe
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/FastExtendedPostdominanceHelper.java
@@ -0,0 +1,355 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.decompose;
+
+import org.jetbrains.java.decompiler.modules.decompiler.StatEdge;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+import org.jetbrains.java.decompiler.util.FastFixedSetFactory;
+import org.jetbrains.java.decompiler.util.FastFixedSetFactory.FastFixedSet;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+
+import java.util.*;
+import java.util.Map.Entry;
+
+public class FastExtendedPostdominanceHelper {
+
+ private List<Statement> lstReversePostOrderList;
+
+ private HashMap<Integer, FastFixedSet<Integer>> mapSupportPoints = new HashMap<Integer, FastFixedSet<Integer>>();
+
+ private HashMap<Integer, FastFixedSet<Integer>> mapExtPostdominators = new HashMap<Integer, FastFixedSet<Integer>>();
+
+ private Statement statement;
+
+ private FastFixedSetFactory<Integer> factory;
+
+ public HashMap<Integer, Set<Integer>> getExtendedPostdominators(Statement statement) {
+
+ this.statement = statement;
+
+ HashSet<Integer> set = new HashSet<Integer>();
+ for (Statement st : statement.getStats()) {
+ set.add(st.id);
+ }
+ this.factory = new FastFixedSetFactory<Integer>(set);
+
+ lstReversePostOrderList = statement.getReversePostOrderList();
+
+ // try {
+ // DotExporter.toDotFile(statement, new File("c:\\Temp\\stat1.dot"));
+ // } catch (Exception ex) {
+ // ex.printStackTrace();
+ // }
+
+ calcDefaultReachableSets();
+
+ removeErroneousNodes();
+
+ DominatorTreeExceptionFilter filter = new DominatorTreeExceptionFilter(statement);
+ filter.initialize();
+
+ filterOnExceptionRanges(filter);
+
+ filterOnDominance(filter);
+
+ HashMap<Integer, Set<Integer>> res = new HashMap<Integer, Set<Integer>>();
+ for (Entry<Integer, FastFixedSet<Integer>> entry : mapExtPostdominators.entrySet()) {
+ res.put(entry.getKey(), entry.getValue().toPlainSet());
+ }
+
+ return res;
+ }
+
+
+ private void filterOnDominance(DominatorTreeExceptionFilter filter) {
+
+ DominatorEngine engine = filter.getDomEngine();
+
+ for (Integer head : new HashSet<Integer>(mapExtPostdominators.keySet())) {
+
+ FastFixedSet<Integer> setPostdoms = mapExtPostdominators.get(head);
+
+ LinkedList<Statement> stack = new LinkedList<Statement>();
+ LinkedList<FastFixedSet<Integer>> stackPath = new LinkedList<FastFixedSet<Integer>>();
+
+ stack.add(statement.getStats().getWithKey(head));
+ stackPath.add(factory.spawnEmptySet());
+
+ Set<Statement> setVisited = new HashSet<Statement>();
+
+ while (!stack.isEmpty()) {
+
+ Statement stat = stack.removeFirst();
+ FastFixedSet<Integer> path = stackPath.removeFirst();
+
+ if (setPostdoms.contains(stat.id)) {
+ path.add(stat.id);
+ }
+
+ if (path.contains(setPostdoms)) {
+ continue;
+ }
+
+ setVisited.add(stat);
+
+ int domflag = 0;
+
+ for (Iterator<Integer> it = setPostdoms.iterator(); it.hasNext(); ) {
+ Integer post = it.next();
+
+ if (!path.contains(post)) {
+ if (domflag == 0) {
+ domflag = engine.isDominator(stat.id, head) ? 2 : 1;
+ }
+
+ if (domflag == 1) { // not a dominator
+ it.remove();
+ }
+ }
+ }
+
+ for (StatEdge edge : stat.getSuccessorEdges(StatEdge.TYPE_REGULAR)) {
+ if (!setVisited.contains(edge.getDestination())) {
+ stack.add(edge.getDestination());
+ stackPath.add(path.getCopy());
+ }
+ }
+ }
+
+ if (setPostdoms.isEmpty()) {
+ mapExtPostdominators.remove(head);
+ }
+ }
+ }
+
+
+ private void filterOnExceptionRanges(DominatorTreeExceptionFilter filter) {
+
+
+ for (Integer head : new HashSet<Integer>(mapExtPostdominators.keySet())) {
+
+ FastFixedSet<Integer> set = mapExtPostdominators.get(head);
+ for (Iterator<Integer> it = set.iterator(); it.hasNext(); ) {
+ if (!filter.acceptStatementPair(head, it.next())) {
+ it.remove();
+ }
+ }
+ if (set.isEmpty()) {
+ mapExtPostdominators.remove(head);
+ }
+ }
+ }
+
+
+ private void removeErroneousNodes() {
+
+ mapSupportPoints = new HashMap<Integer, FastFixedSet<Integer>>();
+
+ calcReachabilitySuppPoints(StatEdge.TYPE_REGULAR);
+
+ iterateReachability(new IReachabilityAction() {
+ public boolean action(Statement node, HashMap<Integer, FastFixedSet<Integer>> mapSets) {
+
+ Integer nodeid = node.id;
+
+ FastFixedSet<Integer> setReachability = mapSets.get(nodeid);
+ List<FastFixedSet<Integer>> lstPredSets = new ArrayList<FastFixedSet<Integer>>();
+
+ for (StatEdge prededge : node.getPredecessorEdges(StatEdge.TYPE_REGULAR)) {
+ FastFixedSet<Integer> setPred = mapSets.get(prededge.getSource().id);
+ if (setPred == null) {
+ setPred = mapSupportPoints.get(prededge.getSource().id);
+ }
+
+ // setPred cannot be empty as it is a reachability set
+ lstPredSets.add(setPred);
+ }
+
+ for (Integer id : setReachability.toPlainSet()) {
+
+ FastFixedSet<Integer> setReachabilityCopy = setReachability.getCopy();
+
+ FastFixedSet<Integer> setIntersection = factory.spawnEmptySet();
+ boolean isIntersectionInitialized = false;
+
+ for (FastFixedSet<Integer> predset : lstPredSets) {
+ if (predset.contains(id)) {
+ if (!isIntersectionInitialized) {
+ setIntersection.union(predset);
+ isIntersectionInitialized = true;
+ }
+ else {
+ setIntersection.intersection(predset);
+ }
+ }
+ }
+
+ if (nodeid != id.intValue()) {
+ setIntersection.add(nodeid);
+ }
+ else {
+ setIntersection.remove(nodeid);
+ }
+
+ setReachabilityCopy.complement(setIntersection);
+
+ mapExtPostdominators.get(id).complement(setReachabilityCopy);
+ }
+
+ return false;
+ }
+ }, StatEdge.TYPE_REGULAR);
+
+ // exception handlers cannot be postdominator nodes
+ // TODO: replace with a standard set?
+ FastFixedSet<Integer> setHandlers = factory.spawnEmptySet();
+ boolean handlerfound = false;
+
+ for (Statement stat : statement.getStats()) {
+ if (stat.getPredecessorEdges(Statement.STATEDGE_DIRECT_ALL).isEmpty() &&
+ !stat.getPredecessorEdges(StatEdge.TYPE_EXCEPTION).isEmpty()) { // exception handler
+ setHandlers.add(stat.id);
+ handlerfound = true;
+ }
+ }
+
+ if (handlerfound) {
+ for (FastFixedSet<Integer> set : mapExtPostdominators.values()) {
+ set.complement(setHandlers);
+ }
+ }
+ }
+
+
+ private void calcDefaultReachableSets() {
+
+ int edgetype = StatEdge.TYPE_REGULAR | StatEdge.TYPE_EXCEPTION;
+
+ calcReachabilitySuppPoints(edgetype);
+
+ for (Statement stat : statement.getStats()) {
+ mapExtPostdominators.put(stat.id, factory.spawnEmptySet());
+ }
+
+ iterateReachability(new IReachabilityAction() {
+ public boolean action(Statement node, HashMap<Integer, FastFixedSet<Integer>> mapSets) {
+
+ Integer nodeid = node.id;
+ FastFixedSet<Integer> setReachability = mapSets.get(nodeid);
+
+ for (Integer id : setReachability.toPlainSet()) {
+ mapExtPostdominators.get(id).add(nodeid);
+ }
+
+ return false;
+ }
+ }, edgetype);
+ }
+
+
+ private void calcReachabilitySuppPoints(final int edgetype) {
+
+ iterateReachability(new IReachabilityAction() {
+ public boolean action(Statement node, HashMap<Integer, FastFixedSet<Integer>> mapSets) {
+
+ // consider to be a support point
+ for (StatEdge sucedge : node.getAllSuccessorEdges()) {
+ if ((sucedge.getType() & edgetype) != 0) {
+ if (mapSets.containsKey(sucedge.getDestination().id)) {
+ FastFixedSet<Integer> setReachability = mapSets.get(node.id);
+
+ if (!InterpreterUtil.equalObjects(setReachability, mapSupportPoints.get(node.id))) {
+ mapSupportPoints.put(node.id, setReachability);
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+ }, edgetype);
+ }
+
+ private void iterateReachability(IReachabilityAction action, int edgetype) {
+
+ while (true) {
+
+ boolean iterate = false;
+
+ HashMap<Integer, FastFixedSet<Integer>> mapSets = new HashMap<Integer, FastFixedSet<Integer>>();
+
+ for (Statement stat : lstReversePostOrderList) {
+
+ FastFixedSet<Integer> set = factory.spawnEmptySet();
+ set.add(stat.id);
+
+ for (StatEdge prededge : stat.getAllPredecessorEdges()) {
+ if ((prededge.getType() & edgetype) != 0) {
+ Statement pred = prededge.getSource();
+
+ FastFixedSet<Integer> setPred = mapSets.get(pred.id);
+ if (setPred == null) {
+ setPred = mapSupportPoints.get(pred.id);
+ }
+
+ if (setPred != null) {
+ set.union(setPred);
+ }
+ }
+ }
+
+ mapSets.put(stat.id, set);
+
+ if (action != null) {
+ iterate |= action.action(stat, mapSets);
+ }
+
+ // remove reachability information of fully processed nodes (saves memory)
+ for (StatEdge prededge : stat.getAllPredecessorEdges()) {
+ if ((prededge.getType() & edgetype) != 0) {
+ Statement pred = prededge.getSource();
+
+ if (mapSets.containsKey(pred.id)) {
+ boolean remstat = true;
+ for (StatEdge sucedge : pred.getAllSuccessorEdges()) {
+ if ((sucedge.getType() & edgetype) != 0) {
+ if (!mapSets.containsKey(sucedge.getDestination().id)) {
+ remstat = false;
+ break;
+ }
+ }
+ }
+
+ if (remstat) {
+ mapSets.put(pred.id, null);
+ }
+ }
+ }
+ }
+ }
+
+ if (!iterate) {
+ break;
+ }
+ }
+ }
+
+
+ private interface IReachabilityAction {
+ boolean action(Statement node, HashMap<Integer, FastFixedSet<Integer>> mapSets);
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/GenericDominatorEngine.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/GenericDominatorEngine.java
new file mode 100644
index 000000000000..c6eb35722eb6
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/GenericDominatorEngine.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.decompose;
+
+import org.jetbrains.java.decompiler.util.VBStyleCollection;
+
+import java.util.List;
+import java.util.Set;
+
+public class GenericDominatorEngine {
+
+ private IGraph graph;
+
+ private VBStyleCollection<IGraphNode, IGraphNode> colOrderedIDoms = new VBStyleCollection<IGraphNode, IGraphNode>();
+
+ private Set<? extends IGraphNode> setRoots;
+
+ public GenericDominatorEngine(IGraph graph) {
+ this.graph = graph;
+ }
+
+ public void initialize() {
+ calcIDoms();
+ }
+
+ private void orderNodes() {
+
+ setRoots = graph.getRoots();
+
+ for (IGraphNode node : graph.getReversePostOrderList()) {
+ colOrderedIDoms.addWithKey(null, node);
+ }
+ }
+
+ private static IGraphNode getCommonIDom(IGraphNode node1, IGraphNode node2, VBStyleCollection<IGraphNode, IGraphNode> orderedIDoms) {
+
+ IGraphNode nodeOld;
+
+ if (node1 == null) {
+ return node2;
+ }
+ else if (node2 == null) {
+ return node1;
+ }
+
+ int index1 = orderedIDoms.getIndexByKey(node1);
+ int index2 = orderedIDoms.getIndexByKey(node2);
+
+ while (index1 != index2) {
+ if (index1 > index2) {
+ nodeOld = node1;
+ node1 = orderedIDoms.getWithKey(node1);
+
+ if (nodeOld == node1) { // no idom - root or merging point
+ return null;
+ }
+
+ index1 = orderedIDoms.getIndexByKey(node1);
+ }
+ else {
+ nodeOld = node2;
+ node2 = orderedIDoms.getWithKey(node2);
+
+ if (nodeOld == node2) { // no idom - root or merging point
+ return null;
+ }
+
+ index2 = orderedIDoms.getIndexByKey(node2);
+ }
+ }
+
+ return node1;
+ }
+
+ private void calcIDoms() {
+
+ orderNodes();
+
+ List<IGraphNode> lstNodes = colOrderedIDoms.getLstKeys();
+
+ while (true) {
+
+ boolean changed = false;
+
+ for (IGraphNode node : lstNodes) {
+
+ IGraphNode idom = null;
+
+ if (!setRoots.contains(node)) {
+ for (IGraphNode pred : node.getPredecessors()) {
+ if (colOrderedIDoms.getWithKey(pred) != null) {
+ idom = getCommonIDom(idom, pred, colOrderedIDoms);
+ if (idom == null) {
+ break; // no idom found: merging point of two trees
+ }
+ }
+ }
+ }
+
+ if (idom == null) {
+ idom = node;
+ }
+
+ IGraphNode oldidom = colOrderedIDoms.putWithKey(idom, node);
+ if (!idom.equals(oldidom)) { // oldidom is null iff the node is touched for the first time
+ changed = true;
+ }
+ }
+
+ if (!changed) {
+ break;
+ }
+ }
+ }
+
+ public VBStyleCollection<IGraphNode, IGraphNode> getOrderedIDoms() {
+ return colOrderedIDoms;
+ }
+
+ public boolean isDominator(IGraphNode node, IGraphNode dom) {
+
+ while (!node.equals(dom)) {
+
+ IGraphNode idom = colOrderedIDoms.getWithKey(node);
+
+ if (idom == node) {
+ return false; // root node or merging point
+ }
+ else if (idom == null) {
+ throw new RuntimeException("Inconsistent idom sequence discovered!");
+ }
+ else {
+ node = idom;
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/IGraph.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/IGraph.java
new file mode 100644
index 000000000000..faaf4c6b66cf
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/IGraph.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.decompose;
+
+import java.util.List;
+import java.util.Set;
+
+public interface IGraph {
+
+ List<? extends IGraphNode> getReversePostOrderList();
+
+ Set<? extends IGraphNode> getRoots();
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/IGraphNode.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/IGraphNode.java
new file mode 100644
index 000000000000..19d59b5acb32
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/decompose/IGraphNode.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.decompose;
+
+import java.util.List;
+
+public interface IGraphNode {
+
+ List<? extends IGraphNode> getPredecessors();
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/deobfuscator/ExceptionDeobfuscator.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/deobfuscator/ExceptionDeobfuscator.java
new file mode 100644
index 000000000000..7614807c99a4
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/deobfuscator/ExceptionDeobfuscator.java
@@ -0,0 +1,330 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.deobfuscator;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.code.Instruction;
+import org.jetbrains.java.decompiler.code.InstructionSequence;
+import org.jetbrains.java.decompiler.code.SimpleInstructionSequence;
+import org.jetbrains.java.decompiler.code.cfg.BasicBlock;
+import org.jetbrains.java.decompiler.code.cfg.ControlFlowGraph;
+import org.jetbrains.java.decompiler.code.cfg.ExceptionRangeCFG;
+import org.jetbrains.java.decompiler.modules.decompiler.decompose.GenericDominatorEngine;
+import org.jetbrains.java.decompiler.modules.decompiler.decompose.IGraph;
+import org.jetbrains.java.decompiler.modules.decompiler.decompose.IGraphNode;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+
+import java.util.*;
+import java.util.Map.Entry;
+
+public class ExceptionDeobfuscator {
+
+ private static class Range {
+ private final BasicBlock handler;
+ private final String uniqueStr;
+ private final Set<BasicBlock> protectedRange;
+ private final ExceptionRangeCFG rangeCFG;
+
+ private Range(BasicBlock handler, String uniqueStr, Set<BasicBlock> protectedRange, ExceptionRangeCFG rangeCFG) {
+ this.handler = handler;
+ this.uniqueStr = uniqueStr;
+ this.protectedRange = protectedRange;
+ this.rangeCFG = rangeCFG;
+ }
+ }
+
+ public static void restorePopRanges(ControlFlowGraph graph) {
+
+ List<Range> lstRanges = new ArrayList<Range>();
+
+ // aggregate ranges
+ for (ExceptionRangeCFG range : graph.getExceptions()) {
+ boolean found = false;
+ for (Range arr : lstRanges) {
+ if (arr.handler == range.getHandler() && InterpreterUtil.equalObjects(range.getUniqueExceptionsString(), arr.uniqueStr)) {
+ arr.protectedRange.addAll(range.getProtectedRange());
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ // doesn't matter, which range chosen
+ lstRanges.add(new Range(range.getHandler(), range.getUniqueExceptionsString(), new HashSet<BasicBlock>(range.getProtectedRange()), range));
+ }
+ }
+
+ // process aggregated ranges
+ for (Range range : lstRanges) {
+
+ if (range.uniqueStr != null) {
+
+ BasicBlock handler = range.handler;
+ InstructionSequence seq = handler.getSeq();
+
+ Instruction firstinstr;
+ if (seq.length() > 0) {
+ firstinstr = seq.getInstr(0);
+
+ if (firstinstr.opcode == CodeConstants.opc_pop ||
+ firstinstr.opcode == CodeConstants.opc_astore) {
+ Set<BasicBlock> setrange = new HashSet<BasicBlock>(range.protectedRange);
+
+ for (Range range_super : lstRanges) { // finally or strict superset
+
+ if (range != range_super) {
+
+ Set<BasicBlock> setrange_super = new HashSet<BasicBlock>(range_super.protectedRange);
+
+ if (!setrange.contains(range_super.handler) && !setrange_super.contains(handler)
+ && (range_super.uniqueStr == null || setrange_super.containsAll(setrange))) {
+
+ if (range_super.uniqueStr == null) {
+ setrange_super.retainAll(setrange);
+ }
+ else {
+ setrange_super.removeAll(setrange);
+ }
+
+ if (!setrange_super.isEmpty()) {
+
+ BasicBlock newblock = handler;
+
+ // split the handler
+ if (seq.length() > 1) {
+ newblock = new BasicBlock(++graph.last_id);
+ InstructionSequence newseq = new SimpleInstructionSequence();
+ newseq.addInstruction(firstinstr.clone(), -1);
+
+ newblock.setSeq(newseq);
+ graph.getBlocks().addWithKey(newblock, newblock.id);
+
+
+ List<BasicBlock> lstTemp = new ArrayList<BasicBlock>();
+ lstTemp.addAll(handler.getPreds());
+ lstTemp.addAll(handler.getPredExceptions());
+
+ // replace predecessors
+ for (BasicBlock pred : lstTemp) {
+ pred.replaceSuccessor(handler, newblock);
+ }
+
+ // replace handler
+ for (ExceptionRangeCFG range_ext : graph.getExceptions()) {
+ if (range_ext.getHandler() == handler) {
+ range_ext.setHandler(newblock);
+ }
+ else if (range_ext.getProtectedRange().contains(handler)) {
+ newblock.addSuccessorException(range_ext.getHandler());
+ range_ext.getProtectedRange().add(newblock);
+ }
+ }
+
+ newblock.addSuccessor(handler);
+ if (graph.getFirst() == handler) {
+ graph.setFirst(newblock);
+ }
+
+ // remove the first pop in the handler
+ seq.removeInstruction(0);
+ }
+
+ newblock.addSuccessorException(range_super.handler);
+ range_super.rangeCFG.getProtectedRange().add(newblock);
+
+ handler = range.rangeCFG.getHandler();
+ seq = handler.getSeq();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public static void insertEmptyExceptionHandlerBlocks(ControlFlowGraph graph) {
+
+ Set<BasicBlock> setVisited = new HashSet<BasicBlock>();
+
+ for (ExceptionRangeCFG range : graph.getExceptions()) {
+ BasicBlock handler = range.getHandler();
+
+ if (setVisited.contains(handler)) {
+ continue;
+ }
+ setVisited.add(handler);
+
+ BasicBlock emptyblock = new BasicBlock(++graph.last_id);
+ graph.getBlocks().addWithKey(emptyblock, emptyblock.id);
+
+ List<BasicBlock> lstTemp = new ArrayList<BasicBlock>();
+ // only exception predecessors considered
+ lstTemp.addAll(handler.getPredExceptions());
+
+ // replace predecessors
+ for (BasicBlock pred : lstTemp) {
+ pred.replaceSuccessor(handler, emptyblock);
+ }
+
+ // replace handler
+ for (ExceptionRangeCFG range_ext : graph.getExceptions()) {
+ if (range_ext.getHandler() == handler) {
+ range_ext.setHandler(emptyblock);
+ }
+ else if (range_ext.getProtectedRange().contains(handler)) {
+ emptyblock.addSuccessorException(range_ext.getHandler());
+ range_ext.getProtectedRange().add(emptyblock);
+ }
+ }
+
+ emptyblock.addSuccessor(handler);
+ if (graph.getFirst() == handler) {
+ graph.setFirst(emptyblock);
+ }
+ }
+ }
+
+ public static void removeEmptyRanges(ControlFlowGraph graph) {
+
+ List<ExceptionRangeCFG> lstRanges = graph.getExceptions();
+ for (int i = lstRanges.size() - 1; i >= 0; i--) {
+ ExceptionRangeCFG range = lstRanges.get(i);
+
+ boolean isEmpty = true;
+ for (BasicBlock block : range.getProtectedRange()) {
+ if (!block.getSeq().isEmpty()) {
+ isEmpty = false;
+ break;
+ }
+ }
+
+ if (isEmpty) {
+ for (BasicBlock block : range.getProtectedRange()) {
+ block.removeSuccessorException(range.getHandler());
+ }
+
+ lstRanges.remove(i);
+ }
+ }
+ }
+
+ public static void removeCircularRanges(final ControlFlowGraph graph) {
+
+ GenericDominatorEngine engine = new GenericDominatorEngine(new IGraph() {
+ public List<? extends IGraphNode> getReversePostOrderList() {
+ return graph.getReversePostOrder();
+ }
+
+ public Set<? extends IGraphNode> getRoots() {
+ return new HashSet<IGraphNode>(Arrays.asList(new IGraphNode[]{graph.getFirst()}));
+ }
+ });
+
+ engine.initialize();
+
+ List<ExceptionRangeCFG> lstRanges = graph.getExceptions();
+ for (int i = lstRanges.size() - 1; i >= 0; i--) {
+ ExceptionRangeCFG range = lstRanges.get(i);
+
+ BasicBlock handler = range.getHandler();
+ List<BasicBlock> rangeList = range.getProtectedRange();
+
+ if (rangeList.contains(handler)) { // TODO: better removing strategy
+
+ List<BasicBlock> lstRemBlocks = getReachableBlocksRestricted(range, engine);
+
+ if (lstRemBlocks.size() < rangeList.size() || rangeList.size() == 1) {
+ for (BasicBlock block : lstRemBlocks) {
+ block.removeSuccessorException(handler);
+ rangeList.remove(block);
+ }
+ }
+
+ if (rangeList.isEmpty()) {
+ lstRanges.remove(i);
+ }
+ }
+ }
+ }
+
+ private static List<BasicBlock> getReachableBlocksRestricted(ExceptionRangeCFG range, GenericDominatorEngine engine) {
+
+ List<BasicBlock> lstRes = new ArrayList<BasicBlock>();
+
+ LinkedList<BasicBlock> stack = new LinkedList<BasicBlock>();
+ Set<BasicBlock> setVisited = new HashSet<BasicBlock>();
+
+ BasicBlock handler = range.getHandler();
+ stack.addFirst(handler);
+
+ while (!stack.isEmpty()) {
+ BasicBlock block = stack.removeFirst();
+
+ setVisited.add(block);
+
+ if (range.getProtectedRange().contains(block) && engine.isDominator(block, handler)) {
+ lstRes.add(block);
+
+ List<BasicBlock> lstSuccs = new ArrayList<BasicBlock>(block.getSuccs());
+ lstSuccs.addAll(block.getSuccExceptions());
+
+ for (BasicBlock succ : lstSuccs) {
+ if (!setVisited.contains(succ)) {
+ stack.add(succ);
+ }
+ }
+ }
+ }
+
+ return lstRes;
+ }
+
+
+ public static boolean hasObfuscatedExceptions(ControlFlowGraph graph) {
+
+ Map<BasicBlock, Set<BasicBlock>> mapRanges = new HashMap<BasicBlock, Set<BasicBlock>>();
+ for (ExceptionRangeCFG range : graph.getExceptions()) {
+ Set<BasicBlock> set = mapRanges.get(range.getHandler());
+ if (set == null) {
+ mapRanges.put(range.getHandler(), set = new HashSet<BasicBlock>());
+ }
+ set.addAll(range.getProtectedRange());
+ }
+
+ for (Entry<BasicBlock, Set<BasicBlock>> ent : mapRanges.entrySet()) {
+ Set<BasicBlock> setEntries = new HashSet<BasicBlock>();
+
+ for (BasicBlock block : ent.getValue()) {
+ Set<BasicBlock> setTemp = new HashSet<BasicBlock>(block.getPreds());
+ setTemp.removeAll(ent.getValue());
+
+ if (!setTemp.isEmpty()) {
+ setEntries.add(block);
+ }
+ }
+
+ if (!setEntries.isEmpty()) {
+ if (setEntries.size() > 1 /*|| ent.getValue().contains(first)*/) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/deobfuscator/IrreducibleCFGDeobfuscator.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/deobfuscator/IrreducibleCFGDeobfuscator.java
new file mode 100644
index 000000000000..31e171e214d5
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/deobfuscator/IrreducibleCFGDeobfuscator.java
@@ -0,0 +1,245 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.deobfuscator;
+
+import org.jetbrains.java.decompiler.modules.decompiler.StatEdge;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.BasicBlockStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
+
+
+public class IrreducibleCFGDeobfuscator {
+
+
+ public static boolean isStatementIrreducible(Statement statement) {
+
+ class Node {
+ public Integer id;
+ public Set<Node> preds = new HashSet<Node>();
+ public Set<Node> succs = new HashSet<Node>();
+
+ public Node(Integer id) {
+ this.id = id;
+ }
+ }
+
+ HashMap<Integer, Node> mapNodes = new HashMap<Integer, Node>();
+
+ // checking exceptions and creating nodes
+ for (Statement stat : statement.getStats()) {
+ if (!stat.getSuccessorEdges(StatEdge.TYPE_EXCEPTION).isEmpty()) {
+ return false;
+ }
+
+ mapNodes.put(stat.id, new Node(stat.id));
+ }
+
+ // connecting nodes
+ for (Statement stat : statement.getStats()) {
+ Node node = mapNodes.get(stat.id);
+
+ for (Statement succ : stat.getNeighbours(StatEdge.TYPE_REGULAR, Statement.DIRECTION_FORWARD)) {
+ Node nodeSucc = mapNodes.get(succ.id);
+
+ node.succs.add(nodeSucc);
+ nodeSucc.preds.add(node);
+ }
+ }
+
+ // transforming and reducing the graph
+ while (true) {
+ int ttype = 0;
+ Node node = null;
+
+ for (Node nd : mapNodes.values()) {
+ if (nd.succs.contains(nd)) { // T1
+ ttype = 1;
+ }
+ else if (nd.preds.size() == 1) { // T2
+ ttype = 2;
+ }
+
+ if (ttype != 0) {
+ node = nd;
+ break;
+ }
+ }
+
+ if (node != null) {
+ if (ttype == 1) {
+ node.succs.remove(node);
+ node.preds.remove(node);
+ }
+ else {
+ Node pred = node.preds.iterator().next();
+
+ pred.succs.addAll(node.succs);
+ pred.succs.remove(node);
+
+ for (Node succ : node.succs) {
+ succ.preds.remove(node);
+ succ.preds.add(pred);
+ }
+
+ mapNodes.remove(node.id);
+ }
+ }
+ else { // no transformation applicable
+ return mapNodes.size() > 1; // reducible iff one node remains
+ }
+ }
+ }
+
+
+ private static Statement getCandidateForSplitting(Statement statement) {
+
+ Statement candidateForSplitting = null;
+ int sizeCandidateForSplitting = Integer.MAX_VALUE;
+ int succsCandidateForSplitting = Integer.MAX_VALUE;
+
+ for (Statement stat : statement.getStats()) {
+
+ Set<Statement> setPreds = stat.getNeighboursSet(StatEdge.TYPE_REGULAR, Statement.DIRECTION_BACKWARD);
+
+ if (setPreds.size() > 1) {
+ int succCount = stat.getNeighboursSet(StatEdge.TYPE_REGULAR, Statement.DIRECTION_FORWARD).size();
+ if (succCount <= succsCandidateForSplitting) {
+ int size = getStatementSize(stat) * (setPreds.size() - 1);
+
+ if (succCount < succsCandidateForSplitting ||
+ size < sizeCandidateForSplitting) {
+ candidateForSplitting = stat;
+ sizeCandidateForSplitting = size;
+ succsCandidateForSplitting = succCount;
+ }
+ }
+ }
+ }
+
+ return candidateForSplitting;
+ }
+
+ public static boolean splitIrreducibleNode(Statement statement) {
+
+ Statement splitnode = getCandidateForSplitting(statement);
+ if (splitnode == null) {
+ return false;
+ }
+
+ StatEdge enteredge = splitnode.getPredecessorEdges(StatEdge.TYPE_REGULAR).iterator().next();
+
+ // copy the smallest statement
+ Statement splitcopy = copyStatement(splitnode, null, new HashMap<Statement, Statement>());
+ initCopiedStatement(splitcopy);
+
+ // insert the copy
+ splitcopy.setParent(statement);
+ statement.getStats().addWithKey(splitcopy, splitcopy.id);
+
+ // switch input edges
+ for (StatEdge prededge : splitnode.getPredecessorEdges(Statement.STATEDGE_DIRECT_ALL)) {
+ if (prededge.getSource() == enteredge.getSource() ||
+ prededge.closure == enteredge.getSource()) {
+ splitnode.removePredecessor(prededge);
+ prededge.getSource().changeEdgeNode(Statement.DIRECTION_FORWARD, prededge, splitcopy);
+ splitcopy.addPredecessor(prededge);
+ }
+ }
+
+ // connect successors
+ for (StatEdge succ : splitnode.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL)) {
+ splitcopy.addSuccessor(new StatEdge(succ.getType(), splitcopy, succ.getDestination(), succ.closure));
+ }
+
+ return true;
+ }
+
+ private static int getStatementSize(Statement statement) {
+
+ int res = 0;
+
+ if (statement.type == Statement.TYPE_BASICBLOCK) {
+ res = ((BasicBlockStatement)statement).getBlock().getSeq().length();
+ }
+ else {
+ for (Statement stat : statement.getStats()) {
+ res += getStatementSize(stat);
+ }
+ }
+
+ return res;
+ }
+
+ private static Statement copyStatement(Statement from, Statement to, HashMap<Statement, Statement> mapAltToCopies) {
+
+ if (to == null) {
+ // first outer invocation
+ to = from.getSimpleCopy();
+ mapAltToCopies.put(from, to);
+ }
+
+ // copy statements
+ for (Statement st : from.getStats()) {
+ Statement stcopy = st.getSimpleCopy();
+
+ to.getStats().addWithKey(stcopy, stcopy.id);
+ mapAltToCopies.put(st, stcopy);
+ }
+
+ // copy edges
+ for (int i = 0; i < from.getStats().size(); i++) {
+ Statement stold = from.getStats().get(i);
+ Statement stnew = to.getStats().get(i);
+
+ for (StatEdge edgeold : stold.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL)) {
+ // type cannot be TYPE_EXCEPTION (checked in isIrreducibleTriangle)
+ StatEdge edgenew = new StatEdge(edgeold.getType(), stnew,
+ mapAltToCopies.containsKey(edgeold.getDestination())
+ ? mapAltToCopies.get(edgeold.getDestination())
+ : edgeold.getDestination(),
+ mapAltToCopies.containsKey(edgeold.closure)
+ ? mapAltToCopies.get(edgeold.closure)
+ : edgeold.closure);
+
+ stnew.addSuccessor(edgenew);
+ }
+ }
+
+ // recurse statements
+ for (int i = 0; i < from.getStats().size(); i++) {
+ Statement stold = from.getStats().get(i);
+ Statement stnew = to.getStats().get(i);
+
+ copyStatement(stold, stnew, mapAltToCopies);
+ }
+
+ return to;
+ }
+
+ private static void initCopiedStatement(Statement statement) {
+
+ statement.initSimpleCopy();
+ statement.setCopied(true);
+
+ for (Statement st : statement.getStats()) {
+ st.setParent(statement);
+ initCopiedStatement(st);
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AnnotationExprent.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AnnotationExprent.java
new file mode 100644
index 000000000000..9383d76559a5
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AnnotationExprent.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.exps;
+
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+
+import java.util.List;
+
+
+public class AnnotationExprent extends Exprent {
+
+ public static final int ANNOTATION_NORMAL = 1;
+ public static final int ANNOTATION_MARKER = 2;
+ public static final int ANNOTATION_SINGLE_ELEMENT = 3;
+
+
+ private String classname;
+
+ private List<String> parnames;
+
+ private List<Exprent> parvalues;
+
+ {
+ this.type = EXPRENT_ANNOTATION;
+ }
+
+ public AnnotationExprent(String classname, List<String> parnames, List<Exprent> parvalues) {
+ this.classname = classname;
+ this.parnames = parnames;
+ this.parvalues = parvalues;
+ }
+
+ public String toJava(int indent) {
+
+ String new_line_separator = DecompilerContext.getNewLineSeparator();
+
+ StringBuilder buffer = new StringBuilder();
+ String indstr = InterpreterUtil.getIndentString(indent);
+
+ buffer.append(indstr);
+ buffer.append("@");
+ buffer.append(DecompilerContext.getImportCollector().getShortName(ExprProcessor.buildJavaClassName(classname)));
+
+ if (!parnames.isEmpty()) {
+ buffer.append("(");
+ if (parnames.size() == 1 && "value".equals(parnames.get(0))) {
+ buffer.append(parvalues.get(0).toJava(indent + 1));
+ }
+ else {
+ String indstr1 = InterpreterUtil.getIndentString(indent + 1);
+
+ for (int i = 0; i < parnames.size(); i++) {
+ buffer.append(new_line_separator).append(indstr1);
+ buffer.append(parnames.get(i));
+ buffer.append(" = ");
+ buffer.append(parvalues.get(i).toJava(indent + 2));
+
+ if (i < parnames.size() - 1) {
+ buffer.append(",");
+ }
+ }
+ buffer.append(new_line_separator).append(indstr);
+ }
+
+ buffer.append(")");
+ }
+
+ return buffer.toString();
+ }
+
+ public int getAnnotationType() {
+
+ if (parnames.isEmpty()) {
+ return ANNOTATION_MARKER;
+ }
+ else {
+ if (parnames.size() == 1 && "value".equals(parnames.get(0))) {
+ return ANNOTATION_SINGLE_ELEMENT;
+ }
+ else {
+ return ANNOTATION_NORMAL;
+ }
+ }
+ }
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof AnnotationExprent)) return false;
+
+ AnnotationExprent ann = (AnnotationExprent)o;
+ return classname.equals(ann.classname) &&
+ InterpreterUtil.equalLists(parnames, ann.parnames) &&
+ InterpreterUtil.equalLists(parvalues, ann.parvalues);
+ }
+
+ public String getClassname() {
+ return classname;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ArrayExprent.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ArrayExprent.java
new file mode 100644
index 000000000000..e5ead9d7c184
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ArrayExprent.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.exps;
+
+import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.CheckTypesResult;
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class ArrayExprent extends Exprent {
+
+ private Exprent array;
+
+ private Exprent index;
+
+ private VarType hardtype;
+
+ {
+ this.type = EXPRENT_ARRAY;
+ }
+
+ public ArrayExprent(Exprent array, Exprent index, VarType hardtype) {
+ this.array = array;
+ this.index = index;
+ this.hardtype = hardtype;
+ }
+
+ public Exprent copy() {
+ return new ArrayExprent(array.copy(), index.copy(), hardtype);
+ }
+
+ public VarType getExprType() {
+ VarType exprType = array.getExprType().copy();
+ if (exprType.equals(VarType.VARTYPE_NULL)) {
+ exprType = hardtype.copy();
+ }
+ else {
+ exprType.decArrayDim();
+ }
+
+ return exprType;
+ }
+
+ public int getExprentUse() {
+ return array.getExprentUse() & index.getExprentUse() & Exprent.MULTIPLE_USES;
+ }
+
+ public CheckTypesResult checkExprTypeBounds() {
+ CheckTypesResult result = new CheckTypesResult();
+
+ result.addMinTypeExprent(index, VarType.VARTYPE_BYTECHAR);
+ result.addMaxTypeExprent(index, VarType.VARTYPE_INT);
+
+ return result;
+ }
+
+ public List<Exprent> getAllExprents() {
+ List<Exprent> lst = new ArrayList<Exprent>();
+ lst.add(array);
+ lst.add(index);
+ return lst;
+ }
+
+
+ public String toJava(int indent) {
+ String res = array.toJava(indent);
+
+ if (array.getPrecedence() > getPrecedence()) { // array precedence equals 0
+ res = "(" + res + ")";
+ }
+
+ VarType arrtype = array.getExprType();
+ if (arrtype.arraydim == 0) {
+ VarType objarr = VarType.VARTYPE_OBJECT.copy();
+ objarr.arraydim = 1; // type family does not change
+
+ res = "((" + ExprProcessor.getCastTypeName(objarr) + ")" + res + ")";
+ }
+
+ return res + "[" + index.toJava(indent) + "]";
+ }
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof ArrayExprent)) return false;
+
+ ArrayExprent arr = (ArrayExprent)o;
+ return InterpreterUtil.equalObjects(array, arr.getArray()) &&
+ InterpreterUtil.equalObjects(index, arr.getIndex());
+ }
+
+ public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
+ if (oldexpr == array) {
+ array = newexpr;
+ }
+
+ if (oldexpr == index) {
+ index = newexpr;
+ }
+ }
+
+ public Exprent getArray() {
+ return array;
+ }
+
+ public Exprent getIndex() {
+ return index;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssertExprent.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssertExprent.java
new file mode 100644
index 000000000000..0983dad0cd9d
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssertExprent.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.exps;
+
+import java.util.List;
+
+public class AssertExprent extends Exprent {
+
+ private List<Exprent> parameters;
+
+ {
+ this.type = EXPRENT_ASSERT;
+ }
+
+ public AssertExprent(List<Exprent> parameters) {
+ this.parameters = parameters;
+ }
+
+ public String toJava(int indent) {
+
+ StringBuilder buffer = new StringBuilder();
+
+ buffer.append("assert ");
+
+ if (parameters.get(0) == null) {
+ buffer.append("false");
+ }
+ else {
+ buffer.append(parameters.get(0).toJava(indent));
+ }
+ if (parameters.size() > 1) {
+ buffer.append(" : ");
+ buffer.append(parameters.get(1).toJava(indent));
+ }
+
+ return buffer.toString();
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java
new file mode 100644
index 000000000000..8ff9fe5a448a
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/AssignmentExprent.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.exps;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.CheckTypesResult;
+import org.jetbrains.java.decompiler.struct.StructField;
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class AssignmentExprent extends Exprent {
+
+ public static final int CONDITION_NONE = -1;
+
+ private static final String[] funceq = new String[]{
+ " += ", // FUNCTION_ADD
+ " -= ", // FUNCTION_SUB
+ " *= ", // FUNCTION_MUL
+ " /= ", // FUNCTION_DIV
+ " &= ", // FUNCTION_AND
+ " |= ", // FUNCTION_OR
+ " ^= ", // FUNCTION_XOR
+ " %= ", // FUNCTION_REM
+ " <<= ", // FUNCTION_SHL
+ " >>= ", // FUNCTION_SHR
+ " >>>= " // FUNCTION_USHR
+ };
+
+
+ private Exprent left;
+
+ private Exprent right;
+
+ private int condtype = CONDITION_NONE;
+
+ {
+ this.type = EXPRENT_ASSIGNMENT;
+ }
+
+
+ public AssignmentExprent(Exprent left, Exprent right) {
+ this.left = left;
+ this.right = right;
+ }
+
+
+ public VarType getExprType() {
+ return left.getExprType();
+ }
+
+
+ public CheckTypesResult checkExprTypeBounds() {
+ CheckTypesResult result = new CheckTypesResult();
+
+ VarType typeleft = left.getExprType();
+ VarType typeright = right.getExprType();
+
+ if (typeleft.type_family > typeright.type_family) {
+ result.addMinTypeExprent(right, VarType.getMinTypeInFamily(typeleft.type_family));
+ }
+ else if (typeleft.type_family < typeright.type_family) {
+ result.addMinTypeExprent(left, typeright);
+ }
+ else {
+ result.addMinTypeExprent(left, VarType.getCommonSupertype(typeleft, typeright));
+ }
+
+ return result;
+ }
+
+ public List<Exprent> getAllExprents() {
+ List<Exprent> lst = new ArrayList<Exprent>();
+ lst.add(left);
+ lst.add(right);
+ return lst;
+ }
+
+ public Exprent copy() {
+ return new AssignmentExprent(left.copy(), right.copy());
+ }
+
+ public int getPrecedence() {
+ return 13;
+ }
+
+ public String toJava(int indent) {
+ VarType leftType = left.getExprType();
+ VarType rightType = right.getExprType();
+
+ boolean fieldInClassInit = false, hiddenField = false;
+ if (left.type == Exprent.EXPRENT_FIELD) { // first assignment to a final field. Field name without "this" in front of it
+ FieldExprent field = (FieldExprent)left;
+ ClassNode node = ((ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_NODE));
+ if (node != null) {
+ StructField fd = node.classStruct.getField(field.getName(), field.getDescriptor().descriptorString);
+ if (fd != null) {
+ if (field.isStatic() && fd.hasModifier(CodeConstants.ACC_FINAL)) {
+ fieldInClassInit = true;
+ }
+ if (node.wrapper.getHiddenMembers().contains(InterpreterUtil.makeUniqueKey(fd.getName(), fd.getDescriptor()))) {
+ hiddenField = true;
+ }
+ }
+ }
+ }
+
+ if (hiddenField) {
+ return "";
+ }
+
+ StringBuilder buffer = new StringBuilder();
+
+ if (fieldInClassInit) {
+ buffer.append(((FieldExprent)left).getName());
+ }
+ else {
+ buffer.append(left.toJava(indent));
+ }
+
+ String res = right.toJava(indent);
+
+ if (condtype == CONDITION_NONE &&
+ !leftType.isSuperset(rightType) &&
+ (rightType.equals(VarType.VARTYPE_OBJECT) || leftType.type != CodeConstants.TYPE_OBJECT)) {
+ if (right.getPrecedence() >= FunctionExprent.getPrecedence(FunctionExprent.FUNCTION_CAST)) {
+ res = "(" + res + ")";
+ }
+
+ res = "(" + ExprProcessor.getCastTypeName(leftType) + ")" + res;
+ }
+
+ buffer.append(condtype == CONDITION_NONE ? " = " : funceq[condtype]).append(res);
+
+ return buffer.toString();
+ }
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof AssignmentExprent)) return false;
+
+ AssignmentExprent as = (AssignmentExprent)o;
+ return InterpreterUtil.equalObjects(left, as.getLeft()) &&
+ InterpreterUtil.equalObjects(right, as.getRight()) &&
+ condtype == as.getCondtype();
+ }
+
+ public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
+ if (oldexpr == left) {
+ left = newexpr;
+ }
+
+ if (oldexpr == right) {
+ right = newexpr;
+ }
+ }
+
+ // *****************************************************************************
+ // getter and setter methods
+ // *****************************************************************************
+
+ public Exprent getLeft() {
+ return left;
+ }
+
+ public void setLeft(Exprent left) {
+ this.left = left;
+ }
+
+ public Exprent getRight() {
+ return right;
+ }
+
+ public void setRight(Exprent right) {
+ this.right = right;
+ }
+
+ public int getCondtype() {
+ return condtype;
+ }
+
+ public void setCondtype(int condtype) {
+ this.condtype = condtype;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java
new file mode 100644
index 000000000000..a45429a85803
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ConstExprent.java
@@ -0,0 +1,402 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.exps;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
+import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
+import org.jetbrains.java.decompiler.struct.gen.FieldDescriptor;
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+public class ConstExprent extends Exprent {
+ private static final HashMap<Integer, String> escapes = new HashMap<Integer, String>();
+
+ static {
+ escapes.put(new Integer(0x8), "\\b"); /* \u0008: backspace BS */
+ escapes.put(new Integer(0x9), "\\t"); /* \u0009: horizontal tab HT */
+ escapes.put(new Integer(0xA), "\\n"); /* \u000a: linefeed LF */
+ escapes.put(new Integer(0xC), "\\f"); /* \u000c: form feed FF */
+ escapes.put(new Integer(0xD), "\\r"); /* \u000d: carriage return CR */
+ escapes.put(new Integer(0x22), "\\\""); /* \u0022: double quote " */
+ escapes.put(new Integer(0x27), "\\\'"); /* \u0027: single quote ' */
+ escapes.put(new Integer(0x5C), "\\\\"); /* \u005c: backslash \ */
+ }
+
+
+ private VarType consttype;
+
+ private Object value;
+
+ private boolean boolPermitted;
+
+ {
+ this.type = EXPRENT_CONST;
+ }
+
+ public ConstExprent(int val, boolean boolPermitted) {
+
+ this.boolPermitted = boolPermitted;
+ if (boolPermitted) {
+ consttype = VarType.VARTYPE_BOOLEAN;
+ if (val != 0 && val != 1) {
+ consttype = consttype.copy();
+ consttype.convinfo |= VarType.FALSEBOOLEAN;
+ }
+ }
+ else {
+ if (0 <= val && val <= 127) {
+ consttype = VarType.VARTYPE_BYTECHAR;
+ }
+ else if (-128 <= val && val <= 127) {
+ consttype = VarType.VARTYPE_BYTE;
+ }
+ else if (0 <= val && val <= 32767) {
+ consttype = VarType.VARTYPE_SHORTCHAR;
+ }
+ else if (-32768 <= val && val <= 32767) {
+ consttype = VarType.VARTYPE_SHORT;
+ }
+ else if (0 <= val && val <= 0xFFFF) {
+ consttype = VarType.VARTYPE_CHAR;
+ }
+ else {
+ consttype = VarType.VARTYPE_INT;
+ }
+ }
+ value = new Integer(val);
+ }
+
+ public ConstExprent(VarType consttype, Object value) {
+ this.consttype = consttype;
+ this.value = value;
+ }
+
+ public Exprent copy() {
+ return new ConstExprent(consttype, value);
+ }
+
+ public VarType getExprType() {
+ return consttype;
+ }
+
+ public int getExprentUse() {
+ return Exprent.MULTIPLE_USES | Exprent.SIDE_EFFECTS_FREE;
+ }
+
+ public List<Exprent> getAllExprents() {
+ return new ArrayList<Exprent>();
+ }
+
+ public String toJava(int indent) {
+ boolean literal = DecompilerContext.getOption(IFernflowerPreferences.LITERALS_AS_IS);
+ boolean ascii = DecompilerContext.getOption(IFernflowerPreferences.ASCII_STRING_CHARACTERS);
+
+ if (consttype.type != CodeConstants.TYPE_NULL && value == null) {
+ return ExprProcessor.getCastTypeName(consttype);
+ }
+ else {
+ switch (consttype.type) {
+ case CodeConstants.TYPE_BOOLEAN:
+ return Boolean.toString(((Integer)value).intValue() != 0);
+ case CodeConstants.TYPE_CHAR:
+ Integer val = (Integer)value;
+ String ret = escapes.get(val);
+ if (ret == null) {
+ char c = (char)val.intValue();
+ if (c >= 32 && c < 127 || !ascii && InterpreterUtil.isPrintableUnicode(c)) {
+ ret = String.valueOf(c);
+ }
+ else {
+ ret = InterpreterUtil.charToUnicodeLiteral(c);
+ }
+ }
+ return "\'" + ret + "\'";
+ case CodeConstants.TYPE_BYTE:
+ case CodeConstants.TYPE_BYTECHAR:
+ case CodeConstants.TYPE_SHORT:
+ case CodeConstants.TYPE_SHORTCHAR:
+ case CodeConstants.TYPE_INT:
+ int ival = ((Integer)value).intValue();
+
+ String intfield;
+ if (literal) {
+ return value.toString();
+ }
+ else if (ival == Integer.MAX_VALUE) {
+ intfield = "MAX_VALUE";
+ }
+ else if (ival == Integer.MIN_VALUE) {
+ intfield = "MIN_VALUE";
+ }
+ else {
+ return value.toString();
+ }
+ return new FieldExprent(intfield, "java/lang/Integer", true, null, FieldDescriptor.INTEGER_DESCRIPTOR).toJava(0);
+ case CodeConstants.TYPE_LONG:
+ long lval = ((Long)value).longValue();
+
+ String longfield;
+ if (literal) {
+ return value.toString() + "L";
+ }
+ else if (lval == Long.MAX_VALUE) {
+ longfield = "MAX_VALUE";
+ }
+ else if (lval == Long.MIN_VALUE) {
+ longfield = "MIN_VALUE";
+ }
+ else {
+ return value.toString() + "L";
+ }
+ return new FieldExprent(longfield, "java/lang/Long", true, null, FieldDescriptor.LONG_DESCRIPTOR).toJava(0);
+ case CodeConstants.TYPE_DOUBLE:
+ double dval = ((Double)value).doubleValue();
+
+ String doublefield;
+ if (literal) {
+ if (Double.isNaN(dval)) {
+ return "0.0D / 0.0";
+ }
+ else if (dval == Double.POSITIVE_INFINITY) {
+ return "1.0D / 0.0";
+ }
+ else if (dval == Double.NEGATIVE_INFINITY) {
+ return "-1.0D / 0.0";
+ }
+ else {
+ return value.toString() + "D";
+ }
+ }
+ else if (Double.isNaN(dval)) {
+ doublefield = "NaN";
+ }
+ else if (dval == Double.POSITIVE_INFINITY) {
+ doublefield = "POSITIVE_INFINITY";
+ }
+ else if (dval == Double.NEGATIVE_INFINITY) {
+ doublefield = "NEGATIVE_INFINITY";
+ }
+ else if (dval == Double.MAX_VALUE) {
+ doublefield = "MAX_VALUE";
+ }
+ else if (dval == Double.MIN_VALUE) {
+ doublefield = "MIN_VALUE";
+ }
+ else {
+ return value.toString() + "D";
+ }
+ return new FieldExprent(doublefield, "java/lang/Double", true, null, FieldDescriptor.DOUBLE_DESCRIPTOR).toJava(0);
+ case CodeConstants.TYPE_FLOAT:
+ float fval = ((Float)value).floatValue();
+
+ String floatfield;
+ if (literal) {
+ if (Double.isNaN(fval)) {
+ return "0.0F / 0.0";
+ }
+ else if (fval == Double.POSITIVE_INFINITY) {
+ return "1.0F / 0.0";
+ }
+ else if (fval == Double.NEGATIVE_INFINITY) {
+ return "-1.0F / 0.0";
+ }
+ else {
+ return value.toString() + "F";
+ }
+ }
+ else if (Float.isNaN(fval)) {
+ floatfield = "NaN";
+ }
+ else if (fval == Float.POSITIVE_INFINITY) {
+ floatfield = "POSITIVE_INFINITY";
+ }
+ else if (fval == Float.NEGATIVE_INFINITY) {
+ floatfield = "NEGATIVE_INFINITY";
+ }
+ else if (fval == Float.MAX_VALUE) {
+ floatfield = "MAX_VALUE";
+ }
+ else if (fval == Float.MIN_VALUE) {
+ floatfield = "MIN_VALUE";
+ }
+ else {
+ return value.toString() + "F";
+ }
+ return new FieldExprent(floatfield, "java/lang/Float", true, null, FieldDescriptor.FLOAT_DESCRIPTOR).toJava(0);
+ case CodeConstants.TYPE_NULL:
+ return "null";
+ case CodeConstants.TYPE_OBJECT:
+ if (consttype.equals(VarType.VARTYPE_STRING)) {
+ return "\"" + convertStringToJava(value.toString(), ascii) + "\"";
+ }
+ else if (consttype.equals(VarType.VARTYPE_CLASS)) {
+ String strval = value.toString();
+
+ VarType classtype;
+ if (strval.startsWith("[")) { // array of simple type
+ classtype = new VarType(strval, false);
+ }
+ else { // class
+ classtype = new VarType(strval, true);
+ }
+
+ return ExprProcessor.getCastTypeName(classtype) + ".class";
+ }
+ }
+ }
+
+ throw new RuntimeException("invalid constant type");
+ }
+
+ private static String convertStringToJava(String value, boolean ascii) {
+ char[] arr = value.toCharArray();
+ StringBuilder buffer = new StringBuilder(arr.length);
+
+ for (char c : arr) {
+ switch (c) {
+ case '\\': // u005c: backslash \
+ buffer.append("\\\\");
+ break;
+ case 0x8: // "\\\\b"); // u0008: backspace BS
+ buffer.append("\\b");
+ break;
+ case 0x9: //"\\\\t"); // u0009: horizontal tab HT
+ buffer.append("\\t");
+ break;
+ case 0xA: //"\\\\n"); // u000a: linefeed LF
+ buffer.append("\\n");
+ break;
+ case 0xC: //"\\\\f"); // u000c: form feed FF
+ buffer.append("\\f");
+ break;
+ case 0xD: //"\\\\r"); // u000d: carriage return CR
+ buffer.append("\\r");
+ break;
+ case 0x22: //"\\\\\""); // u0022: double quote "
+ buffer.append("\\\"");
+ break;
+ case 0x27: //"\\\\'"); // u0027: single quote '
+ buffer.append("\\\'");
+ break;
+ default:
+ if (c >= 32 && c < 127 || !ascii && InterpreterUtil.isPrintableUnicode(c)) {
+ buffer.append(c);
+ }
+ else {
+ buffer.append(InterpreterUtil.charToUnicodeLiteral(c));
+ }
+ }
+ }
+
+ return buffer.toString();
+ }
+
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof ConstExprent)) return false;
+
+ ConstExprent cn = (ConstExprent)o;
+ return InterpreterUtil.equalObjects(consttype, cn.getConsttype()) &&
+ InterpreterUtil.equalObjects(value, cn.getValue());
+ }
+
+ public boolean hasBooleanValue() {
+
+ switch (consttype.type) {
+ case CodeConstants.TYPE_BOOLEAN:
+ case CodeConstants.TYPE_CHAR:
+ case CodeConstants.TYPE_BYTE:
+ case CodeConstants.TYPE_BYTECHAR:
+ case CodeConstants.TYPE_SHORT:
+ case CodeConstants.TYPE_SHORTCHAR:
+ case CodeConstants.TYPE_INT:
+ Integer ival = (Integer)value;
+ return ival.intValue() == 0 ||
+ (DecompilerContext.getOption(IFernflowerPreferences.BOOLEAN_TRUE_ONE) && ival.intValue() == 1);
+ }
+
+ return false;
+ }
+
+ public boolean hasValueOne() {
+
+ switch (consttype.type) {
+ case CodeConstants.TYPE_BOOLEAN:
+ case CodeConstants.TYPE_CHAR:
+ case CodeConstants.TYPE_BYTE:
+ case CodeConstants.TYPE_BYTECHAR:
+ case CodeConstants.TYPE_SHORT:
+ case CodeConstants.TYPE_SHORTCHAR:
+ case CodeConstants.TYPE_INT:
+ return ((Integer)value).intValue() == 1;
+ case CodeConstants.TYPE_LONG:
+ return ((Long)value).intValue() == 1;
+ case CodeConstants.TYPE_DOUBLE:
+ return ((Double)value).intValue() == 1;
+ case CodeConstants.TYPE_FLOAT:
+ return ((Float)value).intValue() == 1;
+ }
+
+ return false;
+ }
+
+ public static ConstExprent getZeroConstant(int type) {
+
+ switch (type) {
+ case CodeConstants.TYPE_INT:
+ return new ConstExprent(VarType.VARTYPE_INT, new Integer(0));
+ case CodeConstants.TYPE_LONG:
+ return new ConstExprent(VarType.VARTYPE_LONG, new Long(0));
+ case CodeConstants.TYPE_DOUBLE:
+ return new ConstExprent(VarType.VARTYPE_DOUBLE, new Double(0));
+ case CodeConstants.TYPE_FLOAT:
+ return new ConstExprent(VarType.VARTYPE_FLOAT, new Float(0));
+ }
+
+ throw new RuntimeException("Invalid argument!");
+ }
+
+ public VarType getConsttype() {
+ return consttype;
+ }
+
+ public void setConsttype(VarType consttype) {
+ this.consttype = consttype;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ public int getIntValue() {
+ return ((Integer)value).intValue();
+ }
+
+ public boolean isBoolPermitted() {
+ return boolPermitted;
+ }
+
+ public void setBoolPermitted(boolean boolPermitted) {
+ this.boolPermitted = boolPermitted;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExitExprent.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExitExprent.java
new file mode 100644
index 000000000000..7a5013432952
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/ExitExprent.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.exps;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.main.rels.MethodWrapper;
+import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.CheckTypesResult;
+import org.jetbrains.java.decompiler.struct.attr.StructExceptionsAttribute;
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class ExitExprent extends Exprent {
+
+ public static final int EXIT_RETURN = 0;
+ public static final int EXIT_THROW = 1;
+
+ // return or throw statement
+ private int exittype;
+
+ private Exprent value;
+
+ private VarType rettype;
+
+ {
+ this.type = EXPRENT_EXIT;
+ }
+
+ public ExitExprent(int exittype, Exprent value, VarType rettype) {
+ this.exittype = exittype;
+ this.value = value;
+ this.rettype = rettype;
+ }
+
+ public Exprent copy() {
+ return new ExitExprent(exittype, value == null ? null : value.copy(), rettype);
+ }
+
+ public CheckTypesResult checkExprTypeBounds() {
+ CheckTypesResult result = new CheckTypesResult();
+
+ if (exittype == EXIT_RETURN && rettype.type != CodeConstants.TYPE_VOID) {
+ result.addMinTypeExprent(value, VarType.getMinTypeInFamily(rettype.type_family));
+ result.addMaxTypeExprent(value, rettype);
+ }
+
+ return result;
+ }
+
+ public List<Exprent> getAllExprents() {
+ List<Exprent> lst = new ArrayList<Exprent>();
+ if (value != null) {
+ lst.add(value);
+ }
+ return lst;
+ }
+
+ public String toJava(int indent) {
+ if (exittype == EXIT_RETURN) {
+ StringBuilder buffer = new StringBuilder();
+
+ if (rettype.type != CodeConstants.TYPE_VOID) {
+ buffer.append(" ");
+ ExprProcessor.getCastedExprent(value, rettype, buffer, indent, false);
+ }
+
+ return "return" + buffer.toString();
+ }
+ else {
+
+ MethodWrapper meth = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER);
+ ClassNode node = ((ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_NODE));
+
+ if (meth != null && node != null) {
+ StructExceptionsAttribute attr = (StructExceptionsAttribute)meth.methodStruct.getAttributes().getWithKey("Exceptions");
+
+ if (attr != null) {
+ String classname = null;
+
+ for (int i = 0; i < attr.getThrowsExceptions().size(); i++) {
+ String excclassname = attr.getExcClassname(i, node.classStruct.getPool());
+ if ("java/lang/Throwable".equals(excclassname)) {
+ classname = excclassname;
+ break;
+ }
+ else if ("java/lang/Exception".equals(excclassname)) {
+ classname = excclassname;
+ }
+ }
+
+ if (classname != null) {
+ VarType exctype = new VarType(classname, true);
+
+ StringBuilder buffer = new StringBuilder();
+ ExprProcessor.getCastedExprent(value, exctype, buffer, indent, false);
+
+ return "throw " + buffer.toString();
+ }
+ }
+ }
+
+ return "throw " + value.toJava(indent);
+ }
+ }
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof ExitExprent)) return false;
+
+ ExitExprent et = (ExitExprent)o;
+ return exittype == et.getExittype() &&
+ InterpreterUtil.equalObjects(value, et.getValue());
+ }
+
+ public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
+ if (oldexpr == value) {
+ value = newexpr;
+ }
+ }
+
+ public int getExittype() {
+ return exittype;
+ }
+
+ public Exprent getValue() {
+ return value;
+ }
+
+ public VarType getRettype() {
+ return rettype;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java
new file mode 100644
index 000000000000..99712d574ab7
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/Exprent.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.exps;
+
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.CheckTypesResult;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar;
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+
+public class Exprent {
+
+ public static final int MULTIPLE_USES = 1;
+ public static final int SIDE_EFFECTS_FREE = 2;
+ public static final int BOTH_FLAGS = 3;
+
+
+ public static final int EXPRENT_ARRAY = 1;
+ public static final int EXPRENT_ASSIGNMENT = 2;
+ public static final int EXPRENT_CONST = 3;
+ public static final int EXPRENT_EXIT = 4;
+ public static final int EXPRENT_FIELD = 5;
+ public static final int EXPRENT_FUNCTION = 6;
+ public static final int EXPRENT_IF = 7;
+ public static final int EXPRENT_INVOCATION = 8;
+ public static final int EXPRENT_MONITOR = 9;
+ public static final int EXPRENT_NEW = 10;
+ public static final int EXPRENT_SWITCH = 11;
+ public static final int EXPRENT_VAR = 12;
+ public static final int EXPRENT_ANNOTATION = 13;
+ public static final int EXPRENT_ASSERT = 14;
+
+ public int type;
+
+ public int id;
+
+ {
+ // set exprent id
+ id = DecompilerContext.getCounterContainer().getCounterAndIncrement(CounterContainer.EXPRENT_COUNTER);
+ }
+
+ public int getPrecedence() {
+ return 0; // the highest precedence
+ }
+
+ public VarType getExprType() {
+ return VarType.VARTYPE_VOID;
+ }
+
+ public int getExprentUse() {
+ return 0;
+ }
+
+ public CheckTypesResult checkExprTypeBounds() {
+ return new CheckTypesResult();
+ }
+
+ public boolean containsExprent(Exprent exprent) {
+
+ List<Exprent> listTemp = new ArrayList<Exprent>(getAllExprents(true));
+ listTemp.add(this);
+
+ for (Exprent lstexpr : listTemp) {
+ if (lstexpr.equals(exprent)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public List<Exprent> getAllExprents(boolean recursive) {
+ List<Exprent> lst = getAllExprents();
+
+ if (recursive) {
+ for (int i = lst.size() - 1; i >= 0; i--) {
+ lst.addAll(lst.get(i).getAllExprents(true));
+ }
+ }
+
+ return lst;
+ }
+
+ public Set<VarVersionPaar> getAllVariables() {
+
+ HashSet<VarVersionPaar> set = new HashSet<VarVersionPaar>();
+
+ List<Exprent> lstAllExprents = getAllExprents(true);
+ lstAllExprents.add(this);
+
+ for (Exprent expr : lstAllExprents) {
+ if (expr.type == EXPRENT_VAR) {
+ set.add(new VarVersionPaar((VarExprent)expr));
+ }
+ }
+
+ return set;
+ }
+
+ public List<Exprent> getAllExprents() {
+ throw new RuntimeException("not implemented");
+ }
+
+ public Exprent copy() {
+ throw new RuntimeException("not implemented");
+ }
+
+ public String toJava(int indent) {
+ throw new RuntimeException("not implemented");
+ }
+
+ public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java
new file mode 100644
index 000000000000..aa180b038798
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FieldExprent.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.exps;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.main.rels.MethodWrapper;
+import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar;
+import org.jetbrains.java.decompiler.struct.StructClass;
+import org.jetbrains.java.decompiler.struct.consts.LinkConstant;
+import org.jetbrains.java.decompiler.struct.gen.FieldDescriptor;
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class FieldExprent extends Exprent {
+
+ private String name;
+
+ private String classname;
+
+ private boolean isStatic;
+
+ private Exprent instance;
+
+ private FieldDescriptor descriptor;
+
+ {
+ this.type = EXPRENT_FIELD;
+ }
+
+ public FieldExprent(LinkConstant cn, Exprent instance) {
+
+ this.instance = instance;
+
+ if (instance == null) {
+ isStatic = true;
+ }
+
+ classname = cn.classname;
+ name = cn.elementname;
+ descriptor = FieldDescriptor.parseDescriptor(cn.descriptor);
+ }
+
+ public FieldExprent(String name, String classname, boolean isStatic, Exprent instance, FieldDescriptor descriptor) {
+ this.name = name;
+ this.classname = classname;
+ this.isStatic = isStatic;
+ this.instance = instance;
+ this.descriptor = descriptor;
+ }
+
+ public VarType getExprType() {
+ return descriptor.type;
+ }
+
+ public int getExprentUse() {
+ if (instance == null) {
+ return Exprent.MULTIPLE_USES;
+ }
+ else {
+ return instance.getExprentUse() & Exprent.MULTIPLE_USES;
+ }
+ }
+
+ public List<Exprent> getAllExprents() {
+ List<Exprent> lst = new ArrayList<Exprent>();
+ if (instance != null) {
+ lst.add(instance);
+ }
+ return lst;
+ }
+
+ public Exprent copy() {
+ return new FieldExprent(name, classname, isStatic, instance == null ? null : instance.copy(), descriptor);
+ }
+
+ public String toJava(int indent) {
+ StringBuilder buf = new StringBuilder();
+
+
+ if (isStatic) {
+ ClassNode node = (ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_NODE);
+ if (node == null || !classname.equals(node.classStruct.qualifiedName)) {
+ buf.append(DecompilerContext.getImportCollector().getShortName(ExprProcessor.buildJavaClassName(classname)));
+ buf.append(".");
+ }
+ }
+ else {
+
+ String super_qualifier = null;
+
+ if (instance != null && instance.type == Exprent.EXPRENT_VAR) {
+ VarExprent instvar = (VarExprent)instance;
+ VarVersionPaar varpaar = new VarVersionPaar(instvar);
+
+ MethodWrapper current_meth = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER);
+
+ if (current_meth != null) { // FIXME: remove
+ String this_classname = current_meth.varproc.getThisvars().get(varpaar);
+
+ if (this_classname != null) {
+ if (!classname.equals(this_classname)) { // TODO: direct comparison to the super class?
+ super_qualifier = this_classname;
+ }
+ }
+ }
+ }
+
+ if (super_qualifier != null) {
+ StructClass current_class = ((ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_NODE)).classStruct;
+
+ if (!super_qualifier.equals(current_class.qualifiedName)) {
+ buf.append(DecompilerContext.getImportCollector().getShortName(ExprProcessor.buildJavaClassName(super_qualifier)));
+ buf.append(".");
+ }
+ buf.append("super");
+ }
+ else {
+ StringBuilder buff = new StringBuilder();
+ boolean casted = ExprProcessor.getCastedExprent(instance, new VarType(CodeConstants.TYPE_OBJECT, 0, classname), buff, indent, true);
+ String res = buff.toString();
+
+ if (casted || instance.getPrecedence() > getPrecedence()) {
+ res = "(" + res + ")";
+ }
+
+ buf.append(res);
+ }
+
+ if (buf.toString().equals(
+ VarExprent.VAR_NAMELESS_ENCLOSURE)) { // FIXME: workaround for field access of an anonymous enclosing class. Find a better way.
+ buf.setLength(0);
+ }
+ else {
+ buf.append(".");
+ }
+ }
+
+ buf.append(name);
+
+ return buf.toString();
+ }
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof FieldExprent)) return false;
+
+ FieldExprent ft = (FieldExprent)o;
+ return InterpreterUtil.equalObjects(name, ft.getName()) &&
+ InterpreterUtil.equalObjects(classname, ft.getClassname()) &&
+ isStatic == ft.isStatic() &&
+ InterpreterUtil.equalObjects(instance, ft.getInstance()) &&
+ InterpreterUtil.equalObjects(descriptor, ft.getDescriptor());
+ }
+
+ public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
+ if (oldexpr == instance) {
+ instance = newexpr;
+ }
+ }
+
+ public String getClassname() {
+ return classname;
+ }
+
+ public FieldDescriptor getDescriptor() {
+ return descriptor;
+ }
+
+ public Exprent getInstance() {
+ return instance;
+ }
+
+ public boolean isStatic() {
+ return isStatic;
+ }
+
+ public String getName() {
+ return name;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java
new file mode 100644
index 000000000000..4fa2ab385cee
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/FunctionExprent.java
@@ -0,0 +1,615 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.exps;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.CheckTypesResult;
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import org.jetbrains.java.decompiler.util.ListStack;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+
+
+public class FunctionExprent extends Exprent {
+
+ public static final int FUNCTION_ADD = 0;
+ public static final int FUNCTION_SUB = 1;
+ public static final int FUNCTION_MUL = 2;
+ public static final int FUNCTION_DIV = 3;
+
+ public static final int FUNCTION_AND = 4;
+ public static final int FUNCTION_OR = 5;
+ public static final int FUNCTION_XOR = 6;
+
+ public static final int FUNCTION_REM = 7;
+
+ public static final int FUNCTION_SHL = 8;
+ public static final int FUNCTION_SHR = 9;
+ public static final int FUNCTION_USHR = 10;
+
+ public static final int FUNCTION_BITNOT = 11;
+ public static final int FUNCTION_BOOLNOT = 12;
+ public static final int FUNCTION_NEG = 13;
+
+ public final static int FUNCTION_I2L = 14;
+ public final static int FUNCTION_I2F = 15;
+ public final static int FUNCTION_I2D = 16;
+ public final static int FUNCTION_L2I = 17;
+ public final static int FUNCTION_L2F = 18;
+ public final static int FUNCTION_L2D = 19;
+ public final static int FUNCTION_F2I = 20;
+ public final static int FUNCTION_F2L = 21;
+ public final static int FUNCTION_F2D = 22;
+ public final static int FUNCTION_D2I = 23;
+ public final static int FUNCTION_D2L = 24;
+ public final static int FUNCTION_D2F = 25;
+ public final static int FUNCTION_I2B = 26;
+ public final static int FUNCTION_I2C = 27;
+ public final static int FUNCTION_I2S = 28;
+
+ public final static int FUNCTION_CAST = 29;
+ public final static int FUNCTION_INSTANCEOF = 30;
+
+ public final static int FUNCTION_ARRAYLENGTH = 31;
+
+ public final static int FUNCTION_IMM = 32;
+ public final static int FUNCTION_MMI = 33;
+
+ public final static int FUNCTION_IPP = 34;
+ public final static int FUNCTION_PPI = 35;
+
+ public final static int FUNCTION_IIF = 36;
+
+ public final static int FUNCTION_LCMP = 37;
+ public final static int FUNCTION_FCMPL = 38;
+ public final static int FUNCTION_FCMPG = 39;
+ public final static int FUNCTION_DCMPL = 40;
+ public final static int FUNCTION_DCMPG = 41;
+
+ public static final int FUNCTION_EQ = 42;
+ public static final int FUNCTION_NE = 43;
+ public static final int FUNCTION_LT = 44;
+ public static final int FUNCTION_GE = 45;
+ public static final int FUNCTION_GT = 46;
+ public static final int FUNCTION_LE = 47;
+
+ public static final int FUNCTION_CADD = 48;
+ public static final int FUNCTION_COR = 49;
+
+ public static final int FUNCTION_STRCONCAT = 50;
+
+ private static final VarType[] types = new VarType[]{
+ VarType.VARTYPE_LONG,
+ VarType.VARTYPE_FLOAT,
+ VarType.VARTYPE_DOUBLE,
+ VarType.VARTYPE_INT,
+ VarType.VARTYPE_FLOAT,
+ VarType.VARTYPE_DOUBLE,
+ VarType.VARTYPE_INT,
+ VarType.VARTYPE_LONG,
+ VarType.VARTYPE_DOUBLE,
+ VarType.VARTYPE_INT,
+ VarType.VARTYPE_LONG,
+ VarType.VARTYPE_FLOAT,
+ VarType.VARTYPE_BYTE,
+ VarType.VARTYPE_CHAR,
+ VarType.VARTYPE_SHORT
+ };
+
+ private static final String[] operators = new String[]{
+ " + ",
+ " - ",
+ " * ",
+ " / ",
+ " & ",
+ " | ",
+ " ^ ",
+ " % ",
+ " << ",
+ " >> ",
+ " >>> ",
+ " == ",
+ " != ",
+ " < ",
+ " >= ",
+ " > ",
+ " <= ",
+ " && ",
+ " || ",
+ " + "
+ };
+
+ private static final int[] precedence = new int[]{
+ 3, // FUNCTION_ADD
+ 3, // FUNCTION_SUB
+ 2, // FUNCTION_MUL
+ 2, // FUNCTION_DIV
+ 7, // FUNCTION_AND
+ 9, // FUNCTION_OR
+ 8, // FUNCTION_XOR
+ 2, // FUNCTION_REM
+ 4, // FUNCTION_SHL
+ 4, // FUNCTION_SHR
+ 4, // FUNCTION_USHR
+ 1, // FUNCTION_BITNOT
+ 1, // FUNCTION_BOOLNOT
+ 1, // FUNCTION_NEG
+ 1, // FUNCTION_I2L
+ 1, // FUNCTION_I2F
+ 1, // FUNCTION_I2D
+ 1, // FUNCTION_L2I
+ 1, // FUNCTION_L2F
+ 1, // FUNCTION_L2D
+ 1, // FUNCTION_F2I
+ 1, // FUNCTION_F2L
+ 1, // FUNCTION_F2D
+ 1, // FUNCTION_D2I
+ 1, // FUNCTION_D2L
+ 1, // FUNCTION_D2F
+ 1, // FUNCTION_I2B
+ 1, // FUNCTION_I2C
+ 1, // FUNCTION_I2S
+ 1, // FUNCTION_CAST
+ 6, // FUNCTION_INSTANCEOF
+ 0, // FUNCTION_ARRAYLENGTH
+ 1, // FUNCTION_IMM
+ 1, // FUNCTION_MMI
+ 1, // FUNCTION_IPP
+ 1, // FUNCTION_PPI
+ 12, // FUNCTION_IFF
+ -1, // FUNCTION_LCMP
+ -1, // FUNCTION_FCMPL
+ -1, // FUNCTION_FCMPG
+ -1, // FUNCTION_DCMPL
+ -1, // FUNCTION_DCMPG
+ 6, // FUNCTION_EQ = 41;
+ 6, // FUNCTION_NE = 42;
+ 5, // FUNCTION_LT = 43;
+ 5, // FUNCTION_GE = 44;
+ 5, // FUNCTION_GT = 45;
+ 5, // FUNCTION_LE = 46;
+ 10, // FUNCTION_CADD = 47;
+ 11, // FUNCTION_COR = 48;
+ 3 // FUNCTION_STRCONCAT = 49;
+ };
+
+ private static final HashSet<Integer> associativity =
+ new HashSet<Integer>(Arrays.asList(new Integer[]{FUNCTION_ADD, FUNCTION_MUL, FUNCTION_AND,
+ FUNCTION_OR, FUNCTION_XOR, FUNCTION_CADD, FUNCTION_COR, FUNCTION_STRCONCAT}));
+
+ private int functype;
+
+ private VarType implicitType;
+
+ private List<Exprent> lstOperands = new ArrayList<Exprent>();
+
+ {
+ this.type = EXPRENT_FUNCTION;
+ }
+
+ public FunctionExprent(int functype, ListStack<Exprent> stack) {
+ this.functype = functype;
+ if (functype >= FUNCTION_BITNOT && functype <= FUNCTION_PPI && functype != FUNCTION_CAST
+ && functype != FUNCTION_INSTANCEOF) {
+ lstOperands.add(stack.pop());
+ }
+ else if (functype == FUNCTION_IIF) {
+ throw new RuntimeException("no direct instantiation possible");
+ }
+ else {
+ Exprent expr = stack.pop();
+ lstOperands.add(stack.pop());
+ lstOperands.add(expr);
+ }
+ }
+
+ public FunctionExprent(int functype, List<Exprent> operands) {
+ this.functype = functype;
+ this.lstOperands = operands;
+ }
+
+ public VarType getExprType() {
+ VarType exprType = null;
+
+ if (functype <= FUNCTION_NEG || functype == FUNCTION_IPP || functype == FUNCTION_PPI
+ || functype == FUNCTION_IMM || functype == FUNCTION_MMI) {
+
+ VarType type1 = lstOperands.get(0).getExprType();
+ VarType type2 = null;
+ if (lstOperands.size() > 1) {
+ type2 = lstOperands.get(1).getExprType();
+ }
+
+ switch (functype) {
+ case FUNCTION_IMM:
+ case FUNCTION_MMI:
+ case FUNCTION_IPP:
+ case FUNCTION_PPI:
+ exprType = implicitType;
+ break;
+ case FUNCTION_BOOLNOT:
+ exprType = VarType.VARTYPE_BOOLEAN;
+ break;
+ case FUNCTION_SHL:
+ case FUNCTION_SHR:
+ case FUNCTION_USHR:
+ case FUNCTION_BITNOT:
+ case FUNCTION_NEG:
+ exprType = getMaxVarType(new VarType[]{type1});
+ break;
+ case FUNCTION_ADD:
+ case FUNCTION_SUB:
+ case FUNCTION_MUL:
+ case FUNCTION_DIV:
+ case FUNCTION_REM:
+ exprType = getMaxVarType(new VarType[]{type1, type2});
+ break;
+ case FUNCTION_AND:
+ case FUNCTION_OR:
+ case FUNCTION_XOR:
+ if (type1.type == CodeConstants.TYPE_BOOLEAN & type2.type == CodeConstants.TYPE_BOOLEAN) {
+ exprType = VarType.VARTYPE_BOOLEAN;
+ }
+ else {
+ exprType = getMaxVarType(new VarType[]{type1, type2});
+ }
+ }
+ }
+ else if (functype == FUNCTION_CAST) {
+ exprType = lstOperands.get(1).getExprType();
+ }
+ else if (functype == FUNCTION_IIF) {
+ Exprent param1 = lstOperands.get(1);
+ Exprent param2 = lstOperands.get(2);
+ VarType supertype = VarType.getCommonSupertype(param1.getExprType(), param2.getExprType());
+
+ if (param1.type == Exprent.EXPRENT_CONST && param2.type == Exprent.EXPRENT_CONST &&
+ supertype.type != CodeConstants.TYPE_BOOLEAN && VarType.VARTYPE_INT.isSuperset(supertype)) {
+ exprType = VarType.VARTYPE_INT;
+ }
+ else {
+ exprType = supertype;
+ }
+ }
+ else if (functype == FUNCTION_STRCONCAT) {
+ exprType = VarType.VARTYPE_STRING;
+ }
+ else if (functype >= FUNCTION_EQ || functype == FUNCTION_INSTANCEOF) {
+ exprType = VarType.VARTYPE_BOOLEAN;
+ }
+ else if (functype >= FUNCTION_ARRAYLENGTH) {
+ exprType = VarType.VARTYPE_INT;
+ }
+ else {
+ exprType = types[functype - FUNCTION_I2L];
+ }
+
+ return exprType;
+ }
+
+ public int getExprentUse() {
+
+ if (functype >= FUNCTION_IMM && functype <= FUNCTION_PPI) {
+ return 0;
+ }
+ else {
+ int ret = Exprent.MULTIPLE_USES | Exprent.SIDE_EFFECTS_FREE;
+ for (Exprent expr : lstOperands) {
+ ret &= expr.getExprentUse();
+ }
+ return ret;
+ }
+ }
+
+ public CheckTypesResult checkExprTypeBounds() {
+ CheckTypesResult result = new CheckTypesResult();
+
+ Exprent param1 = lstOperands.get(0);
+ VarType type1 = param1.getExprType();
+ Exprent param2 = null;
+ VarType type2 = null;
+
+ if (lstOperands.size() > 1) {
+ param2 = lstOperands.get(1);
+ type2 = param2.getExprType();
+ }
+
+ switch (functype) {
+ case FUNCTION_IIF:
+ VarType supertype = getExprType();
+ if (supertype == null) {
+ supertype = getExprType();
+ }
+ result.addMinTypeExprent(param1, VarType.VARTYPE_BOOLEAN);
+ result.addMinTypeExprent(param2, VarType.getMinTypeInFamily(supertype.type_family));
+ result.addMinTypeExprent(lstOperands.get(2), VarType.getMinTypeInFamily(supertype.type_family));
+ break;
+ case FUNCTION_I2L:
+ case FUNCTION_I2F:
+ case FUNCTION_I2D:
+ case FUNCTION_I2B:
+ case FUNCTION_I2C:
+ case FUNCTION_I2S:
+ result.addMinTypeExprent(param1, VarType.VARTYPE_BYTECHAR);
+ result.addMaxTypeExprent(param1, VarType.VARTYPE_INT);
+ break;
+ case FUNCTION_IMM:
+ case FUNCTION_IPP:
+ case FUNCTION_MMI:
+ case FUNCTION_PPI:
+ result.addMinTypeExprent(param1, implicitType);
+ result.addMaxTypeExprent(param1, implicitType);
+ break;
+ case FUNCTION_ADD:
+ case FUNCTION_SUB:
+ case FUNCTION_MUL:
+ case FUNCTION_DIV:
+ case FUNCTION_REM:
+ case FUNCTION_SHL:
+ case FUNCTION_SHR:
+ case FUNCTION_USHR:
+ case FUNCTION_LT:
+ case FUNCTION_GE:
+ case FUNCTION_GT:
+ case FUNCTION_LE:
+ result.addMinTypeExprent(param2, VarType.VARTYPE_BYTECHAR);
+ case FUNCTION_BITNOT:
+ // case FUNCTION_BOOLNOT:
+ case FUNCTION_NEG:
+ result.addMinTypeExprent(param1, VarType.VARTYPE_BYTECHAR);
+ break;
+ case FUNCTION_AND:
+ case FUNCTION_OR:
+ case FUNCTION_XOR:
+ case FUNCTION_EQ:
+ case FUNCTION_NE: {
+ if (type1.type == CodeConstants.TYPE_BOOLEAN) {
+
+ if (type2.isStrictSuperset(type1)) {
+
+ result.addMinTypeExprent(param1, VarType.VARTYPE_BYTECHAR);
+ }
+ else { // both are booleans
+
+ boolean param1_false_boolean =
+ type1.isFalseBoolean() || (param1.type == Exprent.EXPRENT_CONST && !((ConstExprent)param1).hasBooleanValue());
+ boolean param2_false_boolean =
+ type1.isFalseBoolean() || (param2.type == Exprent.EXPRENT_CONST && !((ConstExprent)param2).hasBooleanValue());
+
+ if (param1_false_boolean || param2_false_boolean) {
+ result.addMinTypeExprent(param1, VarType.VARTYPE_BYTECHAR);
+ result.addMinTypeExprent(param2, VarType.VARTYPE_BYTECHAR);
+ }
+ }
+ }
+ else if (type2.type == CodeConstants.TYPE_BOOLEAN) {
+
+ if (type1.isStrictSuperset(type2)) {
+ result.addMinTypeExprent(param2, VarType.VARTYPE_BYTECHAR);
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ public List<Exprent> getAllExprents() {
+ List<Exprent> lst = new ArrayList<Exprent>();
+ lst.addAll(lstOperands);
+ return lst;
+ }
+
+ public Exprent copy() {
+ List<Exprent> lst = new ArrayList<Exprent>();
+ for (Exprent expr : lstOperands) {
+ lst.add(expr.copy());
+ }
+ FunctionExprent func = new FunctionExprent(functype, lst);
+ func.setImplicitType(implicitType);
+
+ return func;
+ }
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof FunctionExprent)) return false;
+
+ FunctionExprent fe = (FunctionExprent)o;
+ return functype == fe.getFunctype() &&
+ InterpreterUtil.equalLists(lstOperands, fe.getLstOperands()); // TODO: order of operands insignificant
+ }
+
+ public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
+ for (int i = 0; i < lstOperands.size(); i++) {
+ if (oldexpr == lstOperands.get(i)) {
+ lstOperands.set(i, newexpr);
+ }
+ }
+ }
+
+ public String toJava(int indent) {
+
+ if (functype <= FUNCTION_USHR) {
+ return wrapOperandString(lstOperands.get(0), false, indent) + operators[functype] +
+ wrapOperandString(lstOperands.get(1), true, indent);
+ }
+
+ if (functype >= FUNCTION_EQ) {
+ return wrapOperandString(lstOperands.get(0), false, indent) + operators[functype - FUNCTION_EQ + 11] +
+ wrapOperandString(lstOperands.get(1), true, indent);
+ }
+
+ switch (functype) {
+ case FUNCTION_BITNOT:
+ return "~" + wrapOperandString(lstOperands.get(0), true, indent);
+ case FUNCTION_BOOLNOT:
+ return "!" + wrapOperandString(lstOperands.get(0), true, indent);
+ case FUNCTION_NEG:
+ return "-" + wrapOperandString(lstOperands.get(0), true, indent);
+ case FUNCTION_CAST:
+ return "(" + lstOperands.get(1).toJava(indent) + ")" + wrapOperandString(lstOperands.get(0), true, indent);
+ case FUNCTION_ARRAYLENGTH:
+ Exprent arr = lstOperands.get(0);
+
+ String res = wrapOperandString(arr, false, indent);
+ if (arr.getExprType().arraydim == 0) {
+ VarType objarr = VarType.VARTYPE_OBJECT.copy();
+ objarr.arraydim = 1; // type family does not change
+
+ res = "((" + ExprProcessor.getCastTypeName(objarr) + ")" + res + ")";
+ }
+ return res + ".length";
+ case FUNCTION_IIF:
+ return wrapOperandString(lstOperands.get(0), true, indent) + "?" + wrapOperandString(lstOperands.get(1), true, indent) + ":" +
+ wrapOperandString(lstOperands.get(2), true, indent);
+ case FUNCTION_IPP:
+ return wrapOperandString(lstOperands.get(0), true, indent) + "++";
+ case FUNCTION_PPI:
+ return "++" + wrapOperandString(lstOperands.get(0), true, indent);
+ case FUNCTION_IMM:
+ return wrapOperandString(lstOperands.get(0), true, indent) + "--";
+ case FUNCTION_MMI:
+ return "--" + wrapOperandString(lstOperands.get(0), true, indent);
+ case FUNCTION_INSTANCEOF:
+ return wrapOperandString(lstOperands.get(0), true, indent) + " instanceof " + wrapOperandString(lstOperands.get(1), true, indent);
+ case FUNCTION_LCMP: // shouldn't appear in the final code
+ return "__lcmp__(" +
+ wrapOperandString(lstOperands.get(0), true, indent) +
+ "," +
+ wrapOperandString(lstOperands.get(1), true, indent) +
+ ")";
+ case FUNCTION_FCMPL: // shouldn't appear in the final code
+ return "__fcmpl__(" +
+ wrapOperandString(lstOperands.get(0), true, indent) +
+ "," +
+ wrapOperandString(lstOperands.get(1), true, indent) +
+ ")";
+ case FUNCTION_FCMPG: // shouldn't appear in the final code
+ return "__fcmpg__(" +
+ wrapOperandString(lstOperands.get(0), true, indent) +
+ "," +
+ wrapOperandString(lstOperands.get(1), true, indent) +
+ ")";
+ case FUNCTION_DCMPL: // shouldn't appear in the final code
+ return "__dcmpl__(" +
+ wrapOperandString(lstOperands.get(0), true, indent) +
+ "," +
+ wrapOperandString(lstOperands.get(1), true, indent) +
+ ")";
+ case FUNCTION_DCMPG: // shouldn't appear in the final code
+ return "__dcmpg__(" +
+ wrapOperandString(lstOperands.get(0), true, indent) +
+ "," +
+ wrapOperandString(lstOperands.get(1), true, indent) +
+ ")";
+ }
+
+ if (functype <= FUNCTION_I2S) {
+ return "(" + ExprProcessor.getTypeName(types[functype - FUNCTION_I2L]) + ")" + wrapOperandString(lstOperands.get(0), true, indent);
+ }
+
+ // return "<unknown function>";
+ throw new RuntimeException("invalid function");
+ }
+
+ public int getPrecedence() {
+ return getPrecedence(functype);
+ }
+
+ public static int getPrecedence(int func) {
+ return precedence[func];
+ }
+
+ public VarType getSimpleCastType() {
+ return types[functype - FUNCTION_I2L];
+ }
+
+ private String wrapOperandString(Exprent expr, boolean eq, int indent) {
+
+ int myprec = getPrecedence();
+ int exprprec = expr.getPrecedence();
+
+ boolean parentheses = exprprec > myprec;
+ if (!parentheses && eq) {
+ parentheses = (exprprec == myprec);
+ if (parentheses) {
+ if (expr.type == Exprent.EXPRENT_FUNCTION &&
+ ((FunctionExprent)expr).getFunctype() == functype) {
+ parentheses = !associativity.contains(functype);
+ }
+ }
+ }
+
+ String res = expr.toJava(indent);
+
+ if (parentheses) {
+ res = "(" + res + ")";
+ }
+
+ return res;
+ }
+
+ private static VarType getMaxVarType(VarType[] arr) {
+
+ int[] types = new int[]{CodeConstants.TYPE_DOUBLE, CodeConstants.TYPE_FLOAT, CodeConstants.TYPE_LONG};
+ VarType[] vartypes = new VarType[]{VarType.VARTYPE_DOUBLE, VarType.VARTYPE_FLOAT, VarType.VARTYPE_LONG};
+
+ for (int i = 0; i < types.length; i++) {
+ for (int j = 0; j < arr.length; j++) {
+ if (arr[j].type == types[i]) {
+ return vartypes[i];
+ }
+ }
+ }
+
+ return VarType.VARTYPE_INT;
+ }
+
+ // *****************************************************************************
+ // getter and setter methods
+ // *****************************************************************************
+
+ public int getFunctype() {
+ return functype;
+ }
+
+ public void setFunctype(int functype) {
+ this.functype = functype;
+ }
+
+ public List<Exprent> getLstOperands() {
+ return lstOperands;
+ }
+
+ public void setLstOperands(List<Exprent> lstOperands) {
+ this.lstOperands = lstOperands;
+ }
+
+ public VarType getImplicitType() {
+ return implicitType;
+ }
+
+ public void setImplicitType(VarType implicitType) {
+ this.implicitType = implicitType;
+ }
+}
+
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/IfExprent.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/IfExprent.java
new file mode 100644
index 000000000000..66e63c0e7fc6
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/IfExprent.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.exps;
+
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import org.jetbrains.java.decompiler.util.ListStack;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+
+public class IfExprent extends Exprent {
+
+ public static final int IF_EQ = 0;
+ public static final int IF_NE = 1;
+ public static final int IF_LT = 2;
+ public static final int IF_GE = 3;
+ public static final int IF_GT = 4;
+ public static final int IF_LE = 5;
+
+ public static final int IF_NULL = 6;
+ public static final int IF_NONNULL = 7;
+
+ public static final int IF_ICMPEQ = 8;
+ public static final int IF_ICMPNE = 9;
+ public static final int IF_ICMPLT = 10;
+ public static final int IF_ICMPGE = 11;
+ public static final int IF_ICMPGT = 12;
+ public static final int IF_ICMPLE = 13;
+ public static final int IF_ACMPEQ = 14;
+ public static final int IF_ACMPNE = 15;
+
+ public static final int IF_CAND = 16;
+ public static final int IF_COR = 17;
+
+ public static final int IF_NOT = 18;
+ public static final int IF_VALUE = 19;
+
+ private static final int[] functypes = new int[]{
+ FunctionExprent.FUNCTION_EQ,
+ FunctionExprent.FUNCTION_NE,
+ FunctionExprent.FUNCTION_LT,
+ FunctionExprent.FUNCTION_GE,
+ FunctionExprent.FUNCTION_GT,
+ FunctionExprent.FUNCTION_LE,
+ FunctionExprent.FUNCTION_EQ,
+ FunctionExprent.FUNCTION_NE,
+ FunctionExprent.FUNCTION_EQ,
+ FunctionExprent.FUNCTION_NE,
+ FunctionExprent.FUNCTION_LT,
+ FunctionExprent.FUNCTION_GE,
+ FunctionExprent.FUNCTION_GT,
+ FunctionExprent.FUNCTION_LE,
+ FunctionExprent.FUNCTION_EQ,
+ FunctionExprent.FUNCTION_NE,
+ FunctionExprent.FUNCTION_CADD,
+ FunctionExprent.FUNCTION_COR,
+ FunctionExprent.FUNCTION_BOOLNOT,
+ -1
+ };
+
+ private Exprent condition;
+
+ {
+ this.type = EXPRENT_IF;
+ }
+
+ public IfExprent(int iftype, ListStack<Exprent> stack) {
+
+ if (iftype <= IF_LE) {
+ stack.push(new ConstExprent(0, true));
+ }
+ else if (iftype <= IF_NONNULL) {
+ stack.push(new ConstExprent(VarType.VARTYPE_NULL, null));
+ }
+
+ if (iftype == IF_VALUE) {
+ condition = stack.pop();
+ }
+ else {
+ condition = new FunctionExprent(functypes[iftype], stack);
+ }
+ }
+
+ private IfExprent(Exprent condition) {
+ this.condition = condition;
+ }
+
+ public Exprent copy() {
+ return new IfExprent(condition.copy());
+ }
+
+ public List<Exprent> getAllExprents() {
+ List<Exprent> lst = new ArrayList<Exprent>();
+ lst.add(condition);
+ return lst;
+ }
+
+ public String toJava(int indent) {
+ return "if(" + condition.toJava(indent) + ")";
+ }
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof IfExprent)) return false;
+
+ IfExprent ie = (IfExprent)o;
+ return InterpreterUtil.equalObjects(condition, ie.getCondition());
+ }
+
+ public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
+ if (oldexpr == condition) {
+ condition = newexpr;
+ }
+ }
+
+ public IfExprent negateIf() {
+ condition = new FunctionExprent(FunctionExprent.FUNCTION_BOOLNOT,
+ Arrays.asList(new Exprent[]{condition}));
+ return this;
+ }
+
+ public Exprent getCondition() {
+ return condition;
+ }
+
+ public void setCondition(Exprent condition) {
+ this.condition = condition;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java
new file mode 100644
index 000000000000..04758dc0492d
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/InvocationExprent.java
@@ -0,0 +1,515 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.exps;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
+import org.jetbrains.java.decompiler.main.rels.MethodWrapper;
+import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.CheckTypesResult;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar;
+import org.jetbrains.java.decompiler.struct.StructClass;
+import org.jetbrains.java.decompiler.struct.StructMethod;
+import org.jetbrains.java.decompiler.struct.consts.LinkConstant;
+import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import org.jetbrains.java.decompiler.util.ListStack;
+
+import java.util.*;
+
+
+public class InvocationExprent extends Exprent {
+
+ public static final int INVOKE_SPECIAL = 1;
+ public static final int INVOKE_VIRTUAL = 2;
+ public static final int INVOKE_STATIC = 3;
+ public static final int INVOKE_INTERFACE = 4;
+ public static final int INVOKE_DYNAMIC = 5;
+
+ public static final int TYP_GENERAL = 1;
+ public static final int TYP_INIT = 2;
+ public static final int TYP_CLINIT = 3;
+
+ public static final int CONSTRUCTOR_NOT = 0;
+ public static final int CONSTRUCTOR_THIS = 1;
+ public static final int CONSTRUCTOR_SUPER = 2;
+
+ private String name;
+
+ private String classname;
+
+ private boolean isStatic;
+
+ private int functype = TYP_GENERAL;
+
+ private Exprent instance;
+
+ private MethodDescriptor descriptor;
+
+ private String stringDescriptor;
+
+ private String invoke_dynamic_classsuffix;
+
+ private int invocationTyp = INVOKE_VIRTUAL;
+
+ private List<Exprent> lstParameters = new ArrayList<Exprent>();
+
+ {
+ this.type = EXPRENT_INVOCATION;
+ }
+
+ public InvocationExprent() {
+ }
+
+ public InvocationExprent(int opcode, LinkConstant cn, ListStack<Exprent> stack, int dynamic_invokation_type) {
+
+ name = cn.elementname;
+ classname = cn.classname;
+
+ switch (opcode) {
+ case CodeConstants.opc_invokestatic:
+ invocationTyp = INVOKE_STATIC;
+ break;
+ case CodeConstants.opc_invokespecial:
+ invocationTyp = INVOKE_SPECIAL;
+ break;
+ case CodeConstants.opc_invokevirtual:
+ invocationTyp = INVOKE_VIRTUAL;
+ break;
+ case CodeConstants.opc_invokeinterface:
+ invocationTyp = INVOKE_INTERFACE;
+ break;
+ case CodeConstants.opc_invokedynamic:
+ invocationTyp = INVOKE_DYNAMIC;
+
+ classname = "java/lang/Class"; // dummy class name
+ invoke_dynamic_classsuffix = "##Lambda_" + cn.index1 + "_" + cn.index2;
+ }
+
+ if ("<init>".equals(name)) {
+ functype = TYP_INIT;
+ }
+ else if ("<clinit>".equals(name)) {
+ functype = TYP_CLINIT;
+ }
+
+ stringDescriptor = cn.descriptor;
+ descriptor = MethodDescriptor.parseDescriptor(cn.descriptor);
+
+ for (int i = 0; i < descriptor.params.length; i++) {
+ lstParameters.add(0, stack.pop());
+ }
+
+ if (opcode == CodeConstants.opc_invokedynamic) {
+ if (dynamic_invokation_type == CodeConstants.CONSTANT_MethodHandle_REF_invokeStatic) {
+ isStatic = true;
+ }
+ else {
+ instance = lstParameters
+ .get(0); // FIXME: remove the first parameter completely from the list. It's the object type for a virtual lambda method.
+ }
+ }
+ else if (opcode == CodeConstants.opc_invokestatic) {
+ isStatic = true;
+ }
+ else {
+ instance = stack.pop();
+ }
+ }
+
+ private InvocationExprent(InvocationExprent expr) {
+ name = expr.getName();
+ classname = expr.getClassname();
+ isStatic = expr.isStatic();
+ functype = expr.getFunctype();
+ instance = expr.getInstance();
+ if (instance != null) {
+ instance = instance.copy();
+ }
+ invocationTyp = expr.getInvocationTyp();
+ stringDescriptor = expr.getStringDescriptor();
+ descriptor = expr.getDescriptor();
+ lstParameters = new ArrayList<Exprent>(expr.getLstParameters());
+ for (int i = 0; i < lstParameters.size(); i++) {
+ lstParameters.set(i, lstParameters.get(i).copy());
+ }
+ }
+
+
+ public VarType getExprType() {
+ return descriptor.ret;
+ }
+
+ public CheckTypesResult checkExprTypeBounds() {
+ CheckTypesResult result = new CheckTypesResult();
+
+ for (int i = 0; i < lstParameters.size(); i++) {
+ Exprent parameter = lstParameters.get(i);
+
+ VarType leftType = descriptor.params[i];
+
+ result.addMinTypeExprent(parameter, VarType.getMinTypeInFamily(leftType.type_family));
+ result.addMaxTypeExprent(parameter, leftType);
+ }
+
+ return result;
+ }
+
+ public List<Exprent> getAllExprents() {
+ List<Exprent> lst = new ArrayList<Exprent>();
+ if (instance != null) {
+ lst.add(instance);
+ }
+ lst.addAll(lstParameters);
+ return lst;
+ }
+
+
+ public Exprent copy() {
+ return new InvocationExprent(this);
+ }
+
+ public String toJava(int indent) {
+ StringBuilder buf = new StringBuilder("");
+
+ String super_qualifier = null;
+ boolean isInstanceThis = false;
+
+ if (invocationTyp == INVOKE_DYNAMIC) {
+ // ClassNode node = (ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASSNODE);
+ //
+ // if(node != null) {
+ // ClassNode lambda_node = DecompilerContext.getClassprocessor().getMapRootClasses().get(node.classStruct.qualifiedName + invoke_dynamic_classsuffix);
+ // if(lambda_node != null) {
+ //
+ // String typename = ExprProcessor.getCastTypeName(lambda_node.anonimousClassType);
+ //
+ // StringWriter strwriter = new StringWriter();
+ // BufferedWriter bufstrwriter = new BufferedWriter(strwriter);
+ //
+ // ClassWriter clwriter = new ClassWriter();
+ //
+ // try {
+ // bufstrwriter.write("new " + typename + "() {");
+ // bufstrwriter.newLine();
+ //
+ //
+ //
+ // bufstrwriter.flush();
+ // } catch(IOException ex) {
+ // throw new RuntimeException(ex);
+ // }
+ //
+ // buf.append(strwriter.toString());
+ //
+ // }
+ // }
+
+ }
+ else if (isStatic) {
+
+ ClassNode node = (ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_NODE);
+ if (node == null || !classname.equals(node.classStruct.qualifiedName)) {
+ buf.append(DecompilerContext.getImportCollector().getShortName(ExprProcessor.buildJavaClassName(classname)));
+ }
+ }
+ else {
+
+ if (instance != null && instance.type == Exprent.EXPRENT_VAR) {
+ VarExprent instvar = (VarExprent)instance;
+ VarVersionPaar varpaar = new VarVersionPaar(instvar);
+
+ VarProcessor vproc = instvar.getProcessor();
+ if (vproc == null) {
+ MethodWrapper current_meth = (MethodWrapper)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_WRAPPER);
+ if (current_meth != null) {
+ vproc = current_meth.varproc;
+ }
+ }
+
+ String this_classname = null;
+ if (vproc != null) {
+ this_classname = vproc.getThisvars().get(varpaar);
+ }
+
+ if (this_classname != null) {
+ isInstanceThis = true;
+
+ if (invocationTyp == INVOKE_SPECIAL) {
+ if (!classname.equals(this_classname)) { // TODO: direct comparison to the super class?
+ super_qualifier = this_classname;
+ }
+ }
+ }
+ }
+
+ if (functype == TYP_GENERAL) {
+ if (super_qualifier != null) {
+ StructClass current_class = ((ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_NODE)).classStruct;
+
+ if (!super_qualifier.equals(current_class.qualifiedName)) {
+ buf.append(DecompilerContext.getImportCollector().getShortName(ExprProcessor.buildJavaClassName(super_qualifier)));
+ buf.append(".");
+ }
+ buf.append("super");
+ }
+ else {
+ String res = instance.toJava(indent);
+
+ VarType rightType = instance.getExprType();
+ VarType leftType = new VarType(CodeConstants.TYPE_OBJECT, 0, classname);
+
+ if (rightType.equals(VarType.VARTYPE_OBJECT) && !leftType.equals(rightType)) {
+ buf.append("((").append(ExprProcessor.getCastTypeName(leftType)).append(")");
+
+ if (instance.getPrecedence() >= FunctionExprent.getPrecedence(FunctionExprent.FUNCTION_CAST)) {
+ res = "(" + res + ")";
+ }
+ buf.append(res).append(")");
+ }
+ else if (instance.getPrecedence() > getPrecedence()) {
+ buf.append("(").append(res).append(")");
+ }
+ else {
+ buf.append(res);
+ }
+ }
+ }
+ }
+
+ switch (functype) {
+ case TYP_GENERAL:
+ if (VarExprent.VAR_NAMELESS_ENCLOSURE.equals(buf.toString())) {
+ buf = new StringBuilder("");
+ }
+
+ if (buf.length() > 0) {
+ buf.append(".");
+ }
+
+ buf.append(name);
+ if (invocationTyp == INVOKE_DYNAMIC) {
+ buf.append("<invokedynamic>");
+ }
+ buf.append("(");
+
+ break;
+ case TYP_CLINIT:
+ throw new RuntimeException("Explicite invocation of <clinit>");
+ case TYP_INIT:
+ if (super_qualifier != null) {
+ buf.append("super(");
+ }
+ else if (isInstanceThis) {
+ buf.append("this(");
+ }
+ else {
+ buf.append(instance.toJava(indent));
+ buf.append(".<init>(");
+ // throw new RuntimeException("Unrecognized invocation of <init>"); // FIXME: activate
+ }
+ }
+
+ List<VarVersionPaar> sigFields = null;
+ boolean isEnum = false;
+ if (functype == TYP_INIT) {
+ ClassNode newNode = DecompilerContext.getClassProcessor().getMapRootClasses().get(classname);
+
+ if (newNode != null) { // own class
+ if (newNode.wrapper != null) {
+ sigFields = newNode.wrapper.getMethodWrapper("<init>", stringDescriptor).signatureFields;
+ }
+ else {
+ if (newNode.type == ClassNode.CLASS_MEMBER && (newNode.access & CodeConstants.ACC_STATIC) == 0) { // non-static member class
+ sigFields = new ArrayList<VarVersionPaar>(Collections.nCopies(lstParameters.size(), (VarVersionPaar)null));
+ sigFields.set(0, new VarVersionPaar(-1, 0));
+ }
+ }
+ isEnum = newNode.classStruct.hasModifier(CodeConstants.ACC_ENUM) && DecompilerContext.getOption(IFernflowerPreferences.DECOMPILE_ENUM);
+ }
+ }
+
+ Set<Integer> setAmbiguousParameters = getAmbiguousParameters();
+
+ boolean firstpar = true;
+ int start = isEnum ? 2 : 0;
+ for (int i = start; i < lstParameters.size(); i++) {
+ if (sigFields == null || sigFields.get(i) == null) {
+ if (!firstpar) {
+ buf.append(", ");
+ }
+
+ StringBuilder buff = new StringBuilder();
+ ExprProcessor.getCastedExprent(lstParameters.get(i), descriptor.params[i], buff, indent, true, setAmbiguousParameters.contains(i));
+
+ buf.append(buff);
+ firstpar = false;
+ }
+ }
+ buf.append(")");
+
+ return buf.toString();
+ }
+
+ private Set<Integer> getAmbiguousParameters() {
+
+ Set<Integer> ret = new HashSet<Integer>();
+
+ StructClass cstr = DecompilerContext.getStructContext().getClass(classname);
+ if (cstr != null) {
+ List<MethodDescriptor> lstMethods = new ArrayList<MethodDescriptor>();
+ for (StructMethod meth : cstr.getMethods()) {
+ if (name.equals(meth.getName())) {
+ MethodDescriptor md = MethodDescriptor.parseDescriptor(meth.getDescriptor());
+ if (md.params.length == descriptor.params.length) {
+ boolean equals = true;
+ for (int i = 0; i < md.params.length; i++) {
+ if (md.params[i].type_family != descriptor.params[i].type_family) {
+ equals = false;
+ break;
+ }
+ }
+
+ if (equals) {
+ lstMethods.add(md);
+ }
+ }
+ }
+ }
+
+ if (lstMethods.size() > 1) {
+ for (int i = 0; i < descriptor.params.length; i++) {
+ VarType partype = descriptor.params[i];
+
+ for (MethodDescriptor md : lstMethods) {
+ if (!partype.equals(md.params[i])) {
+ ret.add(i);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return ret;
+ }
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof InvocationExprent)) return false;
+
+ InvocationExprent it = (InvocationExprent)o;
+ return InterpreterUtil.equalObjects(name, it.getName()) &&
+ InterpreterUtil.equalObjects(classname, it.getClassname()) &&
+ isStatic == it.isStatic() &&
+ InterpreterUtil.equalObjects(instance, it.getInstance()) &&
+ InterpreterUtil.equalObjects(descriptor, it.getDescriptor()) &&
+ functype == it.getFunctype() &&
+ InterpreterUtil.equalLists(lstParameters, it.getLstParameters());
+ }
+
+ public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
+ if (oldexpr == instance) {
+ instance = newexpr;
+ }
+
+ for (int i = 0; i < lstParameters.size(); i++) {
+ if (oldexpr == lstParameters.get(i)) {
+ lstParameters.set(i, newexpr);
+ }
+ }
+ }
+
+ public List<Exprent> getLstParameters() {
+ return lstParameters;
+ }
+
+ public void setLstParameters(List<Exprent> lstParameters) {
+ this.lstParameters = lstParameters;
+ }
+
+ public MethodDescriptor getDescriptor() {
+ return descriptor;
+ }
+
+ public void setDescriptor(MethodDescriptor descriptor) {
+ this.descriptor = descriptor;
+ }
+
+ public String getClassname() {
+ return classname;
+ }
+
+ public void setClassname(String classname) {
+ this.classname = classname;
+ }
+
+ public int getFunctype() {
+ return functype;
+ }
+
+ public void setFunctype(int functype) {
+ this.functype = functype;
+ }
+
+ public Exprent getInstance() {
+ return instance;
+ }
+
+ public void setInstance(Exprent instance) {
+ this.instance = instance;
+ }
+
+ public boolean isStatic() {
+ return isStatic;
+ }
+
+ public void setStatic(boolean isStatic) {
+ this.isStatic = isStatic;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getStringDescriptor() {
+ return stringDescriptor;
+ }
+
+ public void setStringDescriptor(String stringDescriptor) {
+ this.stringDescriptor = stringDescriptor;
+ }
+
+ public int getInvocationTyp() {
+ return invocationTyp;
+ }
+
+ public void setInvocationTyp(int invocationTyp) {
+ this.invocationTyp = invocationTyp;
+ }
+
+ public String getInvokeDynamicClassSuffix() {
+ return invoke_dynamic_classsuffix;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/MonitorExprent.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/MonitorExprent.java
new file mode 100644
index 000000000000..9a1945e85ac7
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/MonitorExprent.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.exps;
+
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class MonitorExprent extends Exprent {
+
+ public static final int MONITOR_ENTER = 0;
+ public static final int MONITOR_EXIT = 1;
+
+ private int montype;
+
+ private Exprent value;
+
+ {
+ this.type = EXPRENT_MONITOR;
+ }
+
+ public MonitorExprent(int montype, Exprent value) {
+ this.montype = montype;
+ this.value = value;
+ }
+
+ public Exprent copy() {
+ return new MonitorExprent(montype, value.copy());
+ }
+
+ public List<Exprent> getAllExprents() {
+ List<Exprent> lst = new ArrayList<Exprent>();
+ lst.add(value);
+ return lst;
+ }
+
+ public String toJava(int indent) {
+ if (montype == MONITOR_ENTER) {
+ return "synchronized(" + value.toJava(indent) + ")";
+ }
+ else {
+ return "";
+ }
+ }
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof MonitorExprent)) return false;
+
+ MonitorExprent me = (MonitorExprent)o;
+ return montype == me.getMontype() &&
+ InterpreterUtil.equalObjects(value, me.getValue());
+ }
+
+ public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
+ if (oldexpr == value) {
+ value = newexpr;
+ }
+ }
+
+ public int getMontype() {
+ return montype;
+ }
+
+ public Exprent getValue() {
+ return value;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java
new file mode 100644
index 000000000000..416b831283f1
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/NewExprent.java
@@ -0,0 +1,504 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.exps;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.main.ClassWriter;
+import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
+import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.CheckTypesResult;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar;
+import org.jetbrains.java.decompiler.struct.StructClass;
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import org.jetbrains.java.decompiler.util.ListStack;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class NewExprent extends Exprent {
+
+ private InvocationExprent constructor;
+
+ private VarType newtype;
+
+ private List<Exprent> lstDims = new ArrayList<Exprent>();
+
+ private List<Exprent> lstArrayElements = new ArrayList<Exprent>();
+
+ private boolean directArrayInit;
+
+ private boolean anonymous;
+
+ private boolean lambda;
+
+ private boolean enumconst;
+
+ {
+ this.type = EXPRENT_NEW;
+ }
+
+ public NewExprent(VarType newtype, ListStack<Exprent> stack, int arraydim) {
+ this.newtype = newtype;
+ for (int i = 0; i < arraydim; i++) {
+ lstDims.add(0, stack.pop());
+ }
+
+ setAnonymous();
+ }
+
+ public NewExprent(VarType newtype, List<Exprent> lstDims) {
+ this.newtype = newtype;
+ this.lstDims = lstDims;
+
+ setAnonymous();
+ }
+
+ private void setAnonymous() {
+
+ anonymous = false;
+ lambda = false;
+
+ if (newtype.type == CodeConstants.TYPE_OBJECT && newtype.arraydim == 0) {
+ ClassNode node = DecompilerContext.getClassProcessor().getMapRootClasses().get(newtype.value);
+
+ if (node != null && (node.type == ClassNode.CLASS_ANONYMOUS || node.type == ClassNode.CLASS_LAMBDA)) {
+ anonymous = true;
+
+ if (node.type == ClassNode.CLASS_LAMBDA) {
+ lambda = true;
+ }
+ }
+ }
+ }
+
+ public VarType getExprType() {
+
+ if (anonymous) {
+ ClassNode node = DecompilerContext.getClassProcessor().getMapRootClasses().get(newtype.value);
+
+ return node.anonimousClassType;
+ }
+ else {
+ return newtype;
+ }
+ }
+
+ public CheckTypesResult checkExprTypeBounds() {
+ CheckTypesResult result = new CheckTypesResult();
+
+ if (newtype.arraydim != 0) {
+ for (Exprent dim : lstDims) {
+ result.addMinTypeExprent(dim, VarType.VARTYPE_BYTECHAR);
+ result.addMaxTypeExprent(dim, VarType.VARTYPE_INT);
+ }
+
+ if (newtype.arraydim == 1) {
+
+ VarType leftType = newtype.copy();
+ leftType.decArrayDim();
+
+ for (Exprent element : lstArrayElements) {
+ result.addMinTypeExprent(element, VarType.getMinTypeInFamily(leftType.type_family));
+ result.addMaxTypeExprent(element, leftType);
+ }
+ }
+ }
+ else {
+ if (constructor != null) {
+ return constructor.checkExprTypeBounds();
+ }
+ }
+
+ return result;
+ }
+
+ public List<Exprent> getAllExprents() {
+ List<Exprent> lst = new ArrayList<Exprent>();
+ if (newtype.arraydim == 0) {
+ if (constructor != null) {
+ Exprent constructor_instance = constructor.getInstance();
+
+ if (constructor_instance != null) { // should be true only for a lambda expression with a virtual content method
+ lst.add(constructor_instance);
+ }
+
+ lst.addAll(constructor.getLstParameters());
+ }
+ }
+ else {
+ lst.addAll(lstDims);
+ lst.addAll(lstArrayElements);
+ }
+
+ return lst;
+ }
+
+ public Exprent copy() {
+ List<Exprent> lst = new ArrayList<Exprent>();
+ for (Exprent expr : lstDims) {
+ lst.add(expr.copy());
+ }
+
+ NewExprent ret = new NewExprent(newtype, lst);
+ ret.setConstructor(constructor == null ? null : (InvocationExprent)constructor.copy());
+ ret.setLstArrayElements(lstArrayElements);
+ ret.setDirectArrayInit(directArrayInit);
+ ret.setAnonymous(anonymous);
+ ret.setEnumconst(enumconst);
+ return ret;
+ }
+
+ public int getPrecedence() {
+ return 1; // precedence of new
+ }
+
+ public String toJava(int indent) {
+ StringBuilder buf = new StringBuilder();
+
+ if (anonymous) {
+
+ ClassNode child = DecompilerContext.getClassProcessor().getMapRootClasses().get(newtype.value);
+
+ buf.append("(");
+
+ if (!lambda && constructor != null) {
+
+ InvocationExprent invsuper = child.superInvocation;
+
+ ClassNode newnode = DecompilerContext.getClassProcessor().getMapRootClasses().get(invsuper.getClassname());
+
+ List<VarVersionPaar> sigFields = null;
+ if (newnode != null) { // own class
+ if (newnode.wrapper != null) {
+ sigFields = newnode.wrapper.getMethodWrapper("<init>", invsuper.getStringDescriptor()).signatureFields;
+ }
+ else {
+ if (newnode.type == ClassNode.CLASS_MEMBER && (newnode.access & CodeConstants.ACC_STATIC) == 0 &&
+ !constructor.getLstParameters().isEmpty()) { // member non-static class invoked with enclosing class instance
+ sigFields = new ArrayList<VarVersionPaar>(Collections.nCopies(constructor.getLstParameters().size(), (VarVersionPaar)null));
+ sigFields.set(0, new VarVersionPaar(-1, 0));
+ }
+ }
+ }
+
+ boolean firstpar = true;
+ int start = 0, end = invsuper.getLstParameters().size();
+ if (enumconst) {
+ start += 2;
+ end -= 1;
+ }
+ for (int i = start; i < end; i++) {
+ if (sigFields == null || sigFields.get(i) == null) {
+ if (!firstpar) {
+ buf.append(", ");
+ }
+
+ Exprent param = invsuper.getLstParameters().get(i);
+ if (param.type == Exprent.EXPRENT_VAR) {
+ int varindex = ((VarExprent)param).getIndex();
+ if (varindex > 0 && varindex <= constructor.getLstParameters().size()) {
+ param = constructor.getLstParameters().get(varindex - 1);
+ }
+ }
+
+ StringBuilder buff = new StringBuilder();
+ ExprProcessor.getCastedExprent(param, invsuper.getDescriptor().params[i], buff, indent, true);
+
+ buf.append(buff);
+ firstpar = false;
+ }
+ }
+ }
+
+ if (!enumconst) {
+ String enclosing = null;
+ if (!lambda && constructor != null) {
+ enclosing = getQualifiedNewInstance(child.anonimousClassType.value, constructor.getLstParameters(), indent);
+ }
+
+ String typename = ExprProcessor.getCastTypeName(child.anonimousClassType);
+
+ if (enclosing != null) {
+ ClassNode anonimousNode = DecompilerContext.getClassProcessor().getMapRootClasses().get(child.anonimousClassType.value);
+ if (anonimousNode != null) {
+ typename = anonimousNode.simpleName;
+ }
+ else {
+ typename = typename.substring(typename.lastIndexOf('.') + 1);
+ }
+ }
+ buf.insert(0, "new " + typename);
+
+ if (enclosing != null) {
+ buf.insert(0, enclosing + ".");
+ }
+ }
+
+ buf.append(")");
+
+ if (enumconst && buf.length() == 2) {
+ buf.setLength(0);
+ }
+
+ if (lambda) {
+ if (!DecompilerContext.getOption(IFernflowerPreferences.LAMBDA_TO_ANONYMOUS_CLASS)) {
+ buf.setLength(0); // remove the usual 'new <class>()', it will be replaced with lambda style '() ->'
+ }
+ Exprent methodObject = constructor == null ? null : constructor.getInstance();
+ new ClassWriter().classLambdaToJava(child, buf, methodObject, indent);
+ }
+ else {
+ new ClassWriter().classToJava(child, buf, indent);
+ }
+ }
+ else if (directArrayInit) {
+ VarType leftType = newtype.copy();
+ leftType.decArrayDim();
+
+ buf.append("{");
+ for (int i = 0; i < lstArrayElements.size(); i++) {
+ if (i > 0) {
+ buf.append(", ");
+ }
+ ExprProcessor.getCastedExprent(lstArrayElements.get(i), leftType, buf, indent, false);
+ }
+ buf.append("}");
+ }
+ else {
+ if (newtype.arraydim == 0) {
+
+ if (constructor != null) {
+
+ List<Exprent> lstParameters = constructor.getLstParameters();
+
+ ClassNode newnode = DecompilerContext.getClassProcessor().getMapRootClasses().get(constructor.getClassname());
+
+ List<VarVersionPaar> sigFields = null;
+ if (newnode != null) { // own class
+ if (newnode.wrapper != null) {
+ sigFields = newnode.wrapper.getMethodWrapper("<init>", constructor.getStringDescriptor()).signatureFields;
+ }
+ else {
+ if (newnode.type == ClassNode.CLASS_MEMBER && (newnode.access & CodeConstants.ACC_STATIC) == 0 &&
+ !constructor.getLstParameters().isEmpty()) { // member non-static class invoked with enclosing class instance
+ sigFields = new ArrayList<VarVersionPaar>(Collections.nCopies(lstParameters.size(), (VarVersionPaar)null));
+ sigFields.set(0, new VarVersionPaar(-1, 0));
+ }
+ }
+ }
+
+ int start = enumconst ? 2 : 0;
+ if (!enumconst || start < lstParameters.size()) {
+ buf.append("(");
+
+ boolean firstpar = true;
+ for (int i = start; i < lstParameters.size(); i++) {
+ if (sigFields == null || sigFields.get(i) == null) {
+ if (!firstpar) {
+ buf.append(", ");
+ }
+
+ StringBuilder buff = new StringBuilder();
+ ExprProcessor.getCastedExprent(lstParameters.get(i), constructor.getDescriptor().params[i], buff, indent, true);
+
+ buf.append(buff);
+ firstpar = false;
+ }
+ }
+ buf.append(")");
+ }
+ }
+
+ if (!enumconst) {
+ String enclosing = null;
+ if (constructor != null) {
+ enclosing = getQualifiedNewInstance(newtype.value, constructor.getLstParameters(), indent);
+ }
+
+ String typename = ExprProcessor.getTypeName(newtype);
+
+ if (enclosing != null) {
+ ClassNode newNode = DecompilerContext.getClassProcessor().getMapRootClasses().get(newtype.value);
+ if (newNode != null) {
+ typename = newNode.simpleName;
+ }
+ else {
+ typename = typename.substring(typename.lastIndexOf('.') + 1);
+ }
+ }
+ buf.insert(0, "new " + typename);
+
+ if (enclosing != null) {
+ buf.insert(0, enclosing + ".");
+ }
+ }
+ }
+ else {
+ buf.append("new ").append(ExprProcessor.getTypeName(newtype));
+
+ if (lstArrayElements.isEmpty()) {
+ for (int i = 0; i < newtype.arraydim; i++) {
+ buf.append("[").append(i < lstDims.size() ? lstDims.get(i).toJava(indent) : "").append("]");
+ }
+ }
+ else {
+ for (int i = 0; i < newtype.arraydim; i++) {
+ buf.append("[]");
+ }
+
+ VarType leftType = newtype.copy();
+ leftType.decArrayDim();
+
+ buf.append("{");
+ for (int i = 0; i < lstArrayElements.size(); i++) {
+ if (i > 0) {
+ buf.append(", ");
+ }
+ StringBuilder buff = new StringBuilder();
+ ExprProcessor.getCastedExprent(lstArrayElements.get(i), leftType, buff, indent, false);
+
+ buf.append(buff);
+ }
+ buf.append("}");
+ }
+ }
+ }
+ return buf.toString();
+ }
+
+ private static String getQualifiedNewInstance(String classname, List<Exprent> lstParams, int indent) {
+
+ ClassNode node = DecompilerContext.getClassProcessor().getMapRootClasses().get(classname);
+
+ if (node != null && node.type != ClassNode.CLASS_ROOT && (node.access & CodeConstants.ACC_STATIC) == 0) {
+ if (!lstParams.isEmpty()) {
+ Exprent enclosing = lstParams.get(0);
+
+ boolean isQualifiedNew = false;
+
+ if (enclosing.type == Exprent.EXPRENT_VAR) {
+ VarExprent varEnclosing = (VarExprent)enclosing;
+
+ StructClass current_class = ((ClassNode)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS_NODE)).classStruct;
+ String this_classname = varEnclosing.getProcessor().getThisvars().get(new VarVersionPaar(varEnclosing));
+
+ if (!current_class.qualifiedName.equals(this_classname)) {
+ isQualifiedNew = true;
+ }
+ }
+ else {
+ isQualifiedNew = true;
+ }
+
+ if (isQualifiedNew) {
+ return enclosing.toJava(indent);
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof NewExprent)) return false;
+
+ NewExprent ne = (NewExprent)o;
+ return InterpreterUtil.equalObjects(newtype, ne.getNewtype()) &&
+ InterpreterUtil.equalLists(lstDims, ne.getLstDims()) &&
+ InterpreterUtil.equalObjects(constructor, ne.getConstructor()) &&
+ directArrayInit == ne.directArrayInit &&
+ InterpreterUtil.equalLists(lstArrayElements, ne.getLstArrayElements());
+ }
+
+ public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
+ if (oldexpr == constructor) {
+ constructor = (InvocationExprent)newexpr;
+ }
+
+ if (constructor != null) {
+ constructor.replaceExprent(oldexpr, newexpr);
+ }
+
+ for (int i = 0; i < lstDims.size(); i++) {
+ if (oldexpr == lstDims.get(i)) {
+ lstDims.set(i, newexpr);
+ }
+ }
+
+ for (int i = 0; i < lstArrayElements.size(); i++) {
+ if (oldexpr == lstArrayElements.get(i)) {
+ lstArrayElements.set(i, newexpr);
+ }
+ }
+ }
+
+ public InvocationExprent getConstructor() {
+ return constructor;
+ }
+
+ public void setConstructor(InvocationExprent constructor) {
+ this.constructor = constructor;
+ }
+
+ public List<Exprent> getLstDims() {
+ return lstDims;
+ }
+
+ public VarType getNewtype() {
+ return newtype;
+ }
+
+ public List<Exprent> getLstArrayElements() {
+ return lstArrayElements;
+ }
+
+ public void setLstArrayElements(List<Exprent> lstArrayElements) {
+ this.lstArrayElements = lstArrayElements;
+ }
+
+ public boolean isDirectArrayInit() {
+ return directArrayInit;
+ }
+
+ public void setDirectArrayInit(boolean directArrayInit) {
+ this.directArrayInit = directArrayInit;
+ }
+
+ public boolean isLambda() {
+ return lambda;
+ }
+
+ public boolean isAnonymous() {
+ return anonymous;
+ }
+
+ public void setAnonymous(boolean anonymous) {
+ this.anonymous = anonymous;
+ }
+
+ public boolean isEnumconst() {
+ return enumconst;
+ }
+
+ public void setEnumconst(boolean enumconst) {
+ this.enumconst = enumconst;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchExprent.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchExprent.java
new file mode 100644
index 000000000000..36bead20490d
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/SwitchExprent.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.exps;
+
+import org.jetbrains.java.decompiler.modules.decompiler.vars.CheckTypesResult;
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class SwitchExprent extends Exprent {
+
+ private Exprent value;
+
+ private List<List<ConstExprent>> caseValues = new ArrayList<List<ConstExprent>>();
+
+ {
+ this.type = EXPRENT_SWITCH;
+ }
+
+ public SwitchExprent(Exprent value) {
+ this.value = value;
+ }
+
+ public Exprent copy() {
+ SwitchExprent swexpr = new SwitchExprent(value.copy());
+
+ List<List<ConstExprent>> lstCaseValues = new ArrayList<List<ConstExprent>>();
+ for (List<ConstExprent> lst : caseValues) {
+ lstCaseValues.add(new ArrayList<ConstExprent>(lst));
+ }
+ swexpr.setCaseValues(lstCaseValues);
+
+ return swexpr;
+ }
+
+ public VarType getExprType() {
+ return value.getExprType();
+ }
+
+ public CheckTypesResult checkExprTypeBounds() {
+ CheckTypesResult result = new CheckTypesResult();
+
+ result.addMinTypeExprent(value, VarType.VARTYPE_BYTECHAR);
+ result.addMaxTypeExprent(value, VarType.VARTYPE_INT);
+
+ VarType valtype = value.getExprType();
+ for (List<ConstExprent> lst : caseValues) {
+ for (ConstExprent expr : lst) {
+ if (expr != null) {
+ VarType casetype = expr.getExprType();
+ if (!casetype.equals(valtype)) {
+ valtype = VarType.getCommonSupertype(casetype, valtype);
+ result.addMinTypeExprent(value, valtype);
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ public List<Exprent> getAllExprents() {
+ List<Exprent> lst = new ArrayList<Exprent>();
+ lst.add(value);
+ return lst;
+ }
+
+ public String toJava(int indent) {
+ return "switch(" + value.toJava(indent) + ")";
+ }
+
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+
+ if (o == null || !(o instanceof SwitchExprent)) {
+ return false;
+ }
+
+ SwitchExprent sw = (SwitchExprent)o;
+ return InterpreterUtil.equalObjects(value, sw.getValue());
+ }
+
+ public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
+ if (oldexpr == value) {
+ value = newexpr;
+ }
+ }
+
+ public Exprent getValue() {
+ return value;
+ }
+
+ public void setCaseValues(List<List<ConstExprent>> caseValues) {
+ this.caseValues = caseValues;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java
new file mode 100644
index 000000000000..352350171a7a
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/exps/VarExprent.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.exps;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.main.ClassWriter;
+import org.jetbrains.java.decompiler.main.ClassesProcessor.ClassNode;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarTypeProcessor;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar;
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class VarExprent extends Exprent {
+
+ public static final int STACK_BASE = 10000;
+
+ public static final String VAR_NAMELESS_ENCLOSURE = "<VAR_NAMELESS_ENCLOSURE>";
+
+ private int index;
+
+ private VarType vartype;
+
+ private boolean definition = false;
+
+ private VarProcessor processor;
+
+ private int version = 0;
+
+ private boolean classdef = false;
+
+ private boolean stack = false;
+
+ {
+ this.type = EXPRENT_VAR;
+ }
+
+ public VarExprent(int index, VarType vartype, VarProcessor processor) {
+ this.index = index;
+ this.vartype = vartype;
+ this.processor = processor;
+ }
+
+ public VarType getExprType() {
+ return getVartype();
+ }
+
+ public int getExprentUse() {
+ return Exprent.MULTIPLE_USES | Exprent.SIDE_EFFECTS_FREE;
+ }
+
+ public List<Exprent> getAllExprents() {
+ return new ArrayList<Exprent>();
+ }
+
+ public Exprent copy() {
+ VarExprent var = new VarExprent(index, getVartype(), processor);
+ var.setDefinition(definition);
+ var.setVersion(version);
+ var.setClassdef(classdef);
+ var.setStack(stack);
+ return var;
+ }
+
+ public String toJava(int indent) {
+ StringBuilder buffer = new StringBuilder();
+
+ if (classdef) {
+ ClassNode child = DecompilerContext.getClassProcessor().getMapRootClasses().get(vartype.value);
+ new ClassWriter().classToJava(child, buffer, indent);
+ }
+ else {
+ String name = null;
+ if (processor != null) {
+ name = processor.getVarName(new VarVersionPaar(index, version));
+ }
+
+ if (definition) {
+ if (processor != null && processor.getVarFinal(new VarVersionPaar(index, version)) == VarTypeProcessor.VAR_FINALEXPLICIT) {
+ buffer.append("final ");
+ }
+ buffer.append(ExprProcessor.getCastTypeName(getVartype())).append(" ");
+ }
+ buffer.append(name == null ? ("var" + index + (version == 0 ? "" : "_" + version)) : name);
+ }
+
+ return buffer.toString();
+ }
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof VarExprent)) return false;
+
+ VarExprent ve = (VarExprent)o;
+ return index == ve.getIndex() &&
+ version == ve.getVersion() &&
+ InterpreterUtil.equalObjects(getVartype(), ve.getVartype()); // FIXME: vartype comparison redundant?
+ }
+
+ public int getIndex() {
+ return index;
+ }
+
+ public void setIndex(int index) {
+ this.index = index;
+ }
+
+ public VarType getVartype() {
+ VarType vt = null;
+ if (processor != null) {
+ vt = processor.getVarType(new VarVersionPaar(index, version));
+ }
+
+ if (vt == null || (vartype != null && vartype.type != CodeConstants.TYPE_UNKNOWN)) {
+ vt = vartype;
+ }
+
+ return vt == null ? VarType.VARTYPE_UNKNOWN : vt;
+ }
+
+ public void setVartype(VarType vartype) {
+ this.vartype = vartype;
+ }
+
+ public boolean isDefinition() {
+ return definition;
+ }
+
+ public void setDefinition(boolean definition) {
+ this.definition = definition;
+ }
+
+ public VarProcessor getProcessor() {
+ return processor;
+ }
+
+ public void setProcessor(VarProcessor processor) {
+ this.processor = processor;
+ }
+
+ public int getVersion() {
+ return version;
+ }
+
+ public void setVersion(int version) {
+ this.version = version;
+ }
+
+ public boolean isClassdef() {
+ return classdef;
+ }
+
+ public void setClassdef(boolean classdef) {
+ this.classdef = classdef;
+ }
+
+ public boolean isStack() {
+ return stack;
+ }
+
+ public void setStack(boolean stack) {
+ this.stack = stack;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/DirectGraph.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/DirectGraph.java
new file mode 100644
index 000000000000..b24b72c261ea
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/DirectGraph.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.sforms;
+
+import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
+import org.jetbrains.java.decompiler.modules.decompiler.sforms.FlattenStatementsHelper.FinallyPathWrapper;
+import org.jetbrains.java.decompiler.util.VBStyleCollection;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+
+
+public class DirectGraph {
+
+ public VBStyleCollection<DirectNode, String> nodes = new VBStyleCollection<DirectNode, String>();
+
+ public DirectNode first;
+
+ // exit, [source, destination]
+ public HashMap<String, List<FinallyPathWrapper>> mapShortRangeFinallyPaths = new HashMap<String, List<FinallyPathWrapper>>();
+
+ // exit, [source, destination]
+ public HashMap<String, List<FinallyPathWrapper>> mapLongRangeFinallyPaths = new HashMap<String, List<FinallyPathWrapper>>();
+
+ // negative if branches (recorded for handling of && and ||)
+ public HashMap<String, String> mapNegIfBranch = new HashMap<String, String>();
+
+ // nodes, that are exception exits of a finally block with monitor variable
+ public HashMap<String, String> mapFinallyMonitorExceptionPathExits = new HashMap<String, String>();
+
+ public void sortReversePostOrder() {
+ LinkedList<DirectNode> res = new LinkedList<DirectNode>();
+ addToReversePostOrderListIterative(first, res);
+
+ nodes.clear();
+ for (DirectNode node : res) {
+ nodes.addWithKey(node, node.id);
+ }
+ }
+
+ private static void addToReversePostOrderListIterative(DirectNode root, List<DirectNode> lst) {
+
+ LinkedList<DirectNode> stackNode = new LinkedList<DirectNode>();
+ LinkedList<Integer> stackIndex = new LinkedList<Integer>();
+
+ HashSet<DirectNode> setVisited = new HashSet<DirectNode>();
+
+ stackNode.add(root);
+ stackIndex.add(0);
+
+ while (!stackNode.isEmpty()) {
+
+ DirectNode node = stackNode.getLast();
+ int index = stackIndex.removeLast();
+
+ setVisited.add(node);
+
+ for (; index < node.succs.size(); index++) {
+ DirectNode succ = node.succs.get(index);
+
+ if (!setVisited.contains(succ)) {
+ stackIndex.add(index + 1);
+
+ stackNode.add(succ);
+ stackIndex.add(0);
+
+ break;
+ }
+ }
+
+ if (index == node.succs.size()) {
+ lst.add(0, node);
+
+ stackNode.removeLast();
+ }
+ }
+ }
+
+
+ public boolean iterateExprents(ExprentIterator iter) {
+
+ LinkedList<DirectNode> stack = new LinkedList<DirectNode>();
+ stack.add(first);
+
+ HashSet<DirectNode> setVisited = new HashSet<DirectNode>();
+
+ while (!stack.isEmpty()) {
+
+ DirectNode node = stack.removeFirst();
+
+ if (setVisited.contains(node)) {
+ continue;
+ }
+ setVisited.add(node);
+
+ for (int i = 0; i < node.exprents.size(); i++) {
+ int res = iter.processExprent(node.exprents.get(i));
+
+ if (res == 1) {
+ return false;
+ }
+
+ if (res == 2) {
+ node.exprents.remove(i);
+ i--;
+ }
+ }
+
+ stack.addAll(node.succs);
+ }
+
+ return true;
+ }
+
+ public interface ExprentIterator {
+ // 0 - success, do nothing
+ // 1 - cancel iteration
+ // 2 - success, delete exprent
+ int processExprent(Exprent exprent);
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/DirectNode.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/DirectNode.java
new file mode 100644
index 000000000000..73303ec6a6d4
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/DirectNode.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.sforms;
+
+import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.BasicBlockStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class DirectNode {
+
+ public static final int NODE_DIRECT = 1;
+ public static final int NODE_TAIL = 2;
+ public static final int NODE_INIT = 3;
+ public static final int NODE_CONDITION = 4;
+ public static final int NODE_INCREMENT = 5;
+ public static final int NODE_TRY = 6;
+
+ public int type;
+
+ public String id;
+
+ public BasicBlockStatement block;
+
+ public Statement statement;
+
+ public List<Exprent> exprents = new ArrayList<Exprent>();
+
+ public List<DirectNode> succs = new ArrayList<DirectNode>();
+
+ public List<DirectNode> preds = new ArrayList<DirectNode>();
+
+ public DirectNode(int type, Statement statement, String id) {
+ this.type = type;
+ this.statement = statement;
+ this.id = id;
+ }
+
+ public DirectNode(int type, Statement statement, BasicBlockStatement block) {
+ this.type = type;
+ this.statement = statement;
+
+ this.id = block.id.toString();
+ this.block = block;
+ }
+
+ @Override
+ public String toString() {
+ return id;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/FlattenStatementsHelper.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/FlattenStatementsHelper.java
new file mode 100644
index 000000000000..05d2f33b27e5
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/FlattenStatementsHelper.java
@@ -0,0 +1,574 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.sforms;
+
+import org.jetbrains.java.decompiler.modules.decompiler.StatEdge;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.*;
+
+import java.util.*;
+import java.util.Map.Entry;
+
+
+public class FlattenStatementsHelper {
+
+ // statement.id, node.id(direct), node.id(continue)
+ private Map<Integer, String[]> mapDestinationNodes = new HashMap<Integer, String[]>();
+
+ // node.id(source), statement.id(destination), edge type
+ private List<Edge> listEdges = new ArrayList<Edge>();
+
+ // node.id(exit), [node.id(source), statement.id(destination)]
+ private Map<String, List<String[]>> mapShortRangeFinallyPathIds = new HashMap<String, List<String[]>>();
+
+ // node.id(exit), [node.id(source), statement.id(destination)]
+ private Map<String, List<String[]>> mapLongRangeFinallyPathIds = new HashMap<String, List<String[]>>();
+
+ // positive if branches
+ private Map<String, Integer> mapPosIfBranch = new HashMap<String, Integer>();
+
+ private DirectGraph graph;
+
+ private RootStatement root;
+
+ public DirectGraph buildDirectGraph(RootStatement root) {
+
+ this.root = root;
+
+ graph = new DirectGraph();
+
+ flattenStatement();
+
+ // dummy exit node
+ Statement dummyexit = root.getDummyExit();
+ DirectNode node = new DirectNode(DirectNode.NODE_DIRECT, dummyexit, dummyexit.id.toString());
+ node.exprents = new ArrayList<Exprent>();
+ graph.nodes.addWithKey(node, node.id);
+ mapDestinationNodes.put(dummyexit.id, new String[]{node.id, null});
+
+ setEdges();
+
+ graph.first = graph.nodes.getWithKey(mapDestinationNodes.get(root.id)[0]);
+ graph.sortReversePostOrder();
+
+ return graph;
+ }
+
+ private void flattenStatement() {
+
+ class StatementStackEntry {
+ public Statement statement;
+ public LinkedList<StackEntry> stackFinally;
+ public List<Exprent> tailExprents;
+
+ public int statementIndex;
+ public int edgeIndex;
+ public List<StatEdge> succEdges;
+
+ public StatementStackEntry(Statement statement, LinkedList<StackEntry> stackFinally, List<Exprent> tailExprents) {
+ this.statement = statement;
+ this.stackFinally = stackFinally;
+ this.tailExprents = tailExprents;
+ }
+ }
+
+ LinkedList<StatementStackEntry> lstStackStatements = new LinkedList<StatementStackEntry>();
+
+ lstStackStatements.add(new StatementStackEntry(root, new LinkedList<StackEntry>(), null));
+
+ mainloop:
+ while (!lstStackStatements.isEmpty()) {
+
+ StatementStackEntry statEntry = lstStackStatements.removeFirst();
+
+ Statement stat = statEntry.statement;
+ LinkedList<StackEntry> stackFinally = statEntry.stackFinally;
+ int statementBreakIndex = statEntry.statementIndex;
+
+ DirectNode node, nd;
+
+ List<StatEdge> lstSuccEdges = new ArrayList<StatEdge>();
+ DirectNode sourcenode = null;
+
+ if (statEntry.succEdges == null) {
+
+ switch (stat.type) {
+ case Statement.TYPE_BASICBLOCK:
+ node = new DirectNode(DirectNode.NODE_DIRECT, stat, (BasicBlockStatement)stat);
+ if (stat.getExprents() != null) {
+ node.exprents = stat.getExprents();
+ }
+ graph.nodes.putWithKey(node, node.id);
+ mapDestinationNodes.put(stat.id, new String[]{node.id, null});
+
+ lstSuccEdges.addAll(stat.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL));
+ sourcenode = node;
+
+ List<Exprent> tailExprentList = statEntry.tailExprents;
+
+ if (tailExprentList != null) {
+ DirectNode tail = new DirectNode(DirectNode.NODE_TAIL, stat, stat.id + "_tail");
+ tail.exprents = tailExprentList;
+ graph.nodes.putWithKey(tail, tail.id);
+
+ mapDestinationNodes.put(-stat.id, new String[]{tail.id, null});
+ listEdges.add(new Edge(node.id, -stat.id, StatEdge.TYPE_REGULAR));
+
+ sourcenode = tail;
+ }
+
+ // 'if' statement: record positive branch
+ if (stat.getLastBasicType() == Statement.LASTBASICTYPE_IF) {
+ mapPosIfBranch.put(sourcenode.id, lstSuccEdges.get(0).getDestination().id);
+ }
+
+ break;
+ case Statement.TYPE_CATCHALL:
+ case Statement.TYPE_TRYCATCH:
+ DirectNode firstnd = new DirectNode(DirectNode.NODE_TRY, stat, stat.id + "_try");
+
+ mapDestinationNodes.put(stat.id, new String[]{firstnd.id, null});
+ graph.nodes.putWithKey(firstnd, firstnd.id);
+
+ LinkedList<StatementStackEntry> lst = new LinkedList<StatementStackEntry>();
+
+ for (Statement st : stat.getStats()) {
+ listEdges.add(new Edge(firstnd.id, st.id, StatEdge.TYPE_REGULAR));
+
+ LinkedList<StackEntry> stack = stackFinally;
+ if (stat.type == Statement.TYPE_CATCHALL && ((CatchAllStatement)stat).isFinally()) {
+ stack = new LinkedList<StackEntry>(stackFinally);
+
+ if (st == stat.getFirst()) { // catch head
+ stack.add(new StackEntry((CatchAllStatement)stat, Boolean.FALSE));
+ }
+ else { // handler
+ stack.add(new StackEntry((CatchAllStatement)stat, Boolean.TRUE, StatEdge.TYPE_BREAK,
+ root.getDummyExit(), st, st, firstnd, firstnd, true));
+ }
+ }
+ lst.add(new StatementStackEntry(st, stack, null));
+ }
+
+ lstStackStatements.addAll(0, lst);
+ break;
+ case Statement.TYPE_DO:
+ if (statementBreakIndex == 0) {
+ statEntry.statementIndex = 1;
+ lstStackStatements.addFirst(statEntry);
+ lstStackStatements.addFirst(new StatementStackEntry(stat.getFirst(), stackFinally, null));
+
+ continue mainloop;
+ }
+
+ nd = graph.nodes.getWithKey(mapDestinationNodes.get(stat.getFirst().id)[0]);
+
+ DoStatement dostat = (DoStatement)stat;
+ int looptype = dostat.getLooptype();
+
+ if (looptype == DoStatement.LOOP_DO) {
+ mapDestinationNodes.put(stat.id, new String[]{nd.id, nd.id});
+ break;
+ }
+
+ lstSuccEdges.add(stat.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL).get(0)); // exactly one edge
+
+ switch (looptype) {
+ case DoStatement.LOOP_WHILE:
+ case DoStatement.LOOP_DOWHILE:
+ node = new DirectNode(DirectNode.NODE_CONDITION, stat, stat.id + "_cond");
+ node.exprents = dostat.getConditionExprentList();
+ graph.nodes.putWithKey(node, node.id);
+
+ listEdges.add(new Edge(node.id, stat.getFirst().id, StatEdge.TYPE_REGULAR));
+
+ if (looptype == DoStatement.LOOP_WHILE) {
+ mapDestinationNodes.put(stat.id, new String[]{node.id, node.id});
+ }
+ else {
+ mapDestinationNodes.put(stat.id, new String[]{nd.id, node.id});
+
+ boolean found = false;
+ for (Edge edge : listEdges) {
+ if (edge.statid.equals(stat.id) && edge.edgetype == StatEdge.TYPE_CONTINUE) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ listEdges.add(new Edge(nd.id, stat.id, StatEdge.TYPE_CONTINUE));
+ }
+ }
+ sourcenode = node;
+ break;
+ case DoStatement.LOOP_FOR:
+ DirectNode nodeinit = new DirectNode(DirectNode.NODE_INIT, stat, stat.id + "_init");
+ if (dostat.getInitExprent() != null) {
+ nodeinit.exprents = dostat.getInitExprentList();
+ }
+ graph.nodes.putWithKey(nodeinit, nodeinit.id);
+
+ DirectNode nodecond = new DirectNode(DirectNode.NODE_CONDITION, stat, stat.id + "_cond");
+ nodecond.exprents = dostat.getConditionExprentList();
+ graph.nodes.putWithKey(nodecond, nodecond.id);
+
+ DirectNode nodeinc = new DirectNode(DirectNode.NODE_INCREMENT, stat, stat.id + "_inc");
+ nodeinc.exprents = dostat.getIncExprentList();
+ graph.nodes.putWithKey(nodeinc, nodeinc.id);
+
+ mapDestinationNodes.put(stat.id, new String[]{nodeinit.id, nodeinc.id});
+ mapDestinationNodes.put(-stat.id, new String[]{nodecond.id, null});
+
+ listEdges.add(new Edge(nodecond.id, stat.getFirst().id, StatEdge.TYPE_REGULAR));
+ listEdges.add(new Edge(nodeinit.id, -stat.id, StatEdge.TYPE_REGULAR));
+ listEdges.add(new Edge(nodeinc.id, -stat.id, StatEdge.TYPE_REGULAR));
+
+ boolean found = false;
+ for (Edge edge : listEdges) {
+ if (edge.statid.equals(stat.id) && edge.edgetype == StatEdge.TYPE_CONTINUE) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ listEdges.add(new Edge(nd.id, stat.id, StatEdge.TYPE_CONTINUE));
+ }
+
+ sourcenode = nodecond;
+ }
+ break;
+ case Statement.TYPE_SYNCRONIZED:
+ case Statement.TYPE_SWITCH:
+ case Statement.TYPE_IF:
+ case Statement.TYPE_SEQUENCE:
+ case Statement.TYPE_ROOT:
+ int statsize = stat.getStats().size();
+ if (stat.type == Statement.TYPE_SYNCRONIZED) {
+ statsize = 2; // exclude the handler if synchronized
+ }
+
+ if (statementBreakIndex <= statsize) {
+ List<Exprent> tailexprlst = null;
+
+ switch (stat.type) {
+ case Statement.TYPE_SYNCRONIZED:
+ tailexprlst = ((SynchronizedStatement)stat).getHeadexprentList();
+ break;
+ case Statement.TYPE_SWITCH:
+ tailexprlst = ((SwitchStatement)stat).getHeadexprentList();
+ break;
+ case Statement.TYPE_IF:
+ tailexprlst = ((IfStatement)stat).getHeadexprentList();
+ }
+
+ for (int i = statementBreakIndex; i < statsize; i++) {
+ statEntry.statementIndex = i + 1;
+ lstStackStatements.addFirst(statEntry);
+ lstStackStatements.addFirst(
+ new StatementStackEntry(stat.getStats().get(i), stackFinally,
+ (i == 0 && tailexprlst != null && tailexprlst.get(0) != null) ? tailexprlst : null));
+
+ continue mainloop;
+ }
+
+ node = graph.nodes.getWithKey(mapDestinationNodes.get(stat.getFirst().id)[0]);
+ mapDestinationNodes.put(stat.id, new String[]{node.id, null});
+
+ if (stat.type == Statement.TYPE_IF && ((IfStatement)stat).iftype == IfStatement.IFTYPE_IF) {
+ lstSuccEdges.add(stat.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL).get(0)); // exactly one edge
+ sourcenode = tailexprlst.get(0) == null ? node : graph.nodes.getWithKey(node.id + "_tail");
+ }
+ }
+ }
+ }
+
+ // no successor edges
+ if (sourcenode != null) {
+
+ if (statEntry.succEdges != null) {
+ lstSuccEdges = statEntry.succEdges;
+ }
+
+ for (int edgeindex = statEntry.edgeIndex; edgeindex < lstSuccEdges.size(); edgeindex++) {
+
+ StatEdge edge = lstSuccEdges.get(edgeindex);
+
+ LinkedList<StackEntry> stack = new LinkedList<StackEntry>(stackFinally);
+
+ int edgetype = edge.getType();
+ Statement destination = edge.getDestination();
+
+ DirectNode finallyShortRangeSource = sourcenode;
+ DirectNode finallyLongRangeSource = sourcenode;
+ Statement finallyShortRangeEntry = null;
+ Statement finallyLongRangeEntry = null;
+
+ boolean isFinallyMonitorExceptionPath = false;
+
+ boolean isFinallyExit = false;
+
+ while (true) {
+
+ StackEntry entry = null;
+ if (!stack.isEmpty()) {
+ entry = stack.getLast();
+ }
+
+ boolean created = true;
+
+ if (entry == null) {
+ saveEdge(sourcenode, destination, edgetype, isFinallyExit ? finallyShortRangeSource : null, finallyLongRangeSource,
+ finallyShortRangeEntry, finallyLongRangeEntry, isFinallyMonitorExceptionPath);
+ }
+ else {
+
+ CatchAllStatement catchall = entry.catchstatement;
+
+ if (entry.state) { // finally handler statement
+ if (edgetype == StatEdge.TYPE_FINALLYEXIT) {
+
+ stack.removeLast();
+ destination = entry.destination;
+ edgetype = entry.edgetype;
+
+ finallyShortRangeSource = entry.finallyShortRangeSource;
+ finallyLongRangeSource = entry.finallyLongRangeSource;
+ finallyShortRangeEntry = entry.finallyShortRangeEntry;
+ finallyLongRangeEntry = entry.finallyLongRangeEntry;
+
+ isFinallyExit = true;
+ isFinallyMonitorExceptionPath = (catchall.getMonitor() != null) & entry.isFinallyExceptionPath;
+
+ created = false;
+ }
+ else {
+ if (!catchall.containsStatementStrict(destination)) {
+ stack.removeLast();
+ created = false;
+ }
+ else {
+ saveEdge(sourcenode, destination, edgetype, isFinallyExit ? finallyShortRangeSource : null, finallyLongRangeSource,
+ finallyShortRangeEntry, finallyLongRangeEntry, isFinallyMonitorExceptionPath);
+ }
+ }
+ }
+ else { // finally protected try statement
+ if (!catchall.containsStatementStrict(destination)) {
+ saveEdge(sourcenode, catchall.getHandler(), StatEdge.TYPE_REGULAR, isFinallyExit ? finallyShortRangeSource : null,
+ finallyLongRangeSource, finallyShortRangeEntry, finallyLongRangeEntry, isFinallyMonitorExceptionPath);
+
+ stack.removeLast();
+ stack.add(new StackEntry(catchall, Boolean.TRUE, edgetype, destination, catchall.getHandler(),
+ finallyLongRangeEntry == null ? catchall.getHandler() : finallyLongRangeEntry,
+ sourcenode, finallyLongRangeSource, false));
+
+ statEntry.edgeIndex = edgeindex + 1;
+ statEntry.succEdges = lstSuccEdges;
+ lstStackStatements.addFirst(statEntry);
+ lstStackStatements.addFirst(new StatementStackEntry(catchall.getHandler(), stack, null));
+
+ continue mainloop;
+ }
+ else {
+ saveEdge(sourcenode, destination, edgetype, isFinallyExit ? finallyShortRangeSource : null, finallyLongRangeSource,
+ finallyShortRangeEntry, finallyLongRangeEntry, isFinallyMonitorExceptionPath);
+ }
+ }
+ }
+
+ if (created) {
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private void saveEdge(DirectNode sourcenode,
+ Statement destination,
+ int edgetype,
+ DirectNode finallyShortRangeSource,
+ DirectNode finallyLongRangeSource,
+ Statement finallyShortRangeEntry,
+ Statement finallyLongRangeEntry,
+ boolean isFinallyMonitorExceptionPath) {
+
+ if (edgetype != StatEdge.TYPE_FINALLYEXIT) {
+ listEdges.add(new Edge(sourcenode.id, destination.id, edgetype));
+ }
+
+ if (finallyShortRangeSource != null) {
+
+ boolean isContinueEdge = (edgetype == StatEdge.TYPE_CONTINUE);
+
+ List<String[]> lst = mapShortRangeFinallyPathIds.get(sourcenode.id);
+ if (lst == null) {
+ mapShortRangeFinallyPathIds.put(sourcenode.id, lst = new ArrayList<String[]>());
+ }
+ lst.add(new String[]{finallyShortRangeSource.id, destination.id.toString(), finallyShortRangeEntry.id.toString(),
+ isFinallyMonitorExceptionPath ? "1" : null, isContinueEdge ? "1" : null});
+
+ lst = mapLongRangeFinallyPathIds.get(sourcenode.id);
+ if (lst == null) {
+ mapLongRangeFinallyPathIds.put(sourcenode.id, lst = new ArrayList<String[]>());
+ }
+ lst.add(new String[]{finallyLongRangeSource.id, destination.id.toString(), finallyLongRangeEntry.id.toString(),
+ isContinueEdge ? "1" : null});
+ }
+ }
+
+ private void setEdges() {
+
+ for (Edge edge : listEdges) {
+
+ String sourceid = edge.sourceid;
+ Integer statid = edge.statid;
+
+ DirectNode source = graph.nodes.getWithKey(sourceid);
+
+ DirectNode dest = graph.nodes.getWithKey(mapDestinationNodes.get(statid)[edge.edgetype == StatEdge.TYPE_CONTINUE ? 1 : 0]);
+
+ if (!source.succs.contains(dest)) {
+ source.succs.add(dest);
+ }
+
+ if (!dest.preds.contains(source)) {
+ dest.preds.add(source);
+ }
+
+ if (mapPosIfBranch.containsKey(sourceid) && !statid.equals(mapPosIfBranch.get(sourceid))) {
+ graph.mapNegIfBranch.put(sourceid, dest.id);
+ }
+ }
+
+ for (int i = 0; i < 2; i++) {
+ for (Entry<String, List<String[]>> ent : (i == 0 ? mapShortRangeFinallyPathIds : mapLongRangeFinallyPathIds).entrySet()) {
+
+ List<FinallyPathWrapper> newLst = new ArrayList<FinallyPathWrapper>();
+
+ List<String[]> lst = ent.getValue();
+ for (String[] arr : lst) {
+
+ boolean isContinueEdge = arr[i == 0 ? 4 : 3] != null;
+
+ DirectNode dest = graph.nodes.getWithKey(mapDestinationNodes.get(Integer.parseInt(arr[1]))[isContinueEdge ? 1 : 0]);
+ DirectNode enter = graph.nodes.getWithKey(mapDestinationNodes.get(Integer.parseInt(arr[2]))[0]);
+
+ newLst.add(new FinallyPathWrapper(arr[0], dest.id, enter.id));
+
+ if (i == 0 && arr[3] != null) {
+ graph.mapFinallyMonitorExceptionPathExits.put(ent.getKey(), dest.id);
+ }
+ }
+
+ if (!newLst.isEmpty()) {
+ (i == 0 ? graph.mapShortRangeFinallyPaths : graph.mapLongRangeFinallyPaths).put(ent.getKey(),
+ new ArrayList<FinallyPathWrapper>(
+ new HashSet<FinallyPathWrapper>(newLst)));
+ }
+ }
+ }
+ }
+
+ public Map<Integer, String[]> getMapDestinationNodes() {
+ return mapDestinationNodes;
+ }
+
+ public static class FinallyPathWrapper {
+ public String source;
+ public String destination;
+ public String entry;
+
+ private FinallyPathWrapper(String source, String destination, String entry) {
+ this.source = source;
+ this.destination = destination;
+ this.entry = entry;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof FinallyPathWrapper)) return false;
+
+ FinallyPathWrapper fpw = (FinallyPathWrapper)o;
+ return (source + ":" + destination + ":" + entry).equals(fpw.source + ":" + fpw.destination + ":" + fpw.entry);
+ }
+
+ @Override
+ public int hashCode() {
+ return (source + ":" + destination + ":" + entry).hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return source + "->(" + entry + ")->" + destination;
+ }
+ }
+
+
+ private static class StackEntry {
+
+ public CatchAllStatement catchstatement;
+ public boolean state;
+ public int edgetype;
+ public boolean isFinallyExceptionPath;
+
+ public Statement destination;
+ public Statement finallyShortRangeEntry;
+ public Statement finallyLongRangeEntry;
+ public DirectNode finallyShortRangeSource;
+ public DirectNode finallyLongRangeSource;
+
+ public StackEntry(CatchAllStatement catchstatement,
+ boolean state,
+ int edgetype,
+ Statement destination,
+ Statement finallyShortRangeEntry,
+ Statement finallyLongRangeEntry,
+ DirectNode finallyShortRangeSource,
+ DirectNode finallyLongRangeSource,
+ boolean isFinallyExceptionPath) {
+
+ this.catchstatement = catchstatement;
+ this.state = state;
+ this.edgetype = edgetype;
+ this.isFinallyExceptionPath = isFinallyExceptionPath;
+
+ this.destination = destination;
+ this.finallyShortRangeEntry = finallyShortRangeEntry;
+ this.finallyLongRangeEntry = finallyLongRangeEntry;
+ this.finallyShortRangeSource = finallyShortRangeSource;
+ this.finallyLongRangeSource = finallyLongRangeSource;
+ }
+
+ public StackEntry(CatchAllStatement catchstatement, boolean state) {
+ this(catchstatement, state, -1, null, null, null, null, null, false);
+ }
+ }
+
+ private static class Edge {
+ public String sourceid;
+ public Integer statid;
+ public int edgetype;
+
+ public Edge(String sourceid, Integer statid, int edgetype) {
+ this.sourceid = sourceid;
+ this.statid = statid;
+ this.edgetype = edgetype;
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAConstructorSparseEx.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAConstructorSparseEx.java
new file mode 100644
index 000000000000..dbec7937c77a
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAConstructorSparseEx.java
@@ -0,0 +1,529 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.sforms;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.AssignmentExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.FunctionExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.sforms.FlattenStatementsHelper.FinallyPathWrapper;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.CatchAllStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.CatchStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar;
+import org.jetbrains.java.decompiler.struct.StructMethod;
+import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
+import org.jetbrains.java.decompiler.util.FastSparseSetFactory;
+import org.jetbrains.java.decompiler.util.FastSparseSetFactory.FastSparseSet;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import org.jetbrains.java.decompiler.util.SFormsFastMapDirect;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map.Entry;
+
+public class SSAConstructorSparseEx {
+
+ // node id, var, version
+ private HashMap<String, SFormsFastMapDirect> inVarVersions = new HashMap<String, SFormsFastMapDirect>();
+
+ // node id, var, version (direct branch)
+ private HashMap<String, SFormsFastMapDirect> outVarVersions = new HashMap<String, SFormsFastMapDirect>();
+
+ // node id, var, version (negative branch)
+ private HashMap<String, SFormsFastMapDirect> outNegVarVersions = new HashMap<String, SFormsFastMapDirect>();
+
+ // node id, var, version
+ private HashMap<String, SFormsFastMapDirect> extraVarVersions = new HashMap<String, SFormsFastMapDirect>();
+
+ // (var, version), version
+ private HashMap<VarVersionPaar, FastSparseSet<Integer>> phi = new HashMap<VarVersionPaar, FastSparseSet<Integer>>();
+
+ // var, version
+ private HashMap<Integer, Integer> lastversion = new HashMap<Integer, Integer>();
+
+ private List<VarVersionPaar> startVars = new ArrayList<VarVersionPaar>();
+
+ // set factory
+ private FastSparseSetFactory<Integer> factory;
+
+ public void splitVariables(RootStatement root, StructMethod mt) {
+
+ FlattenStatementsHelper flatthelper = new FlattenStatementsHelper();
+ DirectGraph dgraph = flatthelper.buildDirectGraph(root);
+
+ // try {
+ // DotExporter.toDotFile(dgraph, new File("c:\\Temp\\gr12_my.dot"));
+ // } catch(Exception ex) {ex.printStackTrace();}
+
+ HashSet<Integer> setInit = new HashSet<Integer>();
+ for (int i = 0; i < 64; i++) {
+ setInit.add(i);
+ }
+ factory = new FastSparseSetFactory<Integer>(setInit);
+
+ SFormsFastMapDirect firstmap = createFirstMap(mt);
+ extraVarVersions.put(dgraph.first.id, firstmap);
+
+ setCatchMaps(root, dgraph, flatthelper);
+
+ HashSet<String> updated = new HashSet<String>();
+ do {
+ // System.out.println("~~~~~~~~~~~~~ \r\n"+root.toJava());
+ ssaStatements(dgraph, updated);
+ // System.out.println("~~~~~~~~~~~~~ \r\n"+root.toJava());
+ }
+ while (!updated.isEmpty());
+ }
+
+ private void ssaStatements(DirectGraph dgraph, HashSet<String> updated) {
+
+ // try {
+ // DotExporter.toDotFile(dgraph, new File("c:\\Temp\\gr1_my.dot"));
+ // } catch(Exception ex) {ex.printStackTrace();}
+
+ for (DirectNode node : dgraph.nodes) {
+
+ // if (node.id.endsWith("_inc")) {
+ // System.out.println();
+ //
+ // try {
+ // DotExporter.toDotFile(dgraph, new File("c:\\Temp\\gr1_my.dot"));
+ // } catch (Exception ex) {
+ // ex.printStackTrace();
+ // }
+ // }
+
+ updated.remove(node.id);
+ mergeInVarMaps(node, dgraph);
+
+ SFormsFastMapDirect varmap = inVarVersions.get(node.id);
+ varmap = new SFormsFastMapDirect(varmap);
+
+ SFormsFastMapDirect[] varmaparr = new SFormsFastMapDirect[]{varmap, null};
+
+ if (node.exprents != null) {
+ for (Exprent expr : node.exprents) {
+ processExprent(expr, varmaparr);
+ }
+ }
+
+ if (varmaparr[1] == null) {
+ varmaparr[1] = varmaparr[0];
+ }
+
+ boolean this_updated = !mapsEqual(varmaparr[0], outVarVersions.get(node.id))
+ || (outNegVarVersions.containsKey(node.id) && !mapsEqual(varmaparr[1], outNegVarVersions.get(node.id)));
+
+ if (this_updated) {
+ outVarVersions.put(node.id, varmaparr[0]);
+ if (dgraph.mapNegIfBranch.containsKey(node.id)) {
+ outNegVarVersions.put(node.id, varmaparr[1]);
+ }
+
+ for (DirectNode nd : node.succs) {
+ updated.add(nd.id);
+ }
+ }
+ }
+ }
+
+ private void processExprent(Exprent expr, SFormsFastMapDirect[] varmaparr) {
+
+ if (expr == null) {
+ return;
+ }
+
+ VarExprent varassign = null;
+ boolean finished = false;
+
+ switch (expr.type) {
+ case Exprent.EXPRENT_ASSIGNMENT:
+ AssignmentExprent assexpr = (AssignmentExprent)expr;
+ if (assexpr.getCondtype() == AssignmentExprent.CONDITION_NONE) {
+ Exprent dest = assexpr.getLeft();
+ if (dest.type == Exprent.EXPRENT_VAR) {
+ varassign = (VarExprent)dest;
+ }
+ }
+ break;
+ case Exprent.EXPRENT_FUNCTION:
+ FunctionExprent func = (FunctionExprent)expr;
+ switch (func.getFunctype()) {
+ case FunctionExprent.FUNCTION_IIF:
+ processExprent(func.getLstOperands().get(0), varmaparr);
+
+ SFormsFastMapDirect varmapFalse;
+ if (varmaparr[1] == null) {
+ varmapFalse = new SFormsFastMapDirect(varmaparr[0]);
+ }
+ else {
+ varmapFalse = varmaparr[1];
+ varmaparr[1] = null;
+ }
+
+ processExprent(func.getLstOperands().get(1), varmaparr);
+
+ SFormsFastMapDirect[] varmaparrNeg = new SFormsFastMapDirect[]{varmapFalse, null};
+ processExprent(func.getLstOperands().get(2), varmaparrNeg);
+
+ mergeMaps(varmaparr[0], varmaparrNeg[0]);
+ varmaparr[1] = null;
+
+ finished = true;
+ break;
+ case FunctionExprent.FUNCTION_CADD:
+ processExprent(func.getLstOperands().get(0), varmaparr);
+
+ SFormsFastMapDirect[] varmaparrAnd = new SFormsFastMapDirect[]{new SFormsFastMapDirect(varmaparr[0]), null};
+
+ processExprent(func.getLstOperands().get(1), varmaparrAnd);
+
+ // false map
+ varmaparr[1] = mergeMaps(varmaparr[varmaparr[1] == null ? 0 : 1], varmaparrAnd[varmaparrAnd[1] == null ? 0 : 1]);
+ // true map
+ varmaparr[0] = varmaparrAnd[0];
+
+ finished = true;
+ break;
+ case FunctionExprent.FUNCTION_COR:
+ processExprent(func.getLstOperands().get(0), varmaparr);
+
+ SFormsFastMapDirect[] varmaparrOr =
+ new SFormsFastMapDirect[]{new SFormsFastMapDirect(varmaparr[varmaparr[1] == null ? 0 : 1]), null};
+
+ processExprent(func.getLstOperands().get(1), varmaparrOr);
+
+ // false map
+ varmaparr[1] = varmaparrOr[varmaparrOr[1] == null ? 0 : 1];
+ // true map
+ varmaparr[0] = mergeMaps(varmaparr[0], varmaparrOr[0]);
+
+ finished = true;
+ }
+ }
+
+ if (finished) {
+ return;
+ }
+
+ List<Exprent> lst = expr.getAllExprents();
+ lst.remove(varassign);
+
+ for (Exprent ex : lst) {
+ processExprent(ex, varmaparr);
+ }
+
+ SFormsFastMapDirect varmap = varmaparr[0];
+
+ if (varassign != null) {
+
+ Integer varindex = varassign.getIndex();
+
+ if (varassign.getVersion() == 0) {
+ // get next version
+ Integer nextver = getNextFreeVersion(varindex);
+
+ // set version
+ varassign.setVersion(nextver);
+
+ setCurrentVar(varmap, varindex, nextver);
+ }
+ else {
+ setCurrentVar(varmap, varindex, varassign.getVersion());
+ }
+ }
+ else if (expr.type == Exprent.EXPRENT_VAR) {
+
+ VarExprent vardest = (VarExprent)expr;
+ Integer varindex = vardest.getIndex();
+ FastSparseSet<Integer> vers = varmap.get(varindex);
+
+ int cardinality = vers.getCardinality();
+ if (cardinality == 1) { // == 1
+ // set version
+ Integer it = vers.iterator().next();
+ vardest.setVersion(it.intValue());
+ }
+ else if (cardinality == 2) { // size > 1
+ Integer current_vers = vardest.getVersion();
+
+ VarVersionPaar currpaar = new VarVersionPaar(varindex, current_vers);
+ if (current_vers != 0 && phi.containsKey(currpaar)) {
+ setCurrentVar(varmap, varindex, current_vers);
+ // update phi node
+ phi.get(currpaar).union(vers);
+ }
+ else {
+ // increase version
+ Integer nextver = getNextFreeVersion(varindex);
+ // set version
+ vardest.setVersion(nextver);
+
+ setCurrentVar(varmap, varindex, nextver);
+ // create new phi node
+ phi.put(new VarVersionPaar(varindex, nextver), vers);
+ }
+ } // 0 means uninitialized variable, which is impossible
+ }
+ }
+
+ private Integer getNextFreeVersion(Integer var) {
+ Integer nextver = lastversion.get(var);
+ if (nextver == null) {
+ nextver = new Integer(1);
+ }
+ else {
+ nextver = new Integer(nextver.intValue() + 1);
+ }
+ lastversion.put(var, nextver);
+ return nextver;
+ }
+
+ private void mergeInVarMaps(DirectNode node, DirectGraph dgraph) {
+
+ SFormsFastMapDirect mapNew = new SFormsFastMapDirect();
+
+ for (DirectNode pred : node.preds) {
+ SFormsFastMapDirect mapOut = getFilteredOutMap(node.id, pred.id, dgraph, node.id);
+ if (mapNew.isEmpty()) {
+ mapNew = mapOut.getCopy();
+ }
+ else {
+ mergeMaps(mapNew, mapOut);
+ }
+ }
+
+ if (extraVarVersions.containsKey(node.id)) {
+ SFormsFastMapDirect mapExtra = extraVarVersions.get(node.id);
+ if (mapNew.isEmpty()) {
+ mapNew = mapExtra.getCopy();
+ }
+ else {
+ mergeMaps(mapNew, mapExtra);
+ }
+ }
+
+ inVarVersions.put(node.id, mapNew);
+ }
+
+ private SFormsFastMapDirect getFilteredOutMap(String nodeid, String predid, DirectGraph dgraph, String destid) {
+
+ SFormsFastMapDirect mapNew = new SFormsFastMapDirect();
+
+ if (nodeid.equals(dgraph.mapNegIfBranch.get(predid))) {
+ if (outNegVarVersions.containsKey(predid)) {
+ mapNew = outNegVarVersions.get(predid).getCopy();
+ }
+ }
+ else if (outVarVersions.containsKey(predid)) {
+ mapNew = outVarVersions.get(predid).getCopy();
+ }
+
+ boolean isFinallyExit = dgraph.mapShortRangeFinallyPaths.containsKey(predid);
+
+ if (isFinallyExit && !mapNew.isEmpty()) {
+
+ SFormsFastMapDirect mapNewTemp = mapNew.getCopy();
+
+ SFormsFastMapDirect mapTrueSource = new SFormsFastMapDirect();
+
+ String exceptionDest = dgraph.mapFinallyMonitorExceptionPathExits.get(predid);
+ boolean isExceptionMonitorExit = (exceptionDest != null && !nodeid.equals(exceptionDest));
+
+ HashSet<String> setLongPathWrapper = new HashSet<String>();
+ for (FinallyPathWrapper finwraplong : dgraph.mapLongRangeFinallyPaths.get(predid)) {
+ setLongPathWrapper.add(finwraplong.destination + "##" + finwraplong.source);
+ }
+
+ for (FinallyPathWrapper finwrap : dgraph.mapShortRangeFinallyPaths.get(predid)) {
+ SFormsFastMapDirect map;
+
+ boolean recFinally = dgraph.mapShortRangeFinallyPaths.containsKey(finwrap.source);
+
+ if (recFinally) {
+ // recursion
+ map = getFilteredOutMap(finwrap.entry, finwrap.source, dgraph, destid);
+ }
+ else {
+ if (finwrap.entry.equals(dgraph.mapNegIfBranch.get(finwrap.source))) {
+ map = outNegVarVersions.get(finwrap.source);
+ }
+ else {
+ map = outVarVersions.get(finwrap.source);
+ }
+ }
+
+ // false path?
+ boolean isFalsePath = true;
+
+ if (recFinally) {
+ isFalsePath = !finwrap.destination.equals(nodeid);
+ }
+ else {
+ isFalsePath = !setLongPathWrapper.contains(destid + "##" + finwrap.source);
+ }
+
+ if (isFalsePath) {
+ mapNewTemp.complement(map);
+ }
+ else {
+ if (mapTrueSource.isEmpty()) {
+ if (map != null) {
+ mapTrueSource = map.getCopy();
+ }
+ }
+ else {
+ mergeMaps(mapTrueSource, map);
+ }
+ }
+ }
+
+ if (isExceptionMonitorExit) {
+
+ mapNew = mapTrueSource;
+ }
+ else {
+
+ mapNewTemp.union(mapTrueSource);
+
+ SFormsFastMapDirect oldInMap = inVarVersions.get(nodeid);
+ if (oldInMap != null) {
+ mapNewTemp.union(oldInMap);
+ }
+
+ mapNew.intersection(mapNewTemp);
+ }
+ }
+
+ return mapNew;
+ }
+
+ private static SFormsFastMapDirect mergeMaps(SFormsFastMapDirect mapTo, SFormsFastMapDirect map2) {
+
+ if (map2 != null && !map2.isEmpty()) {
+ mapTo.union(map2);
+ }
+
+ return mapTo;
+ }
+
+ private static boolean mapsEqual(SFormsFastMapDirect map1, SFormsFastMapDirect map2) {
+
+ if (map1 == null) {
+ return map2 == null;
+ }
+ else if (map2 == null) {
+ return false;
+ }
+
+ if (map1.size() != map2.size()) {
+ return false;
+ }
+
+ for (Entry<Integer, FastSparseSet<Integer>> ent2 : map2.entryList()) {
+ if (!InterpreterUtil.equalObjects(map1.get(ent2.getKey()), ent2.getValue())) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private void setCurrentVar(SFormsFastMapDirect varmap, Integer var, Integer vers) {
+ FastSparseSet<Integer> set = factory.spawnEmptySet();
+ set.add(vers);
+ varmap.put(var, set);
+ }
+
+ private void setCatchMaps(Statement stat, DirectGraph dgraph, FlattenStatementsHelper flatthelper) {
+
+ SFormsFastMapDirect map;
+
+ switch (stat.type) {
+ case Statement.TYPE_CATCHALL:
+ case Statement.TYPE_TRYCATCH:
+
+ List<VarExprent> lstVars;
+ if (stat.type == Statement.TYPE_CATCHALL) {
+ lstVars = ((CatchAllStatement)stat).getVars();
+ }
+ else {
+ lstVars = ((CatchStatement)stat).getVars();
+ }
+
+ for (int i = 1; i < stat.getStats().size(); i++) {
+ int varindex = lstVars.get(i - 1).getIndex();
+ int version = getNextFreeVersion(varindex); // == 1
+
+ map = new SFormsFastMapDirect();
+ setCurrentVar(map, varindex, version);
+
+ extraVarVersions.put(dgraph.nodes.getWithKey(flatthelper.getMapDestinationNodes().get(stat.getStats().get(i).id)[0]).id, map);
+ startVars.add(new VarVersionPaar(varindex, version));
+ }
+ }
+
+ for (Statement st : stat.getStats()) {
+ setCatchMaps(st, dgraph, flatthelper);
+ }
+ }
+
+ private SFormsFastMapDirect createFirstMap(StructMethod mt) {
+ boolean thisvar = !mt.hasModifier(CodeConstants.ACC_STATIC);
+
+ MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
+
+ int paramcount = md.params.length + (thisvar ? 1 : 0);
+
+ int varindex = 0;
+ SFormsFastMapDirect map = new SFormsFastMapDirect();
+ for (int i = 0; i < paramcount; i++) {
+ int version = getNextFreeVersion(varindex); // == 1
+
+ FastSparseSet<Integer> set = factory.spawnEmptySet();
+ set.add(version);
+ map.put(varindex, set);
+ startVars.add(new VarVersionPaar(varindex, version));
+
+ if (thisvar) {
+ if (i == 0) {
+ varindex++;
+ }
+ else {
+ varindex += md.params[i - 1].stack_size;
+ }
+ }
+ else {
+ varindex += md.params[i].stack_size;
+ }
+ }
+
+ return map;
+ }
+
+ public HashMap<VarVersionPaar, FastSparseSet<Integer>> getPhi() {
+ return phi;
+ }
+
+ public List<VarVersionPaar> getStartVars() {
+ return startVars;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAUConstructorSparseEx.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAUConstructorSparseEx.java
new file mode 100644
index 000000000000..fbd652cd442c
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/sforms/SSAUConstructorSparseEx.java
@@ -0,0 +1,844 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.sforms;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
+import org.jetbrains.java.decompiler.modules.decompiler.sforms.FlattenStatementsHelper.FinallyPathWrapper;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.*;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionEdge;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionNode;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionPaar;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarVersionsGraph;
+import org.jetbrains.java.decompiler.struct.StructMethod;
+import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
+import org.jetbrains.java.decompiler.util.FastSparseSetFactory;
+import org.jetbrains.java.decompiler.util.FastSparseSetFactory.FastSparseSet;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import org.jetbrains.java.decompiler.util.SFormsFastMapDirect;
+import org.jetbrains.java.decompiler.util.VBStyleCollection;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map.Entry;
+
+public class SSAUConstructorSparseEx {
+
+ // node id, var, version
+ private HashMap<String, SFormsFastMapDirect> inVarVersions = new HashMap<String, SFormsFastMapDirect>();
+ //private HashMap<String, HashMap<Integer, FastSet<Integer>>> inVarVersions = new HashMap<String, HashMap<Integer, FastSet<Integer>>>();
+
+ // node id, var, version (direct branch)
+ private HashMap<String, SFormsFastMapDirect> outVarVersions = new HashMap<String, SFormsFastMapDirect>();
+ //private HashMap<String, HashMap<Integer, FastSet<Integer>>> outVarVersions = new HashMap<String, HashMap<Integer, FastSet<Integer>>>();
+
+ // node id, var, version (negative branch)
+ private HashMap<String, SFormsFastMapDirect> outNegVarVersions = new HashMap<String, SFormsFastMapDirect>();
+ //private HashMap<String, HashMap<Integer, FastSet<Integer>>> outNegVarVersions = new HashMap<String, HashMap<Integer, FastSet<Integer>>>();
+
+ // node id, var, version
+ private HashMap<String, SFormsFastMapDirect> extraVarVersions = new HashMap<String, SFormsFastMapDirect>();
+ //private HashMap<String, HashMap<Integer, FastSet<Integer>>> extraVarVersions = new HashMap<String, HashMap<Integer, FastSet<Integer>>>();
+
+ // (var, version), version
+ private HashMap<VarVersionPaar, HashSet<Integer>> phi = new HashMap<VarVersionPaar, HashSet<Integer>>();
+
+ // var, version
+ private HashMap<Integer, Integer> lastversion = new HashMap<Integer, Integer>();
+
+ // version, protected ranges (catch, finally)
+ private HashMap<VarVersionPaar, Integer> mapVersionFirstRange = new HashMap<VarVersionPaar, Integer>();
+
+ // version, version
+ private HashMap<VarVersionPaar, VarVersionPaar> phantomppnodes = new HashMap<VarVersionPaar, VarVersionPaar>(); // ++ and --
+
+ // node.id, version, version
+ private HashMap<String, HashMap<VarVersionPaar, VarVersionPaar>> phantomexitnodes =
+ new HashMap<String, HashMap<VarVersionPaar, VarVersionPaar>>(); // finally exits
+
+ // versions memory dependencies
+ private VarVersionsGraph ssuversions = new VarVersionsGraph();
+
+ // field access vars (exprent id, var id)
+ private HashMap<Integer, Integer> mapFieldVars = new HashMap<Integer, Integer>();
+
+ // field access counter
+ private int fieldvarcounter = -1;
+
+ // set factory
+ private FastSparseSetFactory<Integer> factory;
+
+ public void splitVariables(RootStatement root, StructMethod mt) {
+
+ FlattenStatementsHelper flatthelper = new FlattenStatementsHelper();
+ DirectGraph dgraph = flatthelper.buildDirectGraph(root);
+
+ HashSet<Integer> setInit = new HashSet<Integer>();
+ for (int i = 0; i < 64; i++) {
+ setInit.add(i);
+ }
+ factory = new FastSparseSetFactory<Integer>(setInit);
+
+ extraVarVersions.put(dgraph.first.id, createFirstMap(mt, root));
+
+ setCatchMaps(root, dgraph, flatthelper);
+
+ // try {
+ // DotExporter.toDotFile(dgraph, new File("c:\\Temp\\gr12_my.dot"));
+ // } catch(Exception ex) {ex.printStackTrace();}
+
+ HashSet<String> updated = new HashSet<String>();
+ do {
+ // System.out.println("~~~~~~~~~~~~~ \r\n"+root.toJava());
+ ssaStatements(dgraph, updated, false);
+ // System.out.println("~~~~~~~~~~~~~ \r\n"+root.toJava());
+ }
+ while (!updated.isEmpty());
+
+
+ ssaStatements(dgraph, updated, true);
+
+ ssuversions.initDominators();
+ }
+
+ private void ssaStatements(DirectGraph dgraph, HashSet<String> updated, boolean calcLiveVars) {
+
+ for (DirectNode node : dgraph.nodes) {
+
+ updated.remove(node.id);
+ mergeInVarMaps(node, dgraph);
+
+ SFormsFastMapDirect varmap = new SFormsFastMapDirect(inVarVersions.get(node.id));
+
+ SFormsFastMapDirect[] varmaparr = new SFormsFastMapDirect[]{varmap, null};
+
+ if (node.exprents != null) {
+ for (Exprent expr : node.exprents) {
+ processExprent(expr, varmaparr, node.statement, calcLiveVars);
+ }
+ }
+
+ if (varmaparr[1] == null) {
+ varmaparr[1] = varmaparr[0];
+ }
+
+ // quick solution: 'dummy' field variables should not cross basic block borders (otherwise problems e.g. with finally loops - usage without assignment in a loop)
+ // For the full solution consider adding a dummy assignment at the entry point of the method
+ boolean allow_field_propagation = node.succs.isEmpty() || (node.succs.size() == 1 && node.succs.get(0).preds.size() == 1);
+
+ if (!allow_field_propagation && varmaparr[0] != null) {
+ varmaparr[0].removeAllFields();
+ varmaparr[1].removeAllFields();
+ }
+
+ boolean this_updated = !mapsEqual(varmaparr[0], outVarVersions.get(node.id))
+ || (outNegVarVersions.containsKey(node.id) && !mapsEqual(varmaparr[1], outNegVarVersions.get(node.id)));
+
+ if (this_updated) {
+
+ outVarVersions.put(node.id, varmaparr[0]);
+ if (dgraph.mapNegIfBranch.containsKey(node.id)) {
+ outNegVarVersions.put(node.id, varmaparr[1]);
+ }
+
+ for (DirectNode nd : node.succs) {
+ updated.add(nd.id);
+ }
+ }
+ }
+ }
+
+
+ private void processExprent(Exprent expr, SFormsFastMapDirect[] varmaparr, Statement stat, boolean calcLiveVars) {
+
+ if (expr == null) {
+ return;
+ }
+
+
+ VarExprent varassign = null;
+ boolean finished = false;
+
+ switch (expr.type) {
+ case Exprent.EXPRENT_ASSIGNMENT:
+ AssignmentExprent assexpr = (AssignmentExprent)expr;
+ if (assexpr.getCondtype() == AssignmentExprent.CONDITION_NONE) {
+ Exprent dest = assexpr.getLeft();
+ if (dest.type == Exprent.EXPRENT_VAR) {
+ varassign = (VarExprent)dest;
+ }
+ }
+ break;
+ case Exprent.EXPRENT_FUNCTION:
+ FunctionExprent func = (FunctionExprent)expr;
+ switch (func.getFunctype()) {
+ case FunctionExprent.FUNCTION_IIF:
+ processExprent(func.getLstOperands().get(0), varmaparr, stat, calcLiveVars);
+
+ SFormsFastMapDirect varmapFalse;
+ if (varmaparr[1] == null) {
+ varmapFalse = new SFormsFastMapDirect(varmaparr[0]);
+ }
+ else {
+ varmapFalse = varmaparr[1];
+ varmaparr[1] = null;
+ }
+
+ processExprent(func.getLstOperands().get(1), varmaparr, stat, calcLiveVars);
+
+ SFormsFastMapDirect[] varmaparrNeg = new SFormsFastMapDirect[]{varmapFalse, null};
+ processExprent(func.getLstOperands().get(2), varmaparrNeg, stat, calcLiveVars);
+
+ mergeMaps(varmaparr[0], varmaparrNeg[0]);
+ varmaparr[1] = null;
+
+ finished = true;
+ break;
+ case FunctionExprent.FUNCTION_CADD:
+ processExprent(func.getLstOperands().get(0), varmaparr, stat, calcLiveVars);
+
+ SFormsFastMapDirect[] varmaparrAnd = new SFormsFastMapDirect[]{new SFormsFastMapDirect(varmaparr[0]), null};
+
+ processExprent(func.getLstOperands().get(1), varmaparrAnd, stat, calcLiveVars);
+
+ // false map
+ varmaparr[1] = mergeMaps(varmaparr[varmaparr[1] == null ? 0 : 1], varmaparrAnd[varmaparrAnd[1] == null ? 0 : 1]);
+ // true map
+ varmaparr[0] = varmaparrAnd[0];
+
+ finished = true;
+ break;
+ case FunctionExprent.FUNCTION_COR:
+ processExprent(func.getLstOperands().get(0), varmaparr, stat, calcLiveVars);
+
+ SFormsFastMapDirect[] varmaparrOr =
+ new SFormsFastMapDirect[]{new SFormsFastMapDirect(varmaparr[varmaparr[1] == null ? 0 : 1]), null};
+
+ processExprent(func.getLstOperands().get(1), varmaparrOr, stat, calcLiveVars);
+
+ // false map
+ varmaparr[1] = varmaparrOr[varmaparrOr[1] == null ? 0 : 1];
+ // true map
+ varmaparr[0] = mergeMaps(varmaparr[0], varmaparrOr[0]);
+
+ finished = true;
+ }
+ }
+
+ if (!finished) {
+ List<Exprent> lst = expr.getAllExprents();
+ lst.remove(varassign);
+
+ for (Exprent ex : lst) {
+ processExprent(ex, varmaparr, stat, calcLiveVars);
+ }
+ }
+
+
+ SFormsFastMapDirect varmap = varmaparr[0];
+
+ // field access
+ if (expr.type == Exprent.EXPRENT_FIELD) {
+
+ int index;
+ if (mapFieldVars.containsKey(expr.id)) {
+ index = mapFieldVars.get(expr.id);
+ }
+ else {
+ index = fieldvarcounter--;
+ mapFieldVars.put(expr.id, index);
+
+ // ssu graph
+ ssuversions.createNode(new VarVersionPaar(index, 1));
+ }
+
+ setCurrentVar(varmap, index, 1);
+ }
+ else if (expr.type == Exprent.EXPRENT_INVOCATION ||
+ (expr.type == Exprent.EXPRENT_ASSIGNMENT && ((AssignmentExprent)expr).getLeft().type == Exprent.EXPRENT_FIELD) ||
+ (expr.type == Exprent.EXPRENT_NEW && ((NewExprent)expr).getNewtype().type == CodeConstants.TYPE_OBJECT) ||
+ expr.type == Exprent.EXPRENT_FUNCTION) {
+
+ boolean ismmpp = true;
+
+ if (expr.type == Exprent.EXPRENT_FUNCTION) {
+
+ ismmpp = false;
+
+ FunctionExprent fexpr = (FunctionExprent)expr;
+ if (fexpr.getFunctype() >= FunctionExprent.FUNCTION_IMM && fexpr.getFunctype() <= FunctionExprent.FUNCTION_PPI) {
+ if (fexpr.getLstOperands().get(0).type == Exprent.EXPRENT_FIELD) {
+ ismmpp = true;
+ }
+ }
+ }
+
+ if (ismmpp) {
+ varmap.removeAllFields();
+ }
+ }
+
+
+ if (varassign != null) {
+
+ Integer varindex = varassign.getIndex();
+
+ if (varassign.getVersion() == 0) {
+ // get next version
+ Integer nextver = getNextFreeVersion(varindex, stat);
+
+ // set version
+ varassign.setVersion(nextver);
+
+ // ssu graph
+ ssuversions.createNode(new VarVersionPaar(varindex, nextver));
+
+ setCurrentVar(varmap, varindex, nextver);
+ }
+ else {
+ if (calcLiveVars) {
+ varMapToGraph(new VarVersionPaar(varindex.intValue(), varassign.getVersion()), varmap);
+ }
+ setCurrentVar(varmap, varindex, varassign.getVersion());
+ }
+ }
+ else if (expr.type == Exprent.EXPRENT_FUNCTION) { // MM or PP function
+ FunctionExprent func = (FunctionExprent)expr;
+
+ switch (func.getFunctype()) {
+ case FunctionExprent.FUNCTION_IMM:
+ case FunctionExprent.FUNCTION_MMI:
+ case FunctionExprent.FUNCTION_IPP:
+ case FunctionExprent.FUNCTION_PPI:
+
+ if (func.getLstOperands().get(0).type == Exprent.EXPRENT_VAR) {
+ VarExprent var = (VarExprent)func.getLstOperands().get(0);
+ Integer varindex = var.getIndex();
+ VarVersionPaar varpaar = new VarVersionPaar(varindex.intValue(), var.getVersion());
+
+ // ssu graph
+ VarVersionPaar phantomver = phantomppnodes.get(varpaar);
+ if (phantomver == null) {
+ // get next version
+ Integer nextver = getNextFreeVersion(varindex, null);
+ phantomver = new VarVersionPaar(varindex, nextver);
+ //ssuversions.createOrGetNode(phantomver);
+ ssuversions.createNode(phantomver);
+
+ VarVersionNode vernode = ssuversions.nodes.getWithKey(varpaar);
+
+ FastSparseSet<Integer> vers = factory.spawnEmptySet();
+ if (vernode.preds.size() == 1) {
+ vers.add(vernode.preds.iterator().next().source.version);
+ }
+ else {
+ for (VarVersionEdge edge : vernode.preds) {
+ vers.add(edge.source.preds.iterator().next().source.version);
+ }
+ }
+ vers.add(nextver);
+ createOrUpdatePhiNode(varpaar, vers, stat);
+ phantomppnodes.put(varpaar, phantomver);
+ }
+ if (calcLiveVars) {
+ varMapToGraph(varpaar, varmap);
+ }
+ setCurrentVar(varmap, varindex.intValue(), var.getVersion());
+ }
+ }
+ }
+ else if (expr.type == Exprent.EXPRENT_VAR) {
+
+ VarExprent vardest = (VarExprent)expr;
+
+ Integer varindex = vardest.getIndex();
+ Integer current_vers = vardest.getVersion();
+
+ FastSparseSet<Integer> vers = varmap.get(varindex);
+
+ int cardinality = vers.getCardinality();
+ if (cardinality == 1) { // size == 1
+ if (current_vers.intValue() != 0) {
+ if (calcLiveVars) {
+ varMapToGraph(new VarVersionPaar(varindex, current_vers), varmap);
+ }
+ setCurrentVar(varmap, varindex, current_vers);
+ }
+ else {
+ // split last version
+ Integer usever = getNextFreeVersion(varindex, stat);
+
+ // set version
+ vardest.setVersion(usever);
+ setCurrentVar(varmap, varindex, usever);
+
+ // ssu graph
+ Integer lastver = vers.iterator().next();
+ VarVersionNode prenode = ssuversions.nodes.getWithKey(new VarVersionPaar(varindex, lastver));
+ VarVersionNode usenode = ssuversions.createNode(new VarVersionPaar(varindex, usever));
+ VarVersionEdge edge = new VarVersionEdge(VarVersionEdge.EDGE_GENERAL, prenode, usenode);
+ prenode.addSuccessor(edge);
+ usenode.addPredecessor(edge);
+ }
+ }
+ else if (cardinality == 2) { // size > 1
+
+ if (current_vers.intValue() != 0) {
+ if (calcLiveVars) {
+ varMapToGraph(new VarVersionPaar(varindex, current_vers), varmap);
+ }
+ setCurrentVar(varmap, varindex, current_vers);
+ }
+ else {
+ // split version
+ Integer usever = getNextFreeVersion(varindex, stat);
+ // set version
+ vardest.setVersion(usever);
+
+ // ssu node
+ ssuversions.createNode(new VarVersionPaar(varindex, usever));
+
+ setCurrentVar(varmap, varindex, usever);
+
+ current_vers = usever;
+ }
+
+ createOrUpdatePhiNode(new VarVersionPaar(varindex, current_vers), vers, stat);
+ } // vers.size() == 0 means uninitialized variable, which is impossible
+ }
+ }
+
+ private void createOrUpdatePhiNode(VarVersionPaar phivar, FastSparseSet<Integer> vers, Statement stat) {
+
+ FastSparseSet<Integer> versCopy = vers.getCopy();
+ HashSet<Integer> phiVers = new HashSet<Integer>();
+
+ // take into account the corresponding mm/pp node if existing
+ int ppvers = phantomppnodes.containsKey(phivar) ? phantomppnodes.get(phivar).version : -1;
+
+ // ssu graph
+ VarVersionNode phinode = ssuversions.nodes.getWithKey(phivar);
+ List<VarVersionEdge> lstPreds = new ArrayList<VarVersionEdge>(phinode.preds);
+ if (lstPreds.size() == 1) {
+ // not yet a phi node
+ VarVersionEdge edge = lstPreds.get(0);
+ edge.source.removeSuccessor(edge);
+ phinode.removePredecessor(edge);
+ }
+ else {
+ for (VarVersionEdge edge : lstPreds) {
+ int verssrc = edge.source.preds.iterator().next().source.version;
+ if (!vers.contains(verssrc) && verssrc != ppvers) {
+ edge.source.removeSuccessor(edge);
+ phinode.removePredecessor(edge);
+ }
+ else {
+ versCopy.remove(verssrc);
+ phiVers.add(verssrc);
+ }
+ }
+ }
+
+ List<VarVersionNode> colnodes = new ArrayList<VarVersionNode>();
+ List<VarVersionPaar> colpaars = new ArrayList<VarVersionPaar>();
+
+ for (Integer ver : versCopy) {
+
+ VarVersionNode prenode = ssuversions.nodes.getWithKey(new VarVersionPaar(phivar.var, ver.intValue()));
+
+ Integer tempver = getNextFreeVersion(phivar.var, stat);
+
+ VarVersionNode tempnode = new VarVersionNode(phivar.var, tempver.intValue());
+
+ colnodes.add(tempnode);
+ colpaars.add(new VarVersionPaar(phivar.var, tempver.intValue()));
+
+ VarVersionEdge edge = new VarVersionEdge(VarVersionEdge.EDGE_GENERAL, prenode, tempnode);
+
+ prenode.addSuccessor(edge);
+ tempnode.addPredecessor(edge);
+
+
+ edge = new VarVersionEdge(VarVersionEdge.EDGE_GENERAL, tempnode, phinode);
+ tempnode.addSuccessor(edge);
+ phinode.addPredecessor(edge);
+
+ phiVers.add(tempver);
+ }
+
+ ssuversions.addNodes(colnodes, colpaars);
+
+ // update phi node
+ phi.put(phivar, phiVers);
+ }
+
+ private void varMapToGraph(VarVersionPaar varpaar, SFormsFastMapDirect varmap) {
+
+ VBStyleCollection<VarVersionNode, VarVersionPaar> nodes = ssuversions.nodes;
+
+ VarVersionNode node = nodes.getWithKey(varpaar);
+
+ node.live = new SFormsFastMapDirect(varmap);
+ }
+
+ private Integer getNextFreeVersion(Integer var, Statement stat) {
+
+ Integer nextver = lastversion.get(var);
+
+ if (nextver == null) {
+ nextver = new Integer(1);
+ }
+ else {
+ nextver = new Integer(nextver.intValue() + 1);
+ }
+ lastversion.put(var, nextver);
+
+ // save the first protected range, containing current statement
+ if (stat != null) { // null iff phantom version
+ Integer firstRangeId = getFirstProtectedRange(stat);
+ if (firstRangeId != null) {
+ mapVersionFirstRange.put(new VarVersionPaar(var, nextver), firstRangeId);
+ }
+ }
+
+ return nextver;
+ }
+
+ private void mergeInVarMaps(DirectNode node, DirectGraph dgraph) {
+
+
+ SFormsFastMapDirect mapNew = new SFormsFastMapDirect();
+
+ for (DirectNode pred : node.preds) {
+ SFormsFastMapDirect mapOut = getFilteredOutMap(node.id, pred.id, dgraph, node.id);
+ if (mapNew.isEmpty()) {
+ mapNew = mapOut.getCopy();
+ }
+ else {
+ mergeMaps(mapNew, mapOut);
+ }
+ }
+
+ if (extraVarVersions.containsKey(node.id)) {
+ SFormsFastMapDirect mapExtra = extraVarVersions.get(node.id);
+ if (mapNew.isEmpty()) {
+ mapNew = mapExtra.getCopy();
+ }
+ else {
+ mergeMaps(mapNew, mapExtra);
+ }
+ }
+
+ inVarVersions.put(node.id, mapNew);
+ }
+
+ private SFormsFastMapDirect getFilteredOutMap(String nodeid, String predid, DirectGraph dgraph, String destid) {
+
+ SFormsFastMapDirect mapNew = new SFormsFastMapDirect();
+
+ boolean isFinallyExit = dgraph.mapShortRangeFinallyPaths.containsKey(predid);
+
+ if (nodeid.equals(dgraph.mapNegIfBranch.get(predid))) {
+ if (outNegVarVersions.containsKey(predid)) {
+ mapNew = outNegVarVersions.get(predid).getCopy();
+ }
+ }
+ else if (outVarVersions.containsKey(predid)) {
+ mapNew = outVarVersions.get(predid).getCopy();
+ }
+
+ if (isFinallyExit) {
+
+ SFormsFastMapDirect mapNewTemp = mapNew.getCopy();
+
+ SFormsFastMapDirect mapTrueSource = new SFormsFastMapDirect();
+
+ String exceptionDest = dgraph.mapFinallyMonitorExceptionPathExits.get(predid);
+ boolean isExceptionMonitorExit = (exceptionDest != null && !nodeid.equals(exceptionDest));
+
+ HashSet<String> setLongPathWrapper = new HashSet<String>();
+ for (List<FinallyPathWrapper> lstwrapper : dgraph.mapLongRangeFinallyPaths.values()) {
+ for (FinallyPathWrapper finwraplong : lstwrapper) {
+ setLongPathWrapper.add(finwraplong.destination + "##" + finwraplong.source);
+ }
+ }
+
+ for (FinallyPathWrapper finwrap : dgraph.mapShortRangeFinallyPaths.get(predid)) {
+ SFormsFastMapDirect map;
+
+ boolean recFinally = dgraph.mapShortRangeFinallyPaths.containsKey(finwrap.source);
+
+ if (recFinally) {
+ // recursion
+ map = getFilteredOutMap(finwrap.entry, finwrap.source, dgraph, destid);
+ }
+ else {
+ if (finwrap.entry.equals(dgraph.mapNegIfBranch.get(finwrap.source))) {
+ map = outNegVarVersions.get(finwrap.source);
+ }
+ else {
+ map = outVarVersions.get(finwrap.source);
+ }
+ }
+
+ // false path?
+ boolean isFalsePath = true;
+
+ if (recFinally) {
+ isFalsePath = !finwrap.destination.equals(nodeid);
+ }
+ else {
+ isFalsePath = !setLongPathWrapper.contains(destid + "##" + finwrap.source);
+ }
+
+ if (isFalsePath) {
+ mapNewTemp.complement(map);
+ }
+ else {
+ if (mapTrueSource.isEmpty()) {
+ if (map != null) {
+ mapTrueSource = map.getCopy();
+ }
+ }
+ else {
+ mergeMaps(mapTrueSource, map);
+ }
+ }
+ }
+
+ if (isExceptionMonitorExit) {
+
+ mapNew = mapTrueSource;
+ }
+ else {
+
+ mapNewTemp.union(mapTrueSource);
+ mapNew.intersection(mapNewTemp);
+
+ if (!mapTrueSource.isEmpty() && !mapNew.isEmpty()) { // FIXME: what for??
+
+ // replace phi versions with corresponding phantom ones
+ HashMap<VarVersionPaar, VarVersionPaar> mapPhantom = phantomexitnodes.get(predid);
+ if (mapPhantom == null) {
+ mapPhantom = new HashMap<VarVersionPaar, VarVersionPaar>();
+ }
+
+ SFormsFastMapDirect mapExitVar = mapNew.getCopy();
+ mapExitVar.complement(mapTrueSource);
+
+ for (Entry<Integer, FastSparseSet<Integer>> ent : mapExitVar.entryList()) {
+ for (Integer version : ent.getValue()) {
+
+ Integer varindex = ent.getKey();
+ VarVersionPaar exitvar = new VarVersionPaar(varindex, version);
+ FastSparseSet<Integer> newSet = mapNew.get(varindex);
+
+ // remove the actual exit version
+ newSet.remove(version);
+
+ // get or create phantom version
+ VarVersionPaar phantomvar = mapPhantom.get(exitvar);
+ if (phantomvar == null) {
+ Integer newversion = getNextFreeVersion(exitvar.var, null);
+ phantomvar = new VarVersionPaar(exitvar.var, newversion.intValue());
+
+ VarVersionNode exitnode = ssuversions.nodes.getWithKey(exitvar);
+ VarVersionNode phantomnode = ssuversions.createNode(phantomvar);
+ phantomnode.flags |= VarVersionNode.FLAG_PHANTOM_FINEXIT;
+
+ VarVersionEdge edge = new VarVersionEdge(VarVersionEdge.EDGE_PHANTOM, exitnode, phantomnode);
+ exitnode.addSuccessor(edge);
+ phantomnode.addPredecessor(edge);
+
+ mapPhantom.put(exitvar, phantomvar);
+ }
+
+ // add phantom version
+ newSet.add(phantomvar.version);
+ }
+ }
+
+ if (!mapPhantom.isEmpty()) {
+ phantomexitnodes.put(predid, mapPhantom);
+ }
+ }
+ }
+ }
+
+ return mapNew;
+ }
+
+ private static SFormsFastMapDirect mergeMaps(SFormsFastMapDirect mapTo, SFormsFastMapDirect map2) {
+
+ if (map2 != null && !map2.isEmpty()) {
+ mapTo.union(map2);
+ }
+
+ return mapTo;
+ }
+
+ private static boolean mapsEqual(SFormsFastMapDirect map1, SFormsFastMapDirect map2) {
+
+ if (map1 == null) {
+ return map2 == null;
+ }
+ else if (map2 == null) {
+ return false;
+ }
+
+ if (map1.size() != map2.size()) {
+ return false;
+ }
+
+ for (Entry<Integer, FastSparseSet<Integer>> ent2 : map2.entryList()) {
+ if (!InterpreterUtil.equalObjects(map1.get(ent2.getKey()), ent2.getValue())) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+
+ private void setCurrentVar(SFormsFastMapDirect varmap, Integer var, Integer vers) {
+ FastSparseSet<Integer> set = factory.spawnEmptySet();
+ set.add(vers);
+ varmap.put(var, set);
+ }
+
+ private void setCatchMaps(Statement stat, DirectGraph dgraph, FlattenStatementsHelper flatthelper) {
+
+ SFormsFastMapDirect map;
+
+ switch (stat.type) {
+ case Statement.TYPE_CATCHALL:
+ case Statement.TYPE_TRYCATCH:
+
+ List<VarExprent> lstVars;
+ if (stat.type == Statement.TYPE_CATCHALL) {
+ lstVars = ((CatchAllStatement)stat).getVars();
+ }
+ else {
+ lstVars = ((CatchStatement)stat).getVars();
+ }
+
+ for (int i = 1; i < stat.getStats().size(); i++) {
+ int varindex = lstVars.get(i - 1).getIndex();
+ int version = getNextFreeVersion(varindex, stat); // == 1
+
+ map = new SFormsFastMapDirect();
+ setCurrentVar(map, varindex, version);
+
+ extraVarVersions.put(dgraph.nodes.getWithKey(flatthelper.getMapDestinationNodes().get(stat.getStats().get(i).id)[0]).id, map);
+ //ssuversions.createOrGetNode(new VarVersionPaar(varindex, version));
+ ssuversions.createNode(new VarVersionPaar(varindex, version));
+ }
+ }
+
+ for (Statement st : stat.getStats()) {
+ setCatchMaps(st, dgraph, flatthelper);
+ }
+ }
+
+ private SFormsFastMapDirect createFirstMap(StructMethod mt, RootStatement root) {
+ boolean thisvar = !mt.hasModifier(CodeConstants.ACC_STATIC);
+
+ MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
+
+ int paramcount = md.params.length + (thisvar ? 1 : 0);
+
+ int varindex = 0;
+ SFormsFastMapDirect map = new SFormsFastMapDirect();
+ for (int i = 0; i < paramcount; i++) {
+ int version = getNextFreeVersion(varindex, root); // == 1
+
+ FastSparseSet<Integer> set = factory.spawnEmptySet();
+ set.add(version);
+ map.put(varindex, set);
+ ssuversions.createNode(new VarVersionPaar(varindex, version));
+
+ if (thisvar) {
+ if (i == 0) {
+ varindex++;
+ }
+ else {
+ varindex += md.params[i - 1].stack_size;
+ }
+ }
+ else {
+ varindex += md.params[i].stack_size;
+ }
+ }
+
+ return map;
+ }
+
+ private static Integer getFirstProtectedRange(Statement stat) {
+
+ while (true) {
+ Statement parent = stat.getParent();
+
+ if (parent == null) {
+ break;
+ }
+
+ if (parent.type == Statement.TYPE_CATCHALL ||
+ parent.type == Statement.TYPE_TRYCATCH) {
+ if (parent.getFirst() == stat) {
+ return parent.id;
+ }
+ }
+ else if (parent.type == Statement.TYPE_SYNCRONIZED) {
+ if (((SynchronizedStatement)parent).getBody() == stat) {
+ return parent.id;
+ }
+ }
+
+ stat = parent;
+ }
+
+ return null;
+ }
+
+ public HashMap<VarVersionPaar, HashSet<Integer>> getPhi() {
+ return phi;
+ }
+
+ public VarVersionsGraph getSsuversions() {
+ return ssuversions;
+ }
+
+ public SFormsFastMapDirect getLiveVarVersionsMap(VarVersionPaar varpaar) {
+
+
+ VarVersionNode node = ssuversions.nodes.getWithKey(varpaar);
+ if (node != null) {
+ return node.live;
+ }
+
+ return null;
+ }
+
+ public HashMap<VarVersionPaar, Integer> getMapVersionFirstRange() {
+ return mapVersionFirstRange;
+ }
+
+ public HashMap<Integer, Integer> getMapFieldVars() {
+ return mapFieldVars;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/BasicBlockStatement.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/BasicBlockStatement.java
new file mode 100644
index 000000000000..91c1a4e23c84
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/BasicBlockStatement.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.stats;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.code.Instruction;
+import org.jetbrains.java.decompiler.code.SimpleInstructionSequence;
+import org.jetbrains.java.decompiler.code.cfg.BasicBlock;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
+import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
+
+public class BasicBlockStatement extends Statement {
+
+ // *****************************************************************************
+ // private fields
+ // *****************************************************************************
+
+ private BasicBlock block;
+
+ // *****************************************************************************
+ // constructors
+ // *****************************************************************************
+
+ public BasicBlockStatement(BasicBlock block) {
+
+ type = Statement.TYPE_BASICBLOCK;
+
+ this.block = block;
+
+ id = block.id;
+ CounterContainer coun = DecompilerContext.getCounterContainer();
+ if (id >= coun.getCounter(CounterContainer.STATEMENT_COUNTER)) {
+ coun.setCounter(CounterContainer.STATEMENT_COUNTER, id + 1);
+ }
+
+ Instruction instr = block.getLastInstruction();
+ if (instr != null) {
+ if (instr.group == CodeConstants.GROUP_JUMP && instr.opcode != CodeConstants.opc_goto) {
+ lastBasicType = LASTBASICTYPE_IF;
+ }
+ else if (instr.group == CodeConstants.GROUP_SWITCH) {
+ lastBasicType = LASTBASICTYPE_SWITCH;
+ }
+ }
+
+ // monitorenter and monitorexits
+ buildMonitorFlags();
+ }
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public String toJava(int indent) {
+ return ExprProcessor.listToJava(varDefinitions, indent) +
+ ExprProcessor.listToJava(exprents, indent);
+ }
+
+ public Statement getSimpleCopy() {
+
+ BasicBlock newblock = new BasicBlock(
+ DecompilerContext.getCounterContainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER));
+
+ SimpleInstructionSequence seq = new SimpleInstructionSequence();
+ for (int i = 0; i < block.getSeq().length(); i++) {
+ seq.addInstruction(block.getSeq().getInstr(i).clone(), -1);
+ }
+
+ newblock.setSeq(seq);
+
+ return new BasicBlockStatement(newblock);
+ }
+
+
+ // *****************************************************************************
+ // getter and setter methods
+ // *****************************************************************************
+
+ public BasicBlock getBlock() {
+ return block;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchAllStatement.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchAllStatement.java
new file mode 100644
index 000000000000..15af3c604a2e
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchAllStatement.java
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.stats;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
+import org.jetbrains.java.decompiler.modules.decompiler.DecHelper;
+import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
+import org.jetbrains.java.decompiler.modules.decompiler.StatEdge;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor;
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+
+public class CatchAllStatement extends Statement {
+
+ private Statement handler;
+
+ private boolean isFinally;
+
+ private VarExprent monitor;
+
+ private List<VarExprent> vars = new ArrayList<VarExprent>();
+
+ // *****************************************************************************
+ // constructors
+ // *****************************************************************************
+
+ private CatchAllStatement() {
+ type = Statement.TYPE_CATCHALL;
+ }
+
+ private CatchAllStatement(Statement head, Statement handler) {
+
+ this();
+
+ first = head;
+ stats.addWithKey(head, head.id);
+
+ this.handler = handler;
+ stats.addWithKey(handler, handler.id);
+
+ List<StatEdge> lstSuccs = head.getSuccessorEdges(STATEDGE_DIRECT_ALL);
+ if (!lstSuccs.isEmpty()) {
+ StatEdge edge = lstSuccs.get(0);
+ if (edge.getType() == StatEdge.TYPE_REGULAR) {
+ post = edge.getDestination();
+ }
+ }
+
+ vars.add(new VarExprent(DecompilerContext.getCounterContainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER),
+ new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/Throwable"),
+ (VarProcessor)DecompilerContext.getProperty(DecompilerContext.CURRENT_VAR_PROCESSOR)));
+ }
+
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public static Statement isHead(Statement head) {
+
+ if (head.getLastBasicType() != Statement.LASTBASICTYPE_GENERAL) {
+ return null;
+ }
+
+ HashSet<Statement> setHandlers = DecHelper.getUniquePredExceptions(head);
+
+ if (setHandlers.size() != 1) {
+ return null;
+ }
+
+ for (StatEdge edge : head.getSuccessorEdges(StatEdge.TYPE_EXCEPTION)) {
+ Statement exc = edge.getDestination();
+
+ if (edge.getExceptions() == null && setHandlers.contains(exc) && exc.getLastBasicType() == LASTBASICTYPE_GENERAL) {
+ List<StatEdge> lstSuccs = exc.getSuccessorEdges(STATEDGE_DIRECT_ALL);
+ if (lstSuccs.isEmpty() || lstSuccs.get(0).getType() != StatEdge.TYPE_REGULAR) {
+
+ if (head.isMonitorEnter() || exc.isMonitorEnter()) {
+ return null;
+ }
+
+ if (DecHelper.checkStatementExceptions(Arrays.asList(head, exc))) {
+ return new CatchAllStatement(head, exc);
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public String toJava(int indent) {
+ String indstr = InterpreterUtil.getIndentString(indent);
+ String indstr1 = null;
+
+ String new_line_separator = DecompilerContext.getNewLineSeparator();
+
+ StringBuilder buf = new StringBuilder();
+
+ buf.append(ExprProcessor.listToJava(varDefinitions, indent));
+
+ boolean labeled = isLabeled();
+ if (labeled) {
+ buf.append(indstr).append("label").append(this.id).append(":").append(new_line_separator);
+ }
+
+ List<StatEdge> lstSuccs = first.getSuccessorEdges(STATEDGE_DIRECT_ALL);
+ if (first.type == TYPE_TRYCATCH && first.varDefinitions.isEmpty() && isFinally &&
+ !labeled && !first.isLabeled() && (lstSuccs.isEmpty() || !lstSuccs.get(0).explicit)) {
+ String content = ExprProcessor.jmpWrapper(first, indent, true);
+ content = content.substring(0, content.length() - new_line_separator.length());
+
+ buf.append(content);
+ }
+ else {
+ buf.append(indstr).append("try {").append(new_line_separator);
+ buf.append(ExprProcessor.jmpWrapper(first, indent + 1, true));
+ buf.append(indstr).append("}");
+ }
+
+ buf.append(isFinally ? " finally" :
+ " catch (" + vars.get(0).toJava(indent) + ")").append(" {").append(new_line_separator);
+
+ if (monitor != null) {
+ indstr1 = InterpreterUtil.getIndentString(indent + 1);
+ buf.append(indstr1).append("if(").append(monitor.toJava(indent)).append(") {").append(new_line_separator);
+ }
+
+ buf.append(ExprProcessor.jmpWrapper(handler, indent + 1 + (monitor != null ? 1 : 0), true));
+
+ if (monitor != null) {
+ buf.append(indstr1).append("}").append(new_line_separator);
+ }
+
+ buf.append(indstr).append("}").append(new_line_separator);
+
+ return buf.toString();
+ }
+
+ public void replaceStatement(Statement oldstat, Statement newstat) {
+
+ if (handler == oldstat) {
+ handler = newstat;
+ }
+
+ super.replaceStatement(oldstat, newstat);
+ }
+
+ public Statement getSimpleCopy() {
+
+ CatchAllStatement cas = new CatchAllStatement();
+
+ cas.isFinally = this.isFinally;
+
+ if (this.monitor != null) {
+ cas.monitor = new VarExprent(DecompilerContext.getCounterContainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER),
+ VarType.VARTYPE_INT,
+ (VarProcessor)DecompilerContext.getProperty(DecompilerContext.CURRENT_VAR_PROCESSOR));
+ }
+
+ if (!this.vars.isEmpty()) {
+ // FIXME: WTF??? vars?!
+ vars.add(new VarExprent(DecompilerContext.getCounterContainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER),
+ new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/Throwable"),
+ (VarProcessor)DecompilerContext.getProperty(DecompilerContext.CURRENT_VAR_PROCESSOR)));
+ }
+
+ return cas;
+ }
+
+ public void initSimpleCopy() {
+ first = stats.get(0);
+ handler = stats.get(1);
+ }
+
+ // *****************************************************************************
+ // getter and setter methods
+ // *****************************************************************************
+
+ public Statement getHandler() {
+ return handler;
+ }
+
+
+ public void setHandler(Statement handler) {
+ this.handler = handler;
+ }
+
+
+ public boolean isFinally() {
+ return isFinally;
+ }
+
+
+ public void setFinally(boolean isFinally) {
+ this.isFinally = isFinally;
+ }
+
+
+ public VarExprent getMonitor() {
+ return monitor;
+ }
+
+
+ public void setMonitor(VarExprent monitor) {
+ this.monitor = monitor;
+ }
+
+ public List<VarExprent> getVars() {
+ return vars;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchStatement.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchStatement.java
new file mode 100644
index 000000000000..ea45bdda75d7
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/CatchStatement.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.stats;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
+import org.jetbrains.java.decompiler.modules.decompiler.DecHelper;
+import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
+import org.jetbrains.java.decompiler.modules.decompiler.StatEdge;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.vars.VarProcessor;
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+
+public class CatchStatement extends Statement {
+
+ private List<List<String>> exctstrings = new ArrayList<List<String>>();
+
+ private List<VarExprent> vars = new ArrayList<VarExprent>();
+
+ // *****************************************************************************
+ // constructors
+ // *****************************************************************************
+
+ private CatchStatement() {
+ type = TYPE_TRYCATCH;
+ }
+
+ private CatchStatement(Statement head, Statement next, HashSet<Statement> setHandlers) {
+
+ this();
+
+ first = head;
+ stats.addWithKey(first, first.id);
+
+ for (StatEdge edge : head.getSuccessorEdges(StatEdge.TYPE_EXCEPTION)) {
+ Statement stat = edge.getDestination();
+
+ if (setHandlers.contains(stat)) {
+ stats.addWithKey(stat, stat.id);
+ exctstrings.add(new ArrayList<String>(edge.getExceptions()));
+
+ vars.add(new VarExprent(DecompilerContext.getCounterContainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER),
+ new VarType(CodeConstants.TYPE_OBJECT, 0, edge.getExceptions().get(0)),
+ // FIXME: for now simply the first type. Should get the first common superclass when possible.
+ (VarProcessor)DecompilerContext.getProperty(DecompilerContext.CURRENT_VAR_PROCESSOR)));
+ }
+ }
+
+ if (next != null) {
+ post = next;
+ }
+ }
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public static Statement isHead(Statement head) {
+
+ if (head.getLastBasicType() != LASTBASICTYPE_GENERAL) {
+ return null;
+ }
+
+ HashSet<Statement> setHandlers = DecHelper.getUniquePredExceptions(head);
+
+ if (!setHandlers.isEmpty()) {
+
+ int hnextcount = 0; // either no statements with connection to next, or more than 1
+
+ Statement next = null;
+ List<StatEdge> lstHeadSuccs = head.getSuccessorEdges(STATEDGE_DIRECT_ALL);
+ if (!lstHeadSuccs.isEmpty() && lstHeadSuccs.get(0).getType() == StatEdge.TYPE_REGULAR) {
+ next = lstHeadSuccs.get(0).getDestination();
+ hnextcount = 2;
+ }
+
+ for (StatEdge edge : head.getSuccessorEdges(StatEdge.TYPE_EXCEPTION)) {
+ Statement stat = edge.getDestination();
+
+ boolean handlerok = true;
+
+ if (edge.getExceptions() != null && setHandlers.contains(stat)) {
+ if (stat.getLastBasicType() != LASTBASICTYPE_GENERAL) {
+ handlerok = false;
+ }
+ else {
+ List<StatEdge> lstStatSuccs = stat.getSuccessorEdges(STATEDGE_DIRECT_ALL);
+ if (!lstStatSuccs.isEmpty() && lstStatSuccs.get(0).getType() == StatEdge.TYPE_REGULAR) {
+
+ Statement statn = lstStatSuccs.get(0).getDestination();
+
+ if (next == null) {
+ next = statn;
+ }
+ else if (next != statn) {
+ handlerok = false;
+ }
+
+ if (handlerok) {
+ hnextcount++;
+ }
+ }
+ }
+ }
+ else {
+ handlerok = false;
+ }
+
+ if (!handlerok) {
+ setHandlers.remove(stat);
+ }
+ }
+
+ if (hnextcount != 1 && !setHandlers.isEmpty()) {
+ List<Statement> lst = new ArrayList<Statement>();
+ lst.add(head);
+ lst.addAll(setHandlers);
+
+ for (Statement st : lst) {
+ if (st.isMonitorEnter()) {
+ return null;
+ }
+ }
+
+ if (DecHelper.checkStatementExceptions(lst)) {
+ return new CatchStatement(head, next, setHandlers);
+ }
+ }
+ }
+ return null;
+ }
+
+ public String toJava(int indent) {
+ String indstr = InterpreterUtil.getIndentString(indent);
+ StringBuilder buf = new StringBuilder();
+
+ String new_line_separator = DecompilerContext.getNewLineSeparator();
+
+ buf.append(ExprProcessor.listToJava(varDefinitions, indent));
+
+ if (isLabeled()) {
+ buf.append(indstr).append("label").append(this.id).append(":").append(new_line_separator);
+ }
+
+ buf.append(indstr).append("try {").append(new_line_separator);
+ buf.append(ExprProcessor.jmpWrapper(first, indent + 1, true));
+ buf.append(indstr).append("}");
+
+ for (int i = 1; i < stats.size(); i++) {
+ List<String> exception_types = exctstrings.get(i - 1);
+
+ buf.append(" catch (");
+ if (exception_types.size() > 1) { // multi-catch, Java 7 style
+ for (int exc_index = 1; exc_index < exception_types.size(); ++exc_index) {
+ VarType exc_type = new VarType(CodeConstants.TYPE_OBJECT, 0, exception_types.get(exc_index));
+ String exc_type_name = ExprProcessor.getCastTypeName(exc_type);
+
+ buf.append(exc_type_name).append(" | ");
+ }
+ }
+ buf.append(vars.get(i - 1).toJava(indent));
+ buf.append(") {").append(new_line_separator).append(ExprProcessor.jmpWrapper(stats.get(i), indent + 1, true)).append(indstr)
+ .append("}");
+ }
+ buf.append(new_line_separator);
+
+ return buf.toString();
+ }
+
+ public Statement getSimpleCopy() {
+
+ CatchStatement cs = new CatchStatement();
+
+ for (List<String> exc : this.exctstrings) {
+ cs.exctstrings.add(new ArrayList<String>(exc));
+ cs.vars.add(new VarExprent(DecompilerContext.getCounterContainer().getCounterAndIncrement(CounterContainer.VAR_COUNTER),
+ new VarType(CodeConstants.TYPE_OBJECT, 0, exc.get(0)),
+ (VarProcessor)DecompilerContext.getProperty(DecompilerContext.CURRENT_VAR_PROCESSOR)));
+ }
+
+ return cs;
+ }
+
+ // *****************************************************************************
+ // getter and setter methods
+ // *****************************************************************************
+
+ public List<VarExprent> getVars() {
+ return vars;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/DoStatement.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/DoStatement.java
new file mode 100644
index 000000000000..7c152c21eb1f
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/DoStatement.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.stats;
+
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
+import org.jetbrains.java.decompiler.modules.decompiler.StatEdge;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class DoStatement extends Statement {
+
+ public static final int LOOP_DO = 0;
+ public static final int LOOP_DOWHILE = 1;
+ public static final int LOOP_WHILE = 2;
+ public static final int LOOP_FOR = 3;
+
+ private int looptype;
+
+ private List<Exprent> initExprent = new ArrayList<Exprent>();
+ private List<Exprent> conditionExprent = new ArrayList<Exprent>();
+ private List<Exprent> incExprent = new ArrayList<Exprent>();
+
+ // *****************************************************************************
+ // constructors
+ // *****************************************************************************
+
+ private DoStatement() {
+ type = Statement.TYPE_DO;
+ looptype = LOOP_DO;
+
+ initExprent.add(null);
+ conditionExprent.add(null);
+ incExprent.add(null);
+ }
+
+ private DoStatement(Statement head) {
+
+ this();
+
+ first = head;
+ stats.addWithKey(first, first.id);
+
+ // post is always null!
+ }
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public static Statement isHead(Statement head) {
+
+ if (head.getLastBasicType() == LASTBASICTYPE_GENERAL && !head.isMonitorEnter()) {
+
+ // at most one outgoing edge
+ StatEdge edge = null;
+ List<StatEdge> lstSuccs = head.getSuccessorEdges(STATEDGE_DIRECT_ALL);
+ if (!lstSuccs.isEmpty()) {
+ edge = lstSuccs.get(0);
+ }
+
+ // regular loop
+ if (edge != null && edge.getType() == StatEdge.TYPE_REGULAR && edge.getDestination() == head) {
+ return new DoStatement(head);
+ }
+
+ // continues
+ if (head.type != TYPE_DO && (edge == null || edge.getType() != StatEdge.TYPE_REGULAR) &&
+ head.getContinueSet().contains(head.getBasichead())) {
+ return new DoStatement(head);
+ }
+ }
+
+ return null;
+ }
+
+ public String toJava(int indent) {
+ String indstr = InterpreterUtil.getIndentString(indent);
+ StringBuilder buf = new StringBuilder();
+
+ String new_line_separator = DecompilerContext.getNewLineSeparator();
+
+ buf.append(ExprProcessor.listToJava(varDefinitions, indent));
+
+ if (isLabeled()) {
+ buf.append(indstr).append("label").append(this.id).append(":").append(new_line_separator);
+ }
+
+ switch (looptype) {
+ case LOOP_DO:
+ buf.append(indstr).append("while(true) {").append(new_line_separator);
+ buf.append(ExprProcessor.jmpWrapper(first, indent + 1, true));
+ buf.append(indstr).append("}").append(new_line_separator);
+ break;
+ case LOOP_DOWHILE:
+ buf.append(indstr).append("do {").append(new_line_separator);
+ buf.append(ExprProcessor.jmpWrapper(first, indent + 1, true));
+ buf.append(indstr).append("} while(").append(conditionExprent.get(0).toJava(indent)).append(");").append(new_line_separator);
+ break;
+ case LOOP_WHILE:
+ buf.append(indstr).append("while(").append(conditionExprent.get(0).toJava(indent)).append(") {").append(new_line_separator);
+ buf.append(ExprProcessor.jmpWrapper(first, indent + 1, true));
+ buf.append(indstr).append("}").append(new_line_separator);
+ break;
+ case LOOP_FOR:
+ buf.append(indstr).append("for(").append(initExprent.get(0) == null ? "" : initExprent.get(0).toJava(indent)).append("; ")
+ .append(conditionExprent.get(0).toJava(indent)).append("; ").append(incExprent.get(0).toJava(indent)).append(") {")
+ .append(new_line_separator);
+ buf.append(ExprProcessor.jmpWrapper(first, indent + 1, true));
+ buf.append(indstr).append("}").append(new_line_separator);
+ }
+
+ return buf.toString();
+ }
+
+ public List<Object> getSequentialObjects() {
+
+ List<Object> lst = new ArrayList<Object>();
+
+ switch (looptype) {
+ case LOOP_FOR:
+ if (getInitExprent() != null) {
+ lst.add(getInitExprent());
+ }
+ case LOOP_WHILE:
+ lst.add(getConditionExprent());
+ }
+
+ lst.add(first);
+
+ switch (looptype) {
+ case LOOP_DOWHILE:
+ lst.add(getConditionExprent());
+ break;
+ case LOOP_FOR:
+ lst.add(getIncExprent());
+ }
+
+ return lst;
+ }
+
+ public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
+ if (initExprent.get(0) == oldexpr) {
+ initExprent.set(0, newexpr);
+ }
+ if (conditionExprent.get(0) == oldexpr) {
+ conditionExprent.set(0, newexpr);
+ }
+ if (incExprent.get(0) == oldexpr) {
+ incExprent.set(0, newexpr);
+ }
+ }
+
+ public Statement getSimpleCopy() {
+ return new DoStatement();
+ }
+
+ // *****************************************************************************
+ // getter and setter methods
+ // *****************************************************************************
+
+ public List<Exprent> getInitExprentList() {
+ return initExprent;
+ }
+
+ public List<Exprent> getConditionExprentList() {
+ return conditionExprent;
+ }
+
+ public List<Exprent> getIncExprentList() {
+ return incExprent;
+ }
+
+ public Exprent getConditionExprent() {
+ return conditionExprent.get(0);
+ }
+
+ public void setConditionExprent(Exprent conditionExprent) {
+ this.conditionExprent.set(0, conditionExprent);
+ }
+
+ public Exprent getIncExprent() {
+ return incExprent.get(0);
+ }
+
+ public void setIncExprent(Exprent incExprent) {
+ this.incExprent.set(0, incExprent);
+ }
+
+ public Exprent getInitExprent() {
+ return initExprent.get(0);
+ }
+
+ public void setInitExprent(Exprent initExprent) {
+ this.initExprent.set(0, initExprent);
+ }
+
+ public int getLooptype() {
+ return looptype;
+ }
+
+ public void setLooptype(int looptype) {
+ this.looptype = looptype;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/GeneralStatement.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/GeneralStatement.java
new file mode 100644
index 000000000000..a11171ef3010
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/GeneralStatement.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.stats;
+
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+
+import java.util.Collection;
+import java.util.HashSet;
+
+
+public class GeneralStatement extends Statement {
+
+ // *****************************************************************************
+ // constructors
+ // *****************************************************************************
+
+ private GeneralStatement() {
+ type = Statement.TYPE_GENERAL;
+ }
+
+ public GeneralStatement(Statement head, Collection<Statement> statements, Statement post) {
+
+ this();
+
+ first = head;
+ stats.addWithKey(head, head.id);
+
+ HashSet<Statement> set = new HashSet<Statement>(statements);
+ set.remove(head);
+
+ for (Statement st : set) {
+ stats.addWithKey(st, st.id);
+ }
+
+ this.post = post;
+ }
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public String toJava(int indent) {
+ String indstr = InterpreterUtil.getIndentString(indent);
+ StringBuilder buf = new StringBuilder();
+
+ String new_line_separator = DecompilerContext.getNewLineSeparator();
+
+ if (isLabeled()) {
+ buf.append(indstr).append("label").append(this.id).append(":").append(new_line_separator);
+ }
+
+ buf.append(indstr).append("abstract statement {").append(new_line_separator);
+ for (int i = 0; i < stats.size(); i++) {
+ buf.append(stats.get(i).toJava(indent + 1));
+ }
+ buf.append(indstr).append("}");
+
+ return buf.toString();
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/IfStatement.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/IfStatement.java
new file mode 100644
index 000000000000..9ad812534c6c
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/IfStatement.java
@@ -0,0 +1,416 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.stats;
+
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.modules.decompiler.DecHelper;
+import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
+import org.jetbrains.java.decompiler.modules.decompiler.StatEdge;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.IfExprent;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class IfStatement extends Statement {
+
+ public static int IFTYPE_IF = 0;
+ public static int IFTYPE_IFELSE = 1;
+
+ public int iftype;
+
+ // *****************************************************************************
+ // private fields
+ // *****************************************************************************
+
+ private Statement ifstat;
+ private Statement elsestat;
+
+ private StatEdge ifedge;
+ private StatEdge elseedge;
+
+ private boolean negated = false;
+
+ private boolean iffflag;
+
+ private List<Exprent> headexprent = new ArrayList<Exprent>(); // contains IfExprent
+
+ // *****************************************************************************
+ // constructors
+ // *****************************************************************************
+
+ private IfStatement() {
+ type = TYPE_IF;
+
+ headexprent.add(null);
+ }
+
+ private IfStatement(Statement head, int regedges, Statement postst) {
+
+ this();
+
+ first = head;
+ stats.addWithKey(head, head.id);
+
+ List<StatEdge> lstHeadSuccs = head.getSuccessorEdges(STATEDGE_DIRECT_ALL);
+
+ switch (regedges) {
+ case 0:
+ ifstat = null;
+ elsestat = null;
+
+ break;
+ case 1:
+ ifstat = null;
+ elsestat = null;
+
+ StatEdge edgeif = lstHeadSuccs.get(1);
+ if (edgeif.getType() != StatEdge.TYPE_REGULAR) {
+ post = lstHeadSuccs.get(0).getDestination();
+ }
+ else {
+ post = edgeif.getDestination();
+ negated = true;
+ }
+ break;
+ case 2:
+ elsestat = lstHeadSuccs.get(0).getDestination();
+ ifstat = lstHeadSuccs.get(1).getDestination();
+
+ List<StatEdge> lstSucc = ifstat.getSuccessorEdges(StatEdge.TYPE_REGULAR);
+ List<StatEdge> lstSucc1 = elsestat.getSuccessorEdges(StatEdge.TYPE_REGULAR);
+
+ if (ifstat.getPredecessorEdges(StatEdge.TYPE_REGULAR).size() > 1 || lstSucc.size() > 1) {
+ post = ifstat;
+ }
+ else if (elsestat.getPredecessorEdges(StatEdge.TYPE_REGULAR).size() > 1 || lstSucc1.size() > 1) {
+ post = elsestat;
+ }
+ else {
+ if (lstSucc.size() == 0) {
+ post = elsestat;
+ }
+ else if (lstSucc1.size() == 0) {
+ post = ifstat;
+ }
+ }
+
+ if (ifstat == post) {
+ if (elsestat != post) {
+ ifstat = elsestat;
+ negated = true;
+ }
+ else {
+ ifstat = null;
+ }
+ elsestat = null;
+ }
+ else if (elsestat == post) {
+ elsestat = null;
+ }
+ else {
+ post = postst;
+ }
+
+ if (elsestat == null) {
+ regedges = 1; // if without else
+ }
+ }
+
+ ifedge = lstHeadSuccs.get(negated ? 0 : 1);
+ elseedge = (regedges == 2) ? lstHeadSuccs.get(negated ? 1 : 0) : null;
+
+ iftype = (regedges == 2) ? IFTYPE_IFELSE : IFTYPE_IF;
+
+ if (iftype == IFTYPE_IF) {
+ if (regedges == 0) {
+ StatEdge edge = lstHeadSuccs.get(0);
+ head.removeSuccessor(edge);
+ edge.setSource(this);
+ this.addSuccessor(edge);
+ }
+ else if (regedges == 1) {
+ StatEdge edge = lstHeadSuccs.get(negated ? 1 : 0);
+ head.removeSuccessor(edge);
+ }
+ }
+
+ if (ifstat != null) {
+ stats.addWithKey(ifstat, ifstat.id);
+ }
+
+ if (elsestat != null) {
+ stats.addWithKey(elsestat, elsestat.id);
+ }
+
+ if (post == head) {
+ post = this;
+ }
+ }
+
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public static Statement isHead(Statement head) {
+
+ if (head.type == TYPE_BASICBLOCK && head.getLastBasicType() == LASTBASICTYPE_IF) {
+ int regsize = head.getSuccessorEdges(StatEdge.TYPE_REGULAR).size();
+
+ Statement p = null;
+
+ boolean ok = (regsize < 2);
+ if (!ok) {
+ List<Statement> lst = new ArrayList<Statement>();
+ if (DecHelper.isChoiceStatement(head, lst)) {
+ p = lst.remove(0);
+
+ for (Statement st : lst) {
+ if (st.isMonitorEnter()) {
+ return null;
+ }
+ }
+
+ ok = DecHelper.checkStatementExceptions(lst);
+ }
+ }
+
+ if (ok) {
+ return new IfStatement(head, regsize, p);
+ }
+ }
+
+ return null;
+ }
+
+ public String toJava(int indent) {
+ String indstr = InterpreterUtil.getIndentString(indent);
+ StringBuilder buf = new StringBuilder();
+
+ String new_line_separator = DecompilerContext.getNewLineSeparator();
+
+ buf.append(ExprProcessor.listToJava(varDefinitions, indent));
+ buf.append(first.toJava(indent));
+
+ if (isLabeled()) {
+ buf.append(indstr).append("label").append(this.id).append(":").append(new_line_separator);
+ }
+
+ buf.append(indstr).append(headexprent.get(0).toJava(indent)).append(" {").append(new_line_separator);
+
+ if (ifstat == null) {
+ buf.append(InterpreterUtil.getIndentString(indent + 1));
+
+ if (ifedge.explicit) {
+ if (ifedge.getType() == StatEdge.TYPE_BREAK) {
+ // break
+ buf.append("break");
+ }
+ else {
+ // continue
+ buf.append("continue");
+ }
+
+ if (ifedge.labeled) {
+ buf.append(" label").append(ifedge.closure.id);
+ }
+ }
+ buf.append(";").append(new_line_separator);
+ }
+ else {
+ buf.append(ExprProcessor.jmpWrapper(ifstat, indent + 1, true));
+ }
+
+ boolean elseif = false;
+
+ if (elsestat != null) {
+ if (elsestat.type == Statement.TYPE_IF
+ && elsestat.varDefinitions.isEmpty() && elsestat.getFirst().getExprents().isEmpty() &&
+ !elsestat.isLabeled() &&
+ (elsestat.getSuccessorEdges(STATEDGE_DIRECT_ALL).isEmpty()
+ || !elsestat.getSuccessorEdges(STATEDGE_DIRECT_ALL).get(0).explicit)) { // else if
+ String content = ExprProcessor.jmpWrapper(elsestat, indent, false);
+ content = content.substring(indstr.length());
+
+ buf.append(indstr).append("} else ");
+ buf.append(content);
+
+ elseif = true;
+ }
+ else {
+ String content = ExprProcessor.jmpWrapper(elsestat, indent + 1, false);
+
+ if (content.length() > 0) {
+ buf.append(indstr).append("} else {").append(new_line_separator);
+ buf.append(content);
+ }
+ }
+ }
+
+ if (!elseif) {
+ buf.append(indstr).append("}").append(new_line_separator);
+ }
+
+ return buf.toString();
+ }
+
+ public void initExprents() {
+
+ IfExprent ifexpr = (IfExprent)first.getExprents().remove(first.getExprents().size() - 1);
+
+ if (negated) {
+ ifexpr = (IfExprent)ifexpr.copy();
+ ifexpr.negateIf();
+ }
+
+ headexprent.set(0, ifexpr);
+ }
+
+ public List<Object> getSequentialObjects() {
+
+ List<Object> lst = new ArrayList<Object>(stats);
+ lst.add(1, headexprent.get(0));
+
+ return lst;
+ }
+
+ public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
+ if (headexprent.get(0) == oldexpr) {
+ headexprent.set(0, newexpr);
+ }
+ }
+
+ public void replaceStatement(Statement oldstat, Statement newstat) {
+
+ super.replaceStatement(oldstat, newstat);
+
+ if (ifstat == oldstat) {
+ ifstat = newstat;
+ }
+
+ if (elsestat == oldstat) {
+ elsestat = newstat;
+ }
+
+ List<StatEdge> lstSuccs = first.getSuccessorEdges(STATEDGE_DIRECT_ALL);
+
+ if (iftype == IFTYPE_IF) {
+ ifedge = lstSuccs.get(0);
+ elseedge = null;
+ }
+ else {
+ StatEdge edge0 = lstSuccs.get(0);
+ StatEdge edge1 = lstSuccs.get(1);
+ if (edge0.getDestination() == ifstat) {
+ ifedge = edge0;
+ elseedge = edge1;
+ }
+ else {
+ ifedge = edge1;
+ elseedge = edge0;
+ }
+ }
+ }
+
+ public Statement getSimpleCopy() {
+
+ IfStatement is = new IfStatement();
+ is.iftype = this.iftype;
+ is.negated = this.negated;
+ is.iffflag = this.iffflag;
+
+ return is;
+ }
+
+ public void initSimpleCopy() {
+
+ first = stats.get(0);
+
+ List<StatEdge> lstSuccs = first.getSuccessorEdges(STATEDGE_DIRECT_ALL);
+ ifedge = lstSuccs.get((iftype == IFTYPE_IF || negated) ? 0 : 1);
+ if (stats.size() > 1) {
+ ifstat = stats.get(1);
+ }
+
+ if (iftype == IFTYPE_IFELSE) {
+ elseedge = lstSuccs.get(negated ? 1 : 0);
+ elsestat = stats.get(2);
+ }
+ }
+
+ // *****************************************************************************
+ // getter and setter methods
+ // *****************************************************************************
+
+ public Statement getElsestat() {
+ return elsestat;
+ }
+
+ public void setElsestat(Statement elsestat) {
+ this.elsestat = elsestat;
+ }
+
+ public Statement getIfstat() {
+ return ifstat;
+ }
+
+ public void setIfstat(Statement ifstat) {
+ this.ifstat = ifstat;
+ }
+
+ public boolean isNegated() {
+ return negated;
+ }
+
+ public void setNegated(boolean negated) {
+ this.negated = negated;
+ }
+
+ public List<Exprent> getHeadexprentList() {
+ return headexprent;
+ }
+
+ public IfExprent getHeadexprent() {
+ return (IfExprent)headexprent.get(0);
+ }
+
+ public boolean isIffflag() {
+ return iffflag;
+ }
+
+ public void setIffflag(boolean iffflag) {
+ this.iffflag = iffflag;
+ }
+
+ public void setElseEdge(StatEdge elseedge) {
+ this.elseedge = elseedge;
+ }
+
+ public void setIfEdge(StatEdge ifedge) {
+ this.ifedge = ifedge;
+ }
+
+ public StatEdge getIfEdge() {
+ return ifedge;
+ }
+
+ public StatEdge getElseEdge() {
+ return elseedge;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/RootStatement.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/RootStatement.java
new file mode 100644
index 000000000000..2a6944712ace
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/RootStatement.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.stats;
+
+import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
+
+
+public class RootStatement extends Statement {
+
+ private Statement dummyExit;
+
+ public RootStatement(Statement head, Statement dummyExit) {
+
+ type = Statement.TYPE_ROOT;
+
+ first = head;
+ this.dummyExit = dummyExit;
+
+ stats.addWithKey(first, first.id);
+ first.setParent(this);
+ }
+
+ public String toJava(int indent) {
+ return ExprProcessor.listToJava(varDefinitions, indent) +
+ first.toJava(indent);
+ }
+
+ public Statement getDummyExit() {
+ return dummyExit;
+ }
+
+ public void setDummyExit(Statement dummyExit) {
+ this.dummyExit = dummyExit;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SequenceStatement.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SequenceStatement.java
new file mode 100644
index 000000000000..eccce91fd051
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SequenceStatement.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.stats;
+
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.modules.decompiler.DecHelper;
+import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
+import org.jetbrains.java.decompiler.modules.decompiler.StatEdge;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+
+import java.util.Arrays;
+import java.util.List;
+
+
+public class SequenceStatement extends Statement {
+
+
+ // *****************************************************************************
+ // constructors
+ // *****************************************************************************
+
+ private SequenceStatement() {
+ type = Statement.TYPE_SEQUENCE;
+ }
+
+ public SequenceStatement(List<Statement> lst) {
+
+ this();
+
+ lastBasicType = lst.get(lst.size() - 1).getLastBasicType();
+
+ for (Statement st : lst) {
+ stats.addWithKey(st, st.id);
+ }
+
+ first = stats.get(0);
+ }
+
+ private SequenceStatement(Statement head, Statement tail) {
+
+ this(Arrays.asList(head, tail));
+
+ List<StatEdge> lstSuccs = tail.getSuccessorEdges(STATEDGE_DIRECT_ALL);
+ if (!lstSuccs.isEmpty()) {
+ StatEdge edge = lstSuccs.get(0);
+
+ if (edge.getType() == StatEdge.TYPE_REGULAR && edge.getDestination() != head) {
+ post = edge.getDestination();
+ }
+ }
+ }
+
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public static Statement isHead2Block(Statement head) {
+
+ if (head.getLastBasicType() != Statement.LASTBASICTYPE_GENERAL) {
+ return null;
+ }
+
+ // at most one outgoing edge
+ StatEdge edge = null;
+ List<StatEdge> lstSuccs = head.getSuccessorEdges(STATEDGE_DIRECT_ALL);
+ if (!lstSuccs.isEmpty()) {
+ edge = lstSuccs.get(0);
+ }
+
+ if (edge != null && edge.getType() == StatEdge.TYPE_REGULAR) {
+ Statement stat = edge.getDestination();
+
+ if (stat != head && stat.getPredecessorEdges(StatEdge.TYPE_REGULAR).size() == 1
+ && !stat.isMonitorEnter()) {
+
+ if (stat.getLastBasicType() == Statement.LASTBASICTYPE_GENERAL) {
+ if (DecHelper.checkStatementExceptions(Arrays.asList(head, stat))) {
+ return new SequenceStatement(head, stat);
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public String toJava(int indent) {
+
+ StringBuilder buf = new StringBuilder();
+
+ String indstr = null;
+ boolean islabeled = isLabeled();
+
+ String new_line_separator = DecompilerContext.getNewLineSeparator();
+
+ buf.append(ExprProcessor.listToJava(varDefinitions, indent));
+
+ if (islabeled) {
+ indstr = InterpreterUtil.getIndentString(indent);
+ indent++;
+ buf.append(indstr).append("label").append(this.id).append(": {").append(new_line_separator);
+ }
+
+ boolean notempty = false;
+
+ for (int i = 0; i < stats.size(); i++) {
+
+ Statement st = stats.get(i);
+
+ if (i > 0 && notempty) {
+ buf.append(new_line_separator);
+ }
+
+ String str = ExprProcessor.jmpWrapper(st, indent, false);
+ buf.append(str);
+
+ notempty = (str.trim().length() > 0);
+ }
+
+ if (islabeled) {
+ buf.append(indstr).append("}").append(new_line_separator);
+ }
+
+ return buf.toString();
+ }
+
+ public Statement getSimpleCopy() {
+ return new SequenceStatement();
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java
new file mode 100644
index 000000000000..cbdb3b71ff22
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/Statement.java
@@ -0,0 +1,863 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.stats;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.code.InstructionSequence;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
+import org.jetbrains.java.decompiler.modules.decompiler.StatEdge;
+import org.jetbrains.java.decompiler.modules.decompiler.StrongConnectivityHelper;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
+import org.jetbrains.java.decompiler.util.VBStyleCollection;
+
+import java.util.*;
+
+public class Statement {
+
+ public static final int STATEDGE_ALL = 1 << 31;
+ public static final int STATEDGE_DIRECT_ALL = 1 << 30;
+
+ public static final int DIRECTION_BACKWARD = 0;
+ public static final int DIRECTION_FORWARD = 1;
+
+ public static final int TYPE_GENERAL = 0;
+ public static final int TYPE_IF = 2;
+ public static final int TYPE_DO = 5;
+ public static final int TYPE_SWITCH = 6;
+ public static final int TYPE_TRYCATCH = 7;
+ public static final int TYPE_BASICBLOCK = 8;
+ public static final int TYPE_FINALLY = 9;
+ public static final int TYPE_SYNCRONIZED = 10;
+ public static final int TYPE_PLACEHOLDER = 11;
+ public static final int TYPE_CATCHALL = 12;
+ public static final int TYPE_ROOT = 13;
+ public static final int TYPE_DUMMYEXIT = 14;
+ public static final int TYPE_SEQUENCE = 15;
+
+
+ public static final int LASTBASICTYPE_IF = 0;
+ public static final int LASTBASICTYPE_SWITCH = 1;
+ public static final int LASTBASICTYPE_GENERAL = 2;
+
+
+ // *****************************************************************************
+ // public fields
+ // *****************************************************************************
+
+ public int type;
+
+ public Integer id;
+
+ // *****************************************************************************
+ // private fields
+ // *****************************************************************************
+
+ private Map<Integer, List<StatEdge>> mapSuccEdges = new HashMap<Integer, List<StatEdge>>();
+ private Map<Integer, List<StatEdge>> mapPredEdges = new HashMap<Integer, List<StatEdge>>();
+
+ private Map<Integer, List<Statement>> mapSuccStates = new HashMap<Integer, List<Statement>>();
+ private Map<Integer, List<Statement>> mapPredStates = new HashMap<Integer, List<Statement>>();
+
+ // statement as graph
+ protected VBStyleCollection<Statement, Integer> stats = new VBStyleCollection<Statement, Integer>();
+
+ protected Statement parent;
+
+ protected Statement first;
+
+ protected List<Exprent> exprents;
+
+ protected HashSet<StatEdge> labelEdges = new HashSet<StatEdge>();
+
+ protected List<Exprent> varDefinitions = new ArrayList<Exprent>();
+
+ // copied statement, s. deobfuscating of irreducible CFGs
+ private boolean copied = false;
+
+ // relevant for the first stage of processing only
+ // set to null after initializing of the statement structure
+
+ protected Statement post;
+
+ protected int lastBasicType = LASTBASICTYPE_GENERAL;
+
+ protected boolean isMonitorEnter;
+
+ protected boolean containsMonitorExit;
+
+ protected HashSet<Statement> continueSet = new HashSet<Statement>();
+
+ // *****************************************************************************
+ // initializers
+ // *****************************************************************************
+
+ {
+ // set statement id
+ id = DecompilerContext.getCounterContainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER);
+ }
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public void clearTempInformation() {
+
+ post = null;
+ continueSet = null;
+
+ copied = false;
+ // FIXME: used in FlattenStatementsHelper.flattenStatement()! check and remove
+ //lastBasicType = LASTBASICTYPE_GENERAL;
+ isMonitorEnter = false;
+ containsMonitorExit = false;
+
+ processMap(mapSuccEdges);
+ processMap(mapPredEdges);
+ processMap(mapSuccStates);
+ processMap(mapPredStates);
+ }
+
+ private static <T> void processMap(Map<Integer, List<T>> map) {
+ map.remove(StatEdge.TYPE_EXCEPTION);
+
+ List<T> lst = map.get(STATEDGE_DIRECT_ALL);
+ if (lst != null) {
+ map.put(STATEDGE_ALL, new ArrayList<T>(lst));
+ }
+ else {
+ map.remove(STATEDGE_ALL);
+ }
+ }
+
+ public void collapseNodesToStatement(Statement stat) {
+
+ Statement head = stat.getFirst();
+ Statement post = stat.getPost();
+
+ VBStyleCollection<Statement, Integer> setNodes = stat.getStats();
+
+ // post edges
+ if (post != null) {
+ for (StatEdge edge : post.getEdges(STATEDGE_DIRECT_ALL, DIRECTION_BACKWARD)) {
+ if (stat.containsStatementStrict(edge.getSource())) {
+ edge.getSource().changeEdgeType(DIRECTION_FORWARD, edge, StatEdge.TYPE_BREAK);
+ stat.addLabeledEdge(edge);
+ }
+ }
+ }
+
+ // regular head edges
+ for (StatEdge prededge : head.getAllPredecessorEdges()) {
+
+ if (prededge.getType() != StatEdge.TYPE_EXCEPTION &&
+ stat.containsStatementStrict(prededge.getSource())) {
+ prededge.getSource().changeEdgeType(DIRECTION_FORWARD, prededge, StatEdge.TYPE_CONTINUE);
+ stat.addLabeledEdge(prededge);
+ }
+
+ head.removePredecessor(prededge);
+ prededge.getSource().changeEdgeNode(DIRECTION_FORWARD, prededge, stat);
+ stat.addPredecessor(prededge);
+ }
+
+ if (setNodes.containsKey(first.id)) {
+ first = stat;
+ }
+
+ // exception edges
+ Set<Statement> setHandlers = new HashSet<Statement>(head.getNeighbours(StatEdge.TYPE_EXCEPTION, DIRECTION_FORWARD));
+ for (Statement node : setNodes) {
+ setHandlers.retainAll(node.getNeighbours(StatEdge.TYPE_EXCEPTION, DIRECTION_FORWARD));
+ }
+
+ if (!setHandlers.isEmpty()) {
+
+ for (StatEdge edge : head.getEdges(StatEdge.TYPE_EXCEPTION, DIRECTION_FORWARD)) {
+ Statement handler = edge.getDestination();
+
+ if (setHandlers.contains(handler)) {
+ if (!setNodes.containsKey(handler.id)) {
+ stat.addSuccessor(new StatEdge(stat, handler, edge.getExceptions()));
+ }
+ }
+ }
+
+ for (Statement node : setNodes) {
+ for (StatEdge edge : node.getEdges(StatEdge.TYPE_EXCEPTION, DIRECTION_FORWARD)) {
+ if (setHandlers.contains(edge.getDestination())) {
+ node.removeSuccessor(edge);
+ }
+ }
+ }
+ }
+
+ if (post != null &&
+ !stat.getNeighbours(StatEdge.TYPE_EXCEPTION, DIRECTION_FORWARD).contains(post)) { // TODO: second condition redundant?
+ stat.addSuccessor(new StatEdge(StatEdge.TYPE_REGULAR, stat, post));
+ }
+
+
+ // adjust statement collection
+ for (Statement st : setNodes) {
+ stats.removeWithKey(st.id);
+ }
+
+ stats.addWithKey(stat, stat.id);
+
+ stat.setAllParent();
+ stat.setParent(this);
+
+ stat.buildContinueSet();
+ // monitorenter and monitorexit
+ stat.buildMonitorFlags();
+
+ if (stat.type == TYPE_SWITCH) {
+ // special case switch, sorting leaf nodes
+ ((SwitchStatement)stat).sortEdgesAndNodes();
+ }
+ }
+
+ public void setAllParent() {
+ for (Statement st : stats) {
+ st.setParent(this);
+ }
+ }
+
+ public void addLabeledEdge(StatEdge edge) {
+
+ if (edge.closure != null) {
+ edge.closure.getLabelEdges().remove(edge);
+ }
+ edge.closure = this;
+ this.getLabelEdges().add(edge);
+ }
+
+ private void addEdgeDirectInternal(int direction, StatEdge edge, int edgetype) {
+
+ Map<Integer, List<StatEdge>> mapEdges = direction == DIRECTION_BACKWARD ? mapPredEdges : mapSuccEdges;
+ Map<Integer, List<Statement>> mapStates = direction == DIRECTION_BACKWARD ? mapPredStates : mapSuccStates;
+
+ List<StatEdge> lst = mapEdges.get(edgetype);
+ if (lst == null) {
+ mapEdges.put(edgetype, lst = new ArrayList<StatEdge>());
+ }
+ lst.add(edge);
+
+ List<Statement> lstStates = mapStates.get(edgetype);
+ if (lstStates == null) {
+ mapStates.put(edgetype, lstStates = new ArrayList<Statement>());
+ }
+ lstStates.add(direction == DIRECTION_BACKWARD ? edge.getSource() : edge.getDestination());
+ }
+
+ private void addEdgeInternal(int direction, StatEdge edge) {
+
+ int type = edge.getType();
+
+ int[] arrtypes;
+ if (type == StatEdge.TYPE_EXCEPTION) {
+ arrtypes = new int[]{STATEDGE_ALL, StatEdge.TYPE_EXCEPTION};
+ }
+ else {
+ arrtypes = new int[]{STATEDGE_ALL, STATEDGE_DIRECT_ALL, type};
+ }
+
+ for (int edgetype : arrtypes) {
+ addEdgeDirectInternal(direction, edge, edgetype);
+ }
+ }
+
+ private void removeEdgeDirectInternal(int direction, StatEdge edge, int edgetype) {
+
+ Map<Integer, List<StatEdge>> mapEdges = direction == DIRECTION_BACKWARD ? mapPredEdges : mapSuccEdges;
+ Map<Integer, List<Statement>> mapStates = direction == DIRECTION_BACKWARD ? mapPredStates : mapSuccStates;
+
+ List<StatEdge> lst = mapEdges.get(edgetype);
+ if (lst != null) {
+ int index = lst.indexOf(edge);
+ if (index >= 0) {
+ lst.remove(index);
+ mapStates.get(edgetype).remove(index);
+ }
+ }
+ }
+
+ private void removeEdgeInternal(int direction, StatEdge edge) {
+
+ int type = edge.getType();
+
+ int[] arrtypes;
+ if (type == StatEdge.TYPE_EXCEPTION) {
+ arrtypes = new int[]{STATEDGE_ALL, StatEdge.TYPE_EXCEPTION};
+ }
+ else {
+ arrtypes = new int[]{STATEDGE_ALL, STATEDGE_DIRECT_ALL, type};
+ }
+
+ for (int edgetype : arrtypes) {
+ removeEdgeDirectInternal(direction, edge, edgetype);
+ }
+ }
+
+ public void addPredecessor(StatEdge edge) {
+ addEdgeInternal(DIRECTION_BACKWARD, edge);
+ }
+
+ public void removePredecessor(StatEdge edge) {
+
+ if (edge == null) { // FIXME: redundant?
+ return;
+ }
+
+ removeEdgeInternal(DIRECTION_BACKWARD, edge);
+ }
+
+ public void addSuccessor(StatEdge edge) {
+ addEdgeInternal(DIRECTION_FORWARD, edge);
+
+ if (edge.closure != null) {
+ edge.closure.getLabelEdges().add(edge);
+ }
+
+ edge.getDestination().addPredecessor(edge);
+ }
+
+ public void removeSuccessor(StatEdge edge) {
+
+ if (edge == null) {
+ return;
+ }
+
+ removeEdgeInternal(DIRECTION_FORWARD, edge);
+
+ if (edge.closure != null) {
+ edge.closure.getLabelEdges().remove(edge);
+ }
+
+ if (edge.getDestination() != null) { // TODO: redundant?
+ edge.getDestination().removePredecessor(edge);
+ }
+ }
+
+ // TODO: make obsolete and remove
+ public void removeAllSuccessors(Statement stat) {
+
+ if (stat == null) {
+ return;
+ }
+
+ for (StatEdge edge : getAllSuccessorEdges()) {
+ if (edge.getDestination() == stat) {
+ removeSuccessor(edge);
+ }
+ }
+ }
+
+ public HashSet<Statement> buildContinueSet() {
+ continueSet.clear();
+
+ for (Statement st : stats) {
+ continueSet.addAll(st.buildContinueSet());
+ if (st != first) {
+ continueSet.remove(st.getBasichead());
+ }
+ }
+
+ for (StatEdge edge : getEdges(StatEdge.TYPE_CONTINUE, DIRECTION_FORWARD)) {
+ continueSet.add(edge.getDestination().getBasichead());
+ }
+
+ if (type == TYPE_DO) {
+ continueSet.remove(first.getBasichead());
+ }
+
+ return continueSet;
+ }
+
+ public void buildMonitorFlags() {
+
+ for (Statement st : stats) {
+ st.buildMonitorFlags();
+ }
+
+ switch (type) {
+ case TYPE_BASICBLOCK:
+ BasicBlockStatement bblock = (BasicBlockStatement)this;
+ InstructionSequence seq = bblock.getBlock().getSeq();
+
+ if (seq != null && seq.length() > 0) {
+ for (int i = 0; i < seq.length(); i++) {
+ if (seq.getInstr(i).opcode == CodeConstants.opc_monitorexit) {
+ containsMonitorExit = true;
+ break;
+ }
+ }
+ isMonitorEnter = (seq.getLastInstr().opcode == CodeConstants.opc_monitorenter);
+ }
+ break;
+ case TYPE_SEQUENCE:
+ case TYPE_IF:
+ containsMonitorExit = false;
+ for (Statement st : stats) {
+ containsMonitorExit |= st.isContainsMonitorExit();
+ }
+
+ break;
+ case TYPE_SYNCRONIZED:
+ case TYPE_ROOT:
+ case TYPE_GENERAL:
+ break;
+ default:
+ containsMonitorExit = false;
+ for (Statement st : stats) {
+ containsMonitorExit |= st.isContainsMonitorExit();
+ }
+ }
+ }
+
+
+ public List<Statement> getReversePostOrderList() {
+ return getReversePostOrderList(first);
+ }
+
+ public List<Statement> getReversePostOrderList(Statement stat) {
+ List<Statement> res = new ArrayList<Statement>();
+
+ addToReversePostOrderListIterative(stat, res);
+
+ return res;
+ }
+
+ public List<Statement> getPostReversePostOrderList() {
+ return getPostReversePostOrderList(null);
+ }
+
+ public List<Statement> getPostReversePostOrderList(List<Statement> lstexits) {
+
+ List<Statement> res = new ArrayList<Statement>();
+
+ if (lstexits == null) {
+ StrongConnectivityHelper schelper = new StrongConnectivityHelper(this);
+ lstexits = StrongConnectivityHelper.getExitReps(schelper.getComponents());
+ }
+
+ HashSet<Statement> setVisited = new HashSet<Statement>();
+
+ for (Statement exit : lstexits) {
+ addToPostReversePostOrderList(exit, res, setVisited);
+ }
+
+ if (res.size() != stats.size()) {
+ DecompilerContext.getLogger().writeMessage("computing post reverse post order failed!", IFernflowerLogger.Severity.ERROR);
+
+ throw new RuntimeException("parsing failure!");
+ }
+
+ return res;
+ }
+
+ public boolean containsStatement(Statement stat) {
+ return this == stat || containsStatementStrict(stat);
+ }
+
+ public boolean containsStatementStrict(Statement stat) {
+
+ if (stats.contains(stat)) {
+ return true;
+ }
+
+ for (int i = 0; i < stats.size(); i++) {
+ if (stats.get(i).containsStatementStrict(stat)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ // to be overwritten
+ public String toJava() {
+ return toJava(0);
+ }
+
+ public String toJava(int indent) {
+ throw new RuntimeException("not implemented");
+ }
+
+ // TODO: make obsolete and remove
+ public List<Object> getSequentialObjects() {
+ return new ArrayList<Object>(stats);
+ }
+
+ public void initExprents() {
+ // do nothing
+ }
+
+ public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
+ // do nothing
+ }
+
+ public Statement getSimpleCopy() {
+ throw new RuntimeException("not implemented");
+ }
+
+ public void initSimpleCopy() {
+ if (!stats.isEmpty()) {
+ first = stats.get(0);
+ }
+ }
+
+ public void replaceStatement(Statement oldstat, Statement newstat) {
+
+ for (StatEdge edge : oldstat.getAllPredecessorEdges()) {
+ oldstat.removePredecessor(edge);
+ edge.getSource().changeEdgeNode(DIRECTION_FORWARD, edge, newstat);
+ newstat.addPredecessor(edge);
+ }
+
+ for (StatEdge edge : oldstat.getAllSuccessorEdges()) {
+ oldstat.removeSuccessor(edge);
+ edge.setSource(newstat);
+ newstat.addSuccessor(edge);
+ }
+
+ int statindex = stats.getIndexByKey(oldstat.id);
+ stats.removeWithKey(oldstat.id);
+ stats.addWithKeyAndIndex(statindex, newstat, newstat.id);
+
+ newstat.setParent(this);
+ newstat.post = oldstat.post;
+
+ if (first == oldstat) {
+ first = newstat;
+ }
+
+ List<StatEdge> lst = new ArrayList<StatEdge>(oldstat.getLabelEdges());
+
+ for (int i = lst.size() - 1; i >= 0; i--) {
+ StatEdge edge = lst.get(i);
+ if (edge.getSource() != newstat) {
+ newstat.addLabeledEdge(edge);
+ }
+ else {
+ if (this == edge.getDestination() || this.containsStatementStrict(edge.getDestination())) {
+ edge.closure = null;
+ }
+ else {
+ this.addLabeledEdge(edge);
+ }
+ }
+ }
+
+ oldstat.getLabelEdges().clear();
+ }
+
+
+ // *****************************************************************************
+ // private methods
+ // *****************************************************************************
+
+ private static void addToReversePostOrderListIterative(Statement root, List<Statement> lst) {
+
+ LinkedList<Statement> stackNode = new LinkedList<Statement>();
+ LinkedList<Integer> stackIndex = new LinkedList<Integer>();
+ HashSet<Statement> setVisited = new HashSet<Statement>();
+
+ stackNode.add(root);
+ stackIndex.add(0);
+
+ while (!stackNode.isEmpty()) {
+
+ Statement node = stackNode.getLast();
+ int index = stackIndex.removeLast();
+
+ setVisited.add(node);
+
+ List<StatEdge> lstEdges = node.getAllSuccessorEdges();
+
+ for (; index < lstEdges.size(); index++) {
+ StatEdge edge = lstEdges.get(index);
+ Statement succ = edge.getDestination();
+
+ if (!setVisited.contains(succ) &&
+ (edge.getType() == StatEdge.TYPE_REGULAR || edge.getType() == StatEdge.TYPE_EXCEPTION)) { // TODO: edge filter?
+
+ stackIndex.add(index + 1);
+
+ stackNode.add(succ);
+ stackIndex.add(0);
+
+ break;
+ }
+ }
+
+ if (index == lstEdges.size()) {
+ lst.add(0, node);
+
+ stackNode.removeLast();
+ }
+ }
+ }
+
+
+ private static void addToPostReversePostOrderList(Statement stat, List<Statement> lst, HashSet<Statement> setVisited) {
+
+ if (setVisited.contains(stat)) { // because of not considered exception edges, s. isExitComponent. Should be rewritten, if possible.
+ return;
+ }
+ setVisited.add(stat);
+
+ for (StatEdge prededge : stat.getEdges(StatEdge.TYPE_REGULAR | StatEdge.TYPE_EXCEPTION, DIRECTION_BACKWARD)) {
+ Statement pred = prededge.getSource();
+ if (!setVisited.contains(pred)) {
+ addToPostReversePostOrderList(pred, lst, setVisited);
+ }
+ }
+
+ lst.add(0, stat);
+ }
+
+ // *****************************************************************************
+ // getter and setter methods
+ // *****************************************************************************
+
+ public void changeEdgeNode(int direction, StatEdge edge, Statement value) {
+
+ Map<Integer, List<StatEdge>> mapEdges = direction == DIRECTION_BACKWARD ? mapPredEdges : mapSuccEdges;
+ Map<Integer, List<Statement>> mapStates = direction == DIRECTION_BACKWARD ? mapPredStates : mapSuccStates;
+
+ int type = edge.getType();
+
+ int[] arrtypes;
+ if (type == StatEdge.TYPE_EXCEPTION) {
+ arrtypes = new int[]{STATEDGE_ALL, StatEdge.TYPE_EXCEPTION};
+ }
+ else {
+ arrtypes = new int[]{STATEDGE_ALL, STATEDGE_DIRECT_ALL, type};
+ }
+
+ for (int edgetype : arrtypes) {
+ List<StatEdge> lst = mapEdges.get(edgetype);
+ if (lst != null) {
+ int index = lst.indexOf(edge);
+ if (index >= 0) {
+ mapStates.get(edgetype).set(index, value);
+ }
+ }
+ }
+
+ if (direction == DIRECTION_BACKWARD) {
+ edge.setSource(value);
+ }
+ else {
+ edge.setDestination(value);
+ }
+ }
+
+ public void changeEdgeType(int direction, StatEdge edge, int newtype) {
+
+ int oldtype = edge.getType();
+ if (oldtype == newtype) {
+ return;
+ }
+
+ if (oldtype == StatEdge.TYPE_EXCEPTION || newtype == StatEdge.TYPE_EXCEPTION) {
+ throw new RuntimeException("Invalid edge type!");
+ }
+
+ removeEdgeDirectInternal(direction, edge, oldtype);
+ addEdgeDirectInternal(direction, edge, newtype);
+
+ if (direction == DIRECTION_FORWARD) {
+ edge.getDestination().changeEdgeType(DIRECTION_BACKWARD, edge, newtype);
+ }
+
+ edge.setType(newtype);
+ }
+
+
+ private List<StatEdge> getEdges(int type, int direction) {
+
+ Map<Integer, List<StatEdge>> map = direction == DIRECTION_BACKWARD ? mapPredEdges : mapSuccEdges;
+
+ List<StatEdge> res;
+ if ((type & (type - 1)) == 0) {
+ res = map.get(type);
+ res = res == null ? new ArrayList<StatEdge>() : new ArrayList<StatEdge>(res);
+ }
+ else {
+ res = new ArrayList<StatEdge>();
+ for (int edgetype : StatEdge.TYPES) {
+ if ((type & edgetype) != 0) {
+ List<StatEdge> lst = map.get(edgetype);
+ if (lst != null) {
+ res.addAll(lst);
+ }
+ }
+ }
+ }
+
+ return res;
+ }
+
+ public List<Statement> getNeighbours(int type, int direction) {
+
+ Map<Integer, List<Statement>> map = direction == DIRECTION_BACKWARD ? mapPredStates : mapSuccStates;
+
+ List<Statement> res;
+ if ((type & (type - 1)) == 0) {
+ res = map.get(type);
+ res = res == null ? new ArrayList<Statement>() : new ArrayList<Statement>(res);
+ }
+ else {
+ res = new ArrayList<Statement>();
+ for (int edgetype : StatEdge.TYPES) {
+ if ((type & edgetype) != 0) {
+ List<Statement> lst = map.get(edgetype);
+ if (lst != null) {
+ res.addAll(lst);
+ }
+ }
+ }
+ }
+
+ return res;
+ }
+
+ public Set<Statement> getNeighboursSet(int type, int direction) {
+ return new HashSet<Statement>(getNeighbours(type, direction));
+ }
+
+ public List<StatEdge> getSuccessorEdges(int type) {
+ return getEdges(type, DIRECTION_FORWARD);
+ }
+
+ public List<StatEdge> getPredecessorEdges(int type) {
+ return getEdges(type, DIRECTION_BACKWARD);
+ }
+
+ public List<StatEdge> getAllSuccessorEdges() {
+ return getEdges(STATEDGE_ALL, DIRECTION_FORWARD);
+ }
+
+ public List<StatEdge> getAllPredecessorEdges() {
+ return getEdges(STATEDGE_ALL, DIRECTION_BACKWARD);
+ }
+
+ public Statement getFirst() {
+ return first;
+ }
+
+ public void setFirst(Statement first) {
+ this.first = first;
+ }
+
+ public Statement getPost() {
+ return post;
+ }
+
+ public void setPost(Statement post) {
+ this.post = post;
+ }
+
+ public VBStyleCollection<Statement, Integer> getStats() {
+ return stats;
+ }
+
+ public int getLastBasicType() {
+ return lastBasicType;
+ }
+
+ public HashSet<Statement> getContinueSet() {
+ return continueSet;
+ }
+
+ public boolean isContainsMonitorExit() {
+ return containsMonitorExit;
+ }
+
+ public boolean isMonitorEnter() {
+ return isMonitorEnter;
+ }
+
+ public BasicBlockStatement getBasichead() {
+ if (type == TYPE_BASICBLOCK) {
+ return (BasicBlockStatement)this;
+ }
+ else {
+ return first.getBasichead();
+ }
+ }
+
+ public boolean isLabeled() {
+
+ for (StatEdge edge : labelEdges) {
+ if (edge.labeled && edge.explicit) { // FIXME: consistent setting
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean hasBasicSuccEdge() {
+
+ // FIXME: default switch
+
+ return type == TYPE_BASICBLOCK || (type == TYPE_IF &&
+ ((IfStatement)this).iftype == IfStatement.IFTYPE_IF) ||
+ (type == TYPE_DO && ((DoStatement)this).getLooptype() != DoStatement.LOOP_DO);
+ }
+
+
+ public Statement getParent() {
+ return parent;
+ }
+
+ public void setParent(Statement parent) {
+ this.parent = parent;
+ }
+
+ public HashSet<StatEdge> getLabelEdges() { // FIXME: why HashSet?
+ return labelEdges;
+ }
+
+ public List<Exprent> getVarDefinitions() {
+ return varDefinitions;
+ }
+
+ public List<Exprent> getExprents() {
+ return exprents;
+ }
+
+ public void setExprents(List<Exprent> exprents) {
+ this.exprents = exprents;
+ }
+
+ public boolean isCopied() {
+ return copied;
+ }
+
+ public void setCopied(boolean copied) {
+ this.copied = copied;
+ }
+
+ // helper methods
+ public String toString() {
+ return id.toString();
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SwitchStatement.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SwitchStatement.java
new file mode 100644
index 000000000000..b54642dfb58f
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SwitchStatement.java
@@ -0,0 +1,367 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.stats;
+
+import org.jetbrains.java.decompiler.code.SwitchInstruction;
+import org.jetbrains.java.decompiler.code.cfg.BasicBlock;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
+import org.jetbrains.java.decompiler.modules.decompiler.DecHelper;
+import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
+import org.jetbrains.java.decompiler.modules.decompiler.StatEdge;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.ConstExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.SwitchExprent;
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+
+import java.util.*;
+
+public class SwitchStatement extends Statement {
+
+ // *****************************************************************************
+ // private fields
+ // *****************************************************************************
+
+ private List<Statement> caseStatements = new ArrayList<Statement>();
+
+ private List<List<StatEdge>> caseEdges = new ArrayList<List<StatEdge>>();
+
+ private List<List<ConstExprent>> caseValues = new ArrayList<List<ConstExprent>>();
+
+ private StatEdge default_edge;
+
+ private List<Exprent> headexprent = new ArrayList<Exprent>();
+
+ // *****************************************************************************
+ // constructors
+ // *****************************************************************************
+
+ private SwitchStatement() {
+ type = TYPE_SWITCH;
+
+ headexprent.add(null);
+ }
+
+ private SwitchStatement(Statement head, Statement poststat) {
+
+ this();
+
+ first = head;
+ stats.addWithKey(head, head.id);
+
+ // find post node
+ Set<Statement> lstNodes = new HashSet<Statement>(head.getNeighbours(StatEdge.TYPE_REGULAR, DIRECTION_FORWARD));
+
+ // cluster nodes
+ if (poststat != null) {
+ post = poststat;
+ lstNodes.remove(post);
+ }
+
+ default_edge = head.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL).get(0);
+
+ for (Statement st : lstNodes) {
+ stats.addWithKey(st, st.id);
+ }
+ }
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public static Statement isHead(Statement head) {
+
+ if (head.type == Statement.TYPE_BASICBLOCK && head.getLastBasicType() == Statement.LASTBASICTYPE_SWITCH) {
+
+ List<Statement> lst = new ArrayList<Statement>();
+ if (DecHelper.isChoiceStatement(head, lst)) {
+ Statement post = lst.remove(0);
+
+ for (Statement st : lst) {
+ if (st.isMonitorEnter()) {
+ return null;
+ }
+ }
+
+ if (DecHelper.checkStatementExceptions(lst)) {
+ return new SwitchStatement(head, post);
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public String toJava(int indent) {
+
+ String indstr = InterpreterUtil.getIndentString(indent);
+
+ String new_line_separator = DecompilerContext.getNewLineSeparator();
+
+ StringBuilder buf = new StringBuilder();
+ buf.append(ExprProcessor.listToJava(varDefinitions, indent));
+ buf.append(first.toJava(indent));
+
+ if (isLabeled()) {
+ buf.append(indstr).append("label").append(this.id).append(":").append(new_line_separator);
+ }
+
+ buf.append(indstr).append(headexprent.get(0).toJava(indent)).append(" {").append(new_line_separator);
+
+ VarType switch_type = headexprent.get(0).getExprType();
+
+ for (int i = 0; i < caseStatements.size(); i++) {
+
+ Statement stat = caseStatements.get(i);
+ List<StatEdge> edges = caseEdges.get(i);
+ List<ConstExprent> values = caseValues.get(i);
+
+ for (int j = 0; j < edges.size(); j++) {
+ if (edges.get(j) == default_edge) {
+ buf.append(indstr).append("default:").append(new_line_separator);
+ }
+ else {
+ ConstExprent value = (ConstExprent)values.get(j).copy();
+ value.setConsttype(switch_type);
+
+ buf.append(indstr).append("case ").append(value.toJava(indent)).append(":").append(new_line_separator);
+ }
+ }
+
+ buf.append(ExprProcessor.jmpWrapper(stat, indent + 1, false));
+ }
+
+ buf.append(indstr).append("}").append(new_line_separator);
+
+ return buf.toString();
+ }
+
+ public void initExprents() {
+ SwitchExprent swexpr = (SwitchExprent)first.getExprents().remove(first.getExprents().size() - 1);
+ swexpr.setCaseValues(caseValues);
+
+ headexprent.set(0, swexpr);
+ }
+
+ public List<Object> getSequentialObjects() {
+
+ List<Object> lst = new ArrayList<Object>(stats);
+ lst.add(1, headexprent.get(0));
+
+ return lst;
+ }
+
+ public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
+ if (headexprent.get(0) == oldexpr) {
+ headexprent.set(0, newexpr);
+ }
+ }
+
+ public void replaceStatement(Statement oldstat, Statement newstat) {
+
+ for (int i = 0; i < caseStatements.size(); i++) {
+ if (caseStatements.get(i) == oldstat) {
+ caseStatements.set(i, newstat);
+ }
+ }
+
+ super.replaceStatement(oldstat, newstat);
+ }
+
+ public Statement getSimpleCopy() {
+ return new SwitchStatement();
+ }
+
+ public void initSimpleCopy() {
+ first = stats.get(0);
+ default_edge = first.getSuccessorEdges(Statement.STATEDGE_DIRECT_ALL).get(0);
+
+ sortEdgesAndNodes();
+ }
+
+ // *****************************************************************************
+ // private methods
+ // *****************************************************************************
+
+ public void sortEdgesAndNodes() {
+
+ HashMap<StatEdge, Integer> mapEdgeIndex = new HashMap<StatEdge, Integer>();
+
+ List<StatEdge> lstFirstSuccs = first.getSuccessorEdges(STATEDGE_DIRECT_ALL);
+ for (int i = 0; i < lstFirstSuccs.size(); i++) {
+ mapEdgeIndex.put(lstFirstSuccs.get(i), i == 0 ? lstFirstSuccs.size() : i);
+ }
+
+ // case values
+ BasicBlockStatement bbstat = (BasicBlockStatement)first;
+ int[] values = ((SwitchInstruction)bbstat.getBlock().getLastInstruction()).getValues();
+
+ List<Statement> nodes = new ArrayList<Statement>();
+ List<List<Integer>> edges = new ArrayList<List<Integer>>();
+
+ // collect regular edges
+ for (int i = 1; i < stats.size(); i++) {
+
+ Statement stat = stats.get(i);
+
+ List<Integer> lst = new ArrayList<Integer>();
+ for (StatEdge edge : stat.getPredecessorEdges(StatEdge.TYPE_REGULAR)) {
+ if (edge.getSource() == first) {
+ lst.add(mapEdgeIndex.get(edge));
+ }
+ }
+ Collections.sort(lst);
+
+ nodes.add(stat);
+ edges.add(lst);
+ }
+
+ // collect exit edges
+ List<StatEdge> lstExitEdges = first.getSuccessorEdges(StatEdge.TYPE_BREAK | StatEdge.TYPE_CONTINUE);
+ while (!lstExitEdges.isEmpty()) {
+ StatEdge edge = lstExitEdges.get(0);
+
+ List<Integer> lst = new ArrayList<Integer>();
+ for (int i = lstExitEdges.size() - 1; i >= 0; i--) {
+ StatEdge edgeTemp = lstExitEdges.get(i);
+ if (edgeTemp.getDestination() == edge.getDestination() && edgeTemp.getType() == edge.getType()) {
+ lst.add(mapEdgeIndex.get(edgeTemp));
+ lstExitEdges.remove(i);
+ }
+ }
+ Collections.sort(lst);
+
+ nodes.add(null);
+ edges.add(lst);
+ }
+
+ // sort edges (bubblesort)
+ for (int i = 0; i < edges.size() - 1; i++) {
+ for (int j = edges.size() - 1; j > i; j--) {
+ if (edges.get(j - 1).get(0) > edges.get(j).get(0)) {
+ edges.set(j, edges.set(j - 1, edges.get(j)));
+ nodes.set(j, nodes.set(j - 1, nodes.get(j)));
+ }
+ }
+ }
+
+ // sort statement cliques
+ for (int index = 0; index < nodes.size(); index++) {
+ Statement stat = nodes.get(index);
+
+ if (stat != null) {
+ HashSet<Statement> setPreds = new HashSet<Statement>(stat.getNeighbours(StatEdge.TYPE_REGULAR, DIRECTION_BACKWARD));
+ setPreds.remove(first);
+
+ if (!setPreds.isEmpty()) {
+ Statement pred =
+ setPreds.iterator().next(); // assumption: at most one predecessor node besides the head. May not hold true for obfuscated code.
+ for (int j = 0; j < nodes.size(); j++) {
+ if (j != (index - 1) && nodes.get(j) == pred) {
+ nodes.add(j + 1, stat);
+ edges.add(j + 1, edges.get(index));
+
+ if (j > index) {
+ nodes.remove(index);
+ edges.remove(index);
+ index--;
+ }
+ else {
+ nodes.remove(index + 1);
+ edges.remove(index + 1);
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // translate indices back into edges
+ List<List<StatEdge>> lstEdges = new ArrayList<List<StatEdge>>();
+ List<List<ConstExprent>> lstValues = new ArrayList<List<ConstExprent>>();
+
+ for (List<Integer> lst : edges) {
+ List<StatEdge> lste = new ArrayList<StatEdge>();
+ List<ConstExprent> lstv = new ArrayList<ConstExprent>();
+
+ List<StatEdge> lstSuccs = first.getSuccessorEdges(STATEDGE_DIRECT_ALL);
+ for (Integer in : lst) {
+ int index = in == lstSuccs.size() ? 0 : in;
+
+ lste.add(lstSuccs.get(index));
+ lstv.add(index == 0 ? null : new ConstExprent(values[index - 1], false));
+ }
+ lstEdges.add(lste);
+ lstValues.add(lstv);
+ }
+
+ // replace null statements with dummy basic blocks
+ for (int i = 0; i < nodes.size(); i++) {
+ if (nodes.get(i) == null) {
+ BasicBlockStatement bstat = new BasicBlockStatement(new BasicBlock(
+ DecompilerContext.getCounterContainer().getCounterAndIncrement(CounterContainer.STATEMENT_COUNTER)));
+
+ StatEdge sample_edge = lstEdges.get(i).get(0);
+
+ bstat.addSuccessor(new StatEdge(sample_edge.getType(), bstat, sample_edge.getDestination(), sample_edge.closure));
+
+ for (StatEdge edge : lstEdges.get(i)) {
+
+ edge.getSource().changeEdgeType(DIRECTION_FORWARD, edge, StatEdge.TYPE_REGULAR);
+ edge.closure.getLabelEdges().remove(edge);
+
+ edge.getDestination().removePredecessor(edge);
+ edge.getSource().changeEdgeNode(DIRECTION_FORWARD, edge, bstat);
+ bstat.addPredecessor(edge);
+ }
+
+ nodes.set(i, bstat);
+ stats.addWithKey(bstat, bstat.id);
+ bstat.setParent(this);
+ }
+ }
+
+ caseStatements = nodes;
+ caseEdges = lstEdges;
+ caseValues = lstValues;
+ }
+
+ public List<Exprent> getHeadexprentList() {
+ return headexprent;
+ }
+
+ public Exprent getHeadexprent() {
+ return headexprent.get(0);
+ }
+
+ public List<List<StatEdge>> getCaseEdges() {
+ return caseEdges;
+ }
+
+ public List<Statement> getCaseStatements() {
+ return caseStatements;
+ }
+
+ public StatEdge getDefault_edge() {
+ return default_edge;
+ }
+
+ public List<List<ConstExprent>> getCaseValues() {
+ return caseValues;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SynchronizedStatement.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SynchronizedStatement.java
new file mode 100644
index 000000000000..6e3dc4704175
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/stats/SynchronizedStatement.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.stats;
+
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.modules.decompiler.ExprProcessor;
+import org.jetbrains.java.decompiler.modules.decompiler.SequenceHelper;
+import org.jetbrains.java.decompiler.modules.decompiler.StatEdge;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class SynchronizedStatement extends Statement {
+
+ private Statement body;
+
+ private List<Exprent> headexprent = new ArrayList<Exprent>();
+
+ // *****************************************************************************
+ // constructors
+ // *****************************************************************************
+
+ public SynchronizedStatement() {
+ type = TYPE_SYNCRONIZED;
+
+ headexprent.add(null);
+ }
+
+ public SynchronizedStatement(Statement head, Statement body, Statement exc) {
+
+ this();
+
+ first = head;
+ stats.addWithKey(head, head.id);
+
+ this.body = body;
+ stats.addWithKey(body, body.id);
+
+ stats.addWithKey(exc, exc.id);
+
+ List<StatEdge> lstSuccs = body.getSuccessorEdges(STATEDGE_DIRECT_ALL);
+ if (!lstSuccs.isEmpty()) {
+ StatEdge edge = lstSuccs.get(0);
+ if (edge.getType() == StatEdge.TYPE_REGULAR) {
+ post = edge.getDestination();
+ }
+ }
+ }
+
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public String toJava(int indent) {
+ String indstr = InterpreterUtil.getIndentString(indent);
+
+ String new_line_separator = DecompilerContext.getNewLineSeparator();
+
+ StringBuilder buf = new StringBuilder();
+ buf.append(ExprProcessor.listToJava(varDefinitions, indent));
+ buf.append(first.toJava(indent));
+
+ if (isLabeled()) {
+ buf.append(indstr).append("label").append(this.id).append(":").append(new_line_separator);
+ }
+
+ buf.append(indstr).append(headexprent.get(0).toJava(indent)).append(" {").append(new_line_separator);
+ buf.append(ExprProcessor.jmpWrapper(body, indent + 1, true));
+ buf.append(indstr).append("}").append(new_line_separator);
+
+ return buf.toString();
+ }
+
+ public void initExprents() {
+ headexprent.set(0, first.getExprents().remove(first.getExprents().size() - 1));
+ }
+
+ public List<Object> getSequentialObjects() {
+
+ List<Object> lst = new ArrayList<Object>(stats);
+ lst.add(1, headexprent.get(0));
+
+ return lst;
+ }
+
+ public void replaceExprent(Exprent oldexpr, Exprent newexpr) {
+ if (headexprent.get(0) == oldexpr) {
+ headexprent.set(0, newexpr);
+ }
+ }
+
+ public void replaceStatement(Statement oldstat, Statement newstat) {
+
+ if (body == oldstat) {
+ body = newstat;
+ }
+
+ super.replaceStatement(oldstat, newstat);
+ }
+
+ public void removeExc() {
+ Statement exc = stats.get(2);
+ SequenceHelper.destroyStatementContent(exc, true);
+
+ stats.removeWithKey(exc.id);
+ }
+
+ public Statement getSimpleCopy() {
+ return new SynchronizedStatement();
+ }
+
+ public void initSimpleCopy() {
+ first = stats.get(0);
+ body = stats.get(1);
+ }
+
+ // *****************************************************************************
+ // getter and setter methods
+ // *****************************************************************************
+
+ public Statement getBody() {
+ return body;
+ }
+
+ public void setBody(Statement body) {
+ this.body = body;
+ }
+
+ public List<Exprent> getHeadexprentList() {
+ return headexprent;
+ }
+
+ public Exprent getHeadexprent() {
+ return headexprent.get(0);
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/CheckTypesResult.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/CheckTypesResult.java
new file mode 100644
index 000000000000..08c32ec398f9
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/CheckTypesResult.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.vars;
+
+import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class CheckTypesResult {
+
+ private List<ExprentTypePair> lstMaxTypeExprents = new ArrayList<ExprentTypePair>();
+
+ private List<ExprentTypePair> lstMinTypeExprents = new ArrayList<ExprentTypePair>();
+
+ public void addMaxTypeExprent(Exprent exprent, VarType type) {
+ lstMaxTypeExprents.add(new ExprentTypePair(exprent, type, null));
+ }
+
+ public void addMinTypeExprent(Exprent exprent, VarType type) {
+ lstMinTypeExprents.add(new ExprentTypePair(exprent, type, null));
+ }
+
+ public List<ExprentTypePair> getLstMaxTypeExprents() {
+ return lstMaxTypeExprents;
+ }
+
+ public List<ExprentTypePair> getLstMinTypeExprents() {
+ return lstMinTypeExprents;
+ }
+
+ public static class ExprentTypePair {
+ public Exprent exprent;
+ public VarType type;
+ public VarType desttype;
+
+ public ExprentTypePair(Exprent exprent, VarType type, VarType desttype) {
+ this.exprent = exprent;
+ this.type = type;
+ this.desttype = desttype;
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java
new file mode 100644
index 000000000000..fdd6cd5015f8
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarDefinitionHelper.java
@@ -0,0 +1,355 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.vars;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.main.collectors.VarNamesCollector;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.AssignmentExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.CatchAllStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.CatchStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.DoStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+import org.jetbrains.java.decompiler.struct.StructClass;
+import org.jetbrains.java.decompiler.struct.StructMethod;
+import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
+
+import java.util.*;
+import java.util.Map.Entry;
+
+public class VarDefinitionHelper {
+
+ private HashMap<Integer, Statement> mapVarDefStatements;
+
+ // statement.id, defined vars
+ private HashMap<Integer, HashSet<Integer>> mapStatementVars;
+
+ private HashSet<Integer> implDefVars;
+
+ private VarProcessor varproc;
+
+ public VarDefinitionHelper(Statement root, StructMethod mt, VarProcessor varproc) {
+
+ mapVarDefStatements = new HashMap<Integer, Statement>();
+ mapStatementVars = new HashMap<Integer, HashSet<Integer>>();
+ implDefVars = new HashSet<Integer>();
+
+ this.varproc = varproc;
+
+ VarNamesCollector vc = DecompilerContext.getVarNamesCollector();
+
+ boolean thisvar = !mt.hasModifier(CodeConstants.ACC_STATIC);
+
+ MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
+
+ int paramcount = 0;
+ if (thisvar) {
+ paramcount = 1;
+ }
+ paramcount += md.params.length;
+
+
+ // method parameters are implicitly defined
+ int varindex = 0;
+ for (int i = 0; i < paramcount; i++) {
+ implDefVars.add(varindex);
+ varproc.setVarName(new VarVersionPaar(varindex, 0), vc.getFreeName(varindex));
+
+ if (thisvar) {
+ if (i == 0) {
+ varindex++;
+ }
+ else {
+ varindex += md.params[i - 1].stack_size;
+ }
+ }
+ else {
+ varindex += md.params[i].stack_size;
+ }
+ }
+
+ if (thisvar) {
+ StructClass current_class = (StructClass)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS);
+
+ varproc.getThisvars().put(new VarVersionPaar(0, 0), current_class.qualifiedName);
+ varproc.setVarName(new VarVersionPaar(0, 0), "this");
+ vc.addName("this");
+ }
+
+ // catch variables are implicitly defined
+ LinkedList<Statement> stack = new LinkedList<Statement>();
+ stack.add(root);
+
+ while (!stack.isEmpty()) {
+ Statement st = stack.removeFirst();
+
+ List<VarExprent> lstVars = null;
+ if (st.type == Statement.TYPE_CATCHALL) {
+ lstVars = ((CatchAllStatement)st).getVars();
+ }
+ else if (st.type == Statement.TYPE_TRYCATCH) {
+ lstVars = ((CatchStatement)st).getVars();
+ }
+
+ if (lstVars != null) {
+ for (VarExprent var : lstVars) {
+ implDefVars.add(var.getIndex());
+ varproc.setVarName(new VarVersionPaar(var), vc.getFreeName(var.getIndex()));
+ var.setDefinition(true);
+ }
+ }
+
+ stack.addAll(st.getStats());
+ }
+
+ initStatement(root);
+ }
+
+
+ public void setVarDefinitions() {
+
+ VarNamesCollector vc = DecompilerContext.getVarNamesCollector();
+
+ for (Entry<Integer, Statement> en : mapVarDefStatements.entrySet()) {
+ Statement stat = en.getValue();
+ Integer index = en.getKey();
+
+ if (implDefVars.contains(index)) {
+ // already implicitly defined
+ continue;
+ }
+
+ varproc.setVarName(new VarVersionPaar(index.intValue(), 0), vc.getFreeName(index));
+
+ // special case for
+ if (stat.type == Statement.TYPE_DO) {
+ DoStatement dstat = (DoStatement)stat;
+ if (dstat.getLooptype() == DoStatement.LOOP_FOR) {
+
+ if (dstat.getInitExprent() != null && setDefinition(dstat.getInitExprent(), index)) {
+ continue;
+ }
+ else {
+ List<Exprent> lstSpecial = Arrays.asList(dstat.getConditionExprent(), dstat.getIncExprent());
+ for (VarExprent var : getAllVars(lstSpecial)) {
+ if (var.getIndex() == index.intValue()) {
+ stat = stat.getParent();
+ break;
+ }
+ }
+ }
+ }
+ }
+
+
+ Statement first = findFirstBlock(stat, index);
+
+ List<Exprent> lst;
+ if (first == null) {
+ lst = stat.getVarDefinitions();
+ }
+ else if (first.getExprents() == null) {
+ lst = first.getVarDefinitions();
+ }
+ else {
+ lst = first.getExprents();
+ }
+
+
+ boolean defset = false;
+
+ // search for the first assignement to var [index]
+ int addindex = 0;
+ for (Exprent expr : lst) {
+ if (setDefinition(expr, index)) {
+ defset = true;
+ break;
+ }
+ else {
+ boolean foundvar = false;
+ for (Exprent exp : expr.getAllExprents(true)) {
+ if (exp.type == Exprent.EXPRENT_VAR && ((VarExprent)exp).getIndex() == index) {
+ foundvar = true;
+ break;
+ }
+ }
+ if (foundvar) {
+ break;
+ }
+ }
+ addindex++;
+ }
+
+ if (!defset) {
+ VarExprent var = new VarExprent(index.intValue(), varproc.getVarType(new VarVersionPaar(index.intValue(), 0)), varproc);
+ var.setDefinition(true);
+
+ lst.add(addindex, var);
+ }
+ }
+ }
+
+
+ // *****************************************************************************
+ // private methods
+ // *****************************************************************************
+
+ private Statement findFirstBlock(Statement stat, Integer varindex) {
+
+ LinkedList<Statement> stack = new LinkedList<Statement>();
+ stack.add(stat);
+
+ while (!stack.isEmpty()) {
+ Statement st = stack.remove(0);
+
+ if (stack.isEmpty() || mapStatementVars.get(st.id).contains(varindex)) {
+
+ if (st.isLabeled() && !stack.isEmpty()) {
+ return st;
+ }
+
+ if (st.getExprents() != null) {
+ return st;
+ }
+ else {
+ stack.clear();
+
+ switch (st.type) {
+ case Statement.TYPE_SEQUENCE:
+ stack.addAll(0, st.getStats());
+ break;
+ case Statement.TYPE_IF:
+ case Statement.TYPE_ROOT:
+ case Statement.TYPE_SWITCH:
+ case Statement.TYPE_SYNCRONIZED:
+ stack.add(st.getFirst());
+ break;
+ default:
+ return st;
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private Set<Integer> initStatement(Statement stat) {
+
+ HashMap<Integer, Integer> mapCount = new HashMap<Integer, Integer>();
+
+ List<VarExprent> condlst;
+
+ if (stat.getExprents() == null) {
+
+ // recurse on children statements
+ List<Integer> childVars = new ArrayList<Integer>();
+ List<Exprent> currVars = new ArrayList<Exprent>();
+
+ for (Object obj : stat.getSequentialObjects()) {
+ if (obj instanceof Statement) {
+ Statement st = (Statement)obj;
+ childVars.addAll(initStatement(st));
+
+ if (st.type == DoStatement.TYPE_DO) {
+ DoStatement dost = (DoStatement)st;
+ if (dost.getLooptype() != DoStatement.LOOP_FOR &&
+ dost.getLooptype() != DoStatement.LOOP_DO) {
+ currVars.add(dost.getConditionExprent());
+ }
+ }
+ else if (st.type == DoStatement.TYPE_CATCHALL) {
+ CatchAllStatement fin = (CatchAllStatement)st;
+ if (fin.isFinally() && fin.getMonitor() != null) {
+ currVars.add(fin.getMonitor());
+ }
+ }
+ }
+ else if (obj instanceof Exprent) {
+ currVars.add((Exprent)obj);
+ }
+ }
+
+ // children statements
+ for (Integer index : childVars) {
+ Integer count = mapCount.get(index);
+ if (count == null) {
+ count = new Integer(0);
+ }
+ mapCount.put(index, new Integer(count.intValue() + 1));
+ }
+
+ condlst = getAllVars(currVars);
+ }
+ else {
+ condlst = getAllVars(stat.getExprents());
+ }
+
+ // this statement
+ for (VarExprent var : condlst) {
+ mapCount.put(new Integer(var.getIndex()), new Integer(2));
+ }
+
+
+ HashSet<Integer> set = new HashSet<Integer>(mapCount.keySet());
+
+ // put all variables defined in this statement into the set
+ for (Entry<Integer, Integer> en : mapCount.entrySet()) {
+ if (en.getValue().intValue() > 1) {
+ mapVarDefStatements.put(en.getKey(), stat);
+ }
+ }
+
+ mapStatementVars.put(stat.id, set);
+
+ return set;
+ }
+
+ private static List<VarExprent> getAllVars(List<Exprent> lst) {
+
+ List<VarExprent> res = new ArrayList<VarExprent>();
+ List<Exprent> listTemp = new ArrayList<Exprent>();
+
+ for (Exprent expr : lst) {
+ listTemp.addAll(expr.getAllExprents(true));
+ listTemp.add(expr);
+ }
+
+ for (Exprent exprent : listTemp) {
+ if (exprent.type == Exprent.EXPRENT_VAR) {
+ res.add((VarExprent)exprent);
+ }
+ }
+
+ return res;
+ }
+
+ private static boolean setDefinition(Exprent expr, Integer index) {
+ if (expr.type == Exprent.EXPRENT_ASSIGNMENT) {
+ Exprent left = ((AssignmentExprent)expr).getLeft();
+ if (left.type == Exprent.EXPRENT_VAR) {
+ VarExprent var = (VarExprent)left;
+ if (var.getIndex() == index.intValue()) {
+ var.setDefinition(true);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarProcessor.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarProcessor.java
new file mode 100644
index 000000000000..266ba94e1cda
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarProcessor.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.vars;
+
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.main.collectors.VarNamesCollector;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+import org.jetbrains.java.decompiler.struct.StructMethod;
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+
+import java.util.*;
+import java.util.Map.Entry;
+
+
+public class VarProcessor {
+
+ private HashMap<VarVersionPaar, String> mapVarNames = new HashMap<VarVersionPaar, String>();
+
+ private VarVersionsProcessor varvers;
+
+ private HashMap<VarVersionPaar, String> thisvars = new HashMap<VarVersionPaar, String>();
+
+ private HashSet<VarVersionPaar> externvars = new HashSet<VarVersionPaar>();
+
+ public void setVarVersions(RootStatement root) {
+
+ varvers = new VarVersionsProcessor();
+ varvers.setVarVersions(root);
+ }
+
+ public void setVarDefinitions(Statement root) {
+ mapVarNames = new HashMap<VarVersionPaar, String>();
+
+ VarDefinitionHelper defproc = new VarDefinitionHelper(root,
+ (StructMethod)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD),
+ this);
+ defproc.setVarDefinitions();
+ }
+
+ public void setDebugVarNames(Map<Integer, String> mapDebugVarNames) {
+ if (varvers == null) {
+ return;
+ }
+
+ HashMap<Integer, Integer> mapOriginalVarIndices = varvers.getMapOriginalVarIndices();
+
+ List<VarVersionPaar> listVars = new ArrayList<VarVersionPaar>(mapVarNames.keySet());
+ Collections.sort(listVars, new Comparator<VarVersionPaar>() {
+ public int compare(VarVersionPaar o1, VarVersionPaar o2) {
+ return o1.var > o2.var ? 1 : (o1.var == o2.var ? 0 : -1);
+ }
+ });
+
+ HashMap<String, Integer> mapNames = new HashMap<String, Integer>();
+
+ for (VarVersionPaar varpaar : listVars) {
+ String name = mapVarNames.get(varpaar);
+
+ Integer orindex = mapOriginalVarIndices.get(varpaar.var);
+ if (orindex != null && mapDebugVarNames.containsKey(orindex)) {
+ name = mapDebugVarNames.get(orindex);
+ }
+
+ Integer counter = mapNames.get(name);
+ mapNames.put(name, counter == null ? counter = new Integer(0) : ++counter);
+
+ if (counter > 0) {
+ name += String.valueOf(counter);
+ }
+
+ mapVarNames.put(varpaar, name);
+ }
+ }
+
+ public void refreshVarNames(VarNamesCollector vc) {
+
+ HashMap<VarVersionPaar, String> tempVarNames = new HashMap<VarVersionPaar, String>(mapVarNames);
+ for (Entry<VarVersionPaar, String> ent : tempVarNames.entrySet()) {
+ mapVarNames.put(ent.getKey(), vc.getFreeName(ent.getValue()));
+ }
+ }
+
+
+ public VarType getVarType(VarVersionPaar varpaar) {
+ return varvers == null ? null : varvers.getVarType(varpaar);
+ }
+
+ public void setVarType(VarVersionPaar varpaar, VarType type) {
+ varvers.setVarType(varpaar, type);
+ }
+
+ public String getVarName(VarVersionPaar varpaar) {
+ return mapVarNames == null ? null : mapVarNames.get(varpaar);
+ }
+
+ public void setVarName(VarVersionPaar varpaar, String name) {
+ mapVarNames.put(varpaar, name);
+ }
+
+ public int getVarFinal(VarVersionPaar varpaar) {
+ return varvers == null ? VarTypeProcessor.VAR_FINAL : varvers.getVarFinal(varpaar);
+ }
+
+ public void setVarFinal(VarVersionPaar varpaar, int finaltype) {
+ varvers.setVarFinal(varpaar, finaltype);
+ }
+
+ public HashMap<VarVersionPaar, String> getThisvars() {
+ return thisvars;
+ }
+
+ public HashSet<VarVersionPaar> getExternvars() {
+ return externvars;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarTypeProcessor.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarTypeProcessor.java
new file mode 100644
index 000000000000..a21d71f7e9f7
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarTypeProcessor.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.vars;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
+import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectGraph;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.CatchAllStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.CatchStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.Statement;
+import org.jetbrains.java.decompiler.struct.StructClass;
+import org.jetbrains.java.decompiler.struct.StructMethod;
+import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+
+public class VarTypeProcessor {
+
+ public static final int VAR_NONFINAL = 1;
+ public static final int VAR_FINALEXPLICIT = 2;
+ public static final int VAR_FINAL = 3;
+
+ private HashMap<VarVersionPaar, VarType> mapExprentMinTypes = new HashMap<VarVersionPaar, VarType>();
+
+ private HashMap<VarVersionPaar, VarType> mapExprentMaxTypes = new HashMap<VarVersionPaar, VarType>();
+
+ private HashMap<VarVersionPaar, Integer> mapFinalVars = new HashMap<VarVersionPaar, Integer>();
+
+ private void setInitVars(RootStatement root) {
+
+ StructMethod mt = (StructMethod)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD);
+
+ // method descriptor
+ boolean thisvar = !mt.hasModifier(CodeConstants.ACC_STATIC);
+
+ MethodDescriptor md = (MethodDescriptor)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD_DESCRIPTOR);
+
+ if (thisvar) {
+ VarType cltype = new VarType(CodeConstants.TYPE_OBJECT, 0,
+ ((StructClass)DecompilerContext.getProperty(DecompilerContext.CURRENT_CLASS)).qualifiedName);
+ mapExprentMinTypes.put(new VarVersionPaar(0, 1), cltype);
+ mapExprentMaxTypes.put(new VarVersionPaar(0, 1), cltype);
+ }
+
+ int varindex = 0;
+ for (int i = 0; i < md.params.length; i++) {
+ mapExprentMinTypes.put(new VarVersionPaar(varindex + (thisvar ? 1 : 0), 1), md.params[i]);
+ mapExprentMaxTypes.put(new VarVersionPaar(varindex + (thisvar ? 1 : 0), 1), md.params[i]);
+ varindex += md.params[i].stack_size;
+ }
+
+ // catch variables
+ LinkedList<Statement> stack = new LinkedList<Statement>();
+ stack.add(root);
+
+ while (!stack.isEmpty()) {
+ Statement stat = stack.removeFirst();
+
+ List<VarExprent> lstVars = null;
+ if (stat.type == Statement.TYPE_CATCHALL) {
+ lstVars = ((CatchAllStatement)stat).getVars();
+ }
+ else if (stat.type == Statement.TYPE_TRYCATCH) {
+ lstVars = ((CatchStatement)stat).getVars();
+ }
+
+ if (lstVars != null) {
+ for (VarExprent var : lstVars) {
+ mapExprentMinTypes.put(new VarVersionPaar(var.getIndex(), 1), var.getVartype());
+ mapExprentMaxTypes.put(new VarVersionPaar(var.getIndex(), 1), var.getVartype());
+ }
+ }
+
+ stack.addAll(stat.getStats());
+ }
+ }
+
+ public void calculateVarTypes(RootStatement root, DirectGraph dgraph) {
+
+ setInitVars(root);
+
+ resetExprentTypes(dgraph);
+
+ while (!processVarTypes(dgraph)) ;
+ }
+
+ private static void resetExprentTypes(DirectGraph dgraph) {
+
+ dgraph.iterateExprents(new DirectGraph.ExprentIterator() {
+ public int processExprent(Exprent exprent) {
+ List<Exprent> lst = exprent.getAllExprents(true);
+ lst.add(exprent);
+
+ for (Exprent expr : lst) {
+ if (expr.type == Exprent.EXPRENT_VAR) {
+ ((VarExprent)expr).setVartype(VarType.VARTYPE_UNKNOWN);
+ }
+ else if (expr.type == Exprent.EXPRENT_CONST) {
+ ConstExprent cexpr = (ConstExprent)expr;
+ if (cexpr.getConsttype().type_family == CodeConstants.TYPE_FAMILY_INTEGER) {
+ cexpr.setConsttype(new ConstExprent(cexpr.getIntValue(), cexpr.isBoolPermitted()).getConsttype());
+ }
+ }
+ }
+ return 0;
+ }
+ });
+ }
+
+ private boolean processVarTypes(DirectGraph dgraph) {
+
+ return dgraph.iterateExprents(new DirectGraph.ExprentIterator() {
+ public int processExprent(Exprent exprent) {
+ return checkTypeExprent(exprent) ? 0 : 1;
+ }
+ });
+ }
+
+
+ private boolean checkTypeExprent(Exprent exprent) {
+
+ for (Exprent expr : exprent.getAllExprents()) {
+ if (!checkTypeExprent(expr)) {
+ return false;
+ }
+ }
+
+ if (exprent.type == Exprent.EXPRENT_CONST) {
+ ConstExprent cexpr = (ConstExprent)exprent;
+ if (cexpr.getConsttype().type_family <= CodeConstants.TYPE_FAMILY_INTEGER) { // boolean or integer
+ VarVersionPaar cpaar = new VarVersionPaar(cexpr.id, -1);
+ if (!mapExprentMinTypes.containsKey(cpaar)) {
+ mapExprentMinTypes.put(cpaar, cexpr.getConsttype());
+ }
+ }
+ }
+
+ CheckTypesResult result = exprent.checkExprTypeBounds();
+
+ for (CheckTypesResult.ExprentTypePair entry : result.getLstMaxTypeExprents()) {
+ if (entry.type.type_family != CodeConstants.TYPE_FAMILY_OBJECT) {
+ changeExprentType(entry.exprent, entry.type, 1);
+ }
+ }
+
+ boolean res = true;
+ for (CheckTypesResult.ExprentTypePair entry : result.getLstMinTypeExprents()) {
+ res &= changeExprentType(entry.exprent, entry.type, 0);
+ }
+
+ return res;
+ }
+
+
+ private boolean changeExprentType(Exprent exprent, VarType newtype, int minmax) {
+
+ boolean res = true;
+
+ switch (exprent.type) {
+ case Exprent.EXPRENT_CONST:
+ ConstExprent cexpr = (ConstExprent)exprent;
+ VarType consttype = cexpr.getConsttype();
+
+ if (newtype.type_family > CodeConstants.TYPE_FAMILY_INTEGER || consttype.type_family > CodeConstants.TYPE_FAMILY_INTEGER) {
+ return true;
+ }
+ else if (newtype.type_family == CodeConstants.TYPE_FAMILY_INTEGER) {
+ VarType mininteger = new ConstExprent((Integer)((ConstExprent)exprent).getValue(), false).getConsttype();
+ if (mininteger.isStrictSuperset(newtype)) {
+ newtype = mininteger;
+ }
+ }
+ case Exprent.EXPRENT_VAR:
+ VarVersionPaar varpaar = null;
+ if (exprent.type == Exprent.EXPRENT_CONST) {
+ varpaar = new VarVersionPaar(((ConstExprent)exprent).id, -1);
+ }
+ else if (exprent.type == Exprent.EXPRENT_VAR) {
+ varpaar = new VarVersionPaar((VarExprent)exprent);
+ }
+
+ if (minmax == 0) { // min
+ VarType currentMinType = mapExprentMinTypes.get(varpaar);
+ VarType newMinType;
+ if (currentMinType == null || newtype.type_family > currentMinType.type_family) {
+ newMinType = newtype;
+ }
+ else if (newtype.type_family < currentMinType.type_family) {
+ return true;
+ }
+ else {
+ newMinType = VarType.getCommonSupertype(currentMinType, newtype);
+ }
+
+ mapExprentMinTypes.put(varpaar, newMinType);
+ if (exprent.type == Exprent.EXPRENT_CONST) {
+ ((ConstExprent)exprent).setConsttype(newMinType);
+ }
+
+ if (currentMinType != null && (newMinType.type_family > currentMinType.type_family ||
+ newMinType.isStrictSuperset(currentMinType))) {
+ return false;
+ }
+ }
+ else { // max
+ VarType currentMaxType = mapExprentMaxTypes.get(varpaar);
+ VarType newMaxType;
+ if (currentMaxType == null || newtype.type_family < currentMaxType.type_family) {
+ newMaxType = newtype;
+ }
+ else if (newtype.type_family > currentMaxType.type_family) {
+ return true;
+ }
+ else {
+ newMaxType = VarType.getCommonMinType(currentMaxType, newtype);
+ }
+
+ mapExprentMaxTypes.put(varpaar, newMaxType);
+ }
+ break;
+ case Exprent.EXPRENT_ASSIGNMENT:
+ return changeExprentType(((AssignmentExprent)exprent).getRight(), newtype, minmax);
+ case Exprent.EXPRENT_FUNCTION:
+ FunctionExprent func = (FunctionExprent)exprent;
+ switch (func.getFunctype()) {
+ case FunctionExprent.FUNCTION_IIF: // FIXME:
+ res &= changeExprentType(func.getLstOperands().get(1), newtype, minmax);
+ res &= changeExprentType(func.getLstOperands().get(2), newtype, minmax);
+ break;
+ case FunctionExprent.FUNCTION_AND:
+ case FunctionExprent.FUNCTION_OR:
+ case FunctionExprent.FUNCTION_XOR:
+ res &= changeExprentType(func.getLstOperands().get(0), newtype, minmax);
+ res &= changeExprentType(func.getLstOperands().get(1), newtype, minmax);
+ }
+ }
+
+ return res;
+ }
+
+ public HashMap<VarVersionPaar, VarType> getMapExprentMaxTypes() {
+ return mapExprentMaxTypes;
+ }
+
+ public HashMap<VarVersionPaar, VarType> getMapExprentMinTypes() {
+ return mapExprentMinTypes;
+ }
+
+ public HashMap<VarVersionPaar, Integer> getMapFinalVars() {
+ return mapFinalVars;
+ }
+
+ public void setVarType(VarVersionPaar varpaar, VarType type) {
+ mapExprentMinTypes.put(varpaar, type);
+ }
+
+ public VarType getVarType(VarVersionPaar varpaar) {
+ return mapExprentMinTypes.get(varpaar);
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionEdge.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionEdge.java
new file mode 100644
index 000000000000..9d9798279d41
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionEdge.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.vars;
+
+public class VarVersionEdge { // FIXME: can be removed?
+
+ public static final int EDGE_GENERAL = 0;
+ public static final int EDGE_PHANTOM = 1;
+
+ public int type;
+
+ public VarVersionNode source;
+
+ public VarVersionNode dest;
+
+ private int hashCode;
+
+ public VarVersionEdge(int type, VarVersionNode source, VarVersionNode dest) {
+ this.type = type;
+ this.source = source;
+ this.dest = dest;
+ this.hashCode = source.hashCode() ^ dest.hashCode() + type;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof VarVersionEdge)) return false;
+
+ VarVersionEdge edge = (VarVersionEdge)o;
+ return type == edge.type && source == edge.source && dest == edge.dest;
+ }
+
+ @Override
+ public int hashCode() {
+ return hashCode;
+ }
+
+ @Override
+ public String toString() {
+ return source.toString() + " ->" + type + "-> " + dest.toString();
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionNode.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionNode.java
new file mode 100644
index 000000000000..587c653dc3fb
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionNode.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.vars;
+
+import org.jetbrains.java.decompiler.modules.decompiler.decompose.IGraphNode;
+import org.jetbrains.java.decompiler.util.SFormsFastMapDirect;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class VarVersionNode implements IGraphNode {
+
+ public static final int FLAG_PHANTOM_FINEXIT = 2;
+
+ public int var;
+
+ public int version;
+
+ public Set<VarVersionEdge> succs = new HashSet<VarVersionEdge>();
+
+ public Set<VarVersionEdge> preds = new HashSet<VarVersionEdge>();
+
+ public int flags;
+
+ public SFormsFastMapDirect live = new SFormsFastMapDirect();
+
+
+ public VarVersionNode(int var, int version) {
+ this.var = var;
+ this.version = version;
+ }
+
+ public VarVersionPaar getVarPaar() {
+ return new VarVersionPaar(var, version);
+ }
+
+ public List<IGraphNode> getPredecessors() {
+ List<IGraphNode> lst = new ArrayList<IGraphNode>(preds.size());
+ for (VarVersionEdge edge : preds) {
+ lst.add(edge.source);
+ }
+ return lst;
+ }
+
+ public void removeSuccessor(VarVersionEdge edge) {
+ succs.remove(edge);
+ }
+
+ public void removePredecessor(VarVersionEdge edge) {
+ preds.remove(edge);
+ }
+
+ public void addSuccessor(VarVersionEdge edge) {
+ succs.add(edge);
+ }
+
+ public void addPredecessor(VarVersionEdge edge) {
+ preds.add(edge);
+ }
+
+ @Override
+ public String toString() {
+ return "(" + var + "_" + version + ")";
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionPaar.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionPaar.java
new file mode 100644
index 000000000000..5f3e520a84d0
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionPaar.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.vars;
+
+import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent;
+
+public class VarVersionPaar {
+
+ public int var;
+ public int version;
+
+ private int hashCode = -1;
+
+ public VarVersionPaar(int var, int version) {
+ this.var = var;
+ this.version = version;
+ }
+
+ public VarVersionPaar(Integer var, Integer version) {
+ this.var = var.intValue();
+ this.version = version.intValue();
+ }
+
+ public VarVersionPaar(VarExprent var) {
+ this.var = var.getIndex();
+ this.version = var.getVersion();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof VarVersionPaar)) return false;
+
+ VarVersionPaar paar = (VarVersionPaar)o;
+ return var == paar.var && version == paar.version;
+ }
+
+ @Override
+ public int hashCode() {
+ if (hashCode == -1) {
+ hashCode = this.var * 3 + this.version;
+ }
+ return hashCode;
+ }
+
+ @Override
+ public String toString() {
+ return "(" + var + "," + version + ")";
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsGraph.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsGraph.java
new file mode 100644
index 000000000000..f839a05819df
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsGraph.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.vars;
+
+import org.jetbrains.java.decompiler.modules.decompiler.decompose.GenericDominatorEngine;
+import org.jetbrains.java.decompiler.modules.decompiler.decompose.IGraph;
+import org.jetbrains.java.decompiler.modules.decompiler.decompose.IGraphNode;
+import org.jetbrains.java.decompiler.util.VBStyleCollection;
+
+import java.util.*;
+
+
+public class VarVersionsGraph {
+
+ public int counter = 0;
+
+ public VBStyleCollection<VarVersionNode, VarVersionPaar> nodes = new VBStyleCollection<VarVersionNode, VarVersionPaar>();
+
+ private GenericDominatorEngine engine;
+
+ public VarVersionNode createNode(VarVersionPaar ver) {
+ VarVersionNode node;
+ nodes.addWithKey(node = new VarVersionNode(ver.var, ver.version), ver);
+ return node;
+ }
+
+ public void addNodes(Collection<VarVersionNode> colnodes, Collection<VarVersionPaar> colpaars) {
+ nodes.addAllWithKey(colnodes, colpaars);
+ }
+
+ public boolean isDominatorSet(VarVersionNode node, HashSet<VarVersionNode> domnodes) {
+
+ if (domnodes.size() == 1) {
+ return engine.isDominator(node, domnodes.iterator().next());
+ }
+ else {
+
+ HashSet<VarVersionNode> marked = new HashSet<VarVersionNode>();
+
+ if (domnodes.contains(node)) {
+ return true;
+ }
+
+ LinkedList<VarVersionNode> lstNodes = new LinkedList<VarVersionNode>();
+ lstNodes.add(node);
+
+ while (!lstNodes.isEmpty()) {
+
+ VarVersionNode nd = lstNodes.remove(0);
+ if (marked.contains(nd)) {
+ continue;
+ }
+ else {
+ marked.add(nd);
+ }
+
+ if (nd.preds.isEmpty()) {
+ return false;
+ }
+
+ for (VarVersionEdge edge : nd.preds) {
+ VarVersionNode pred = edge.source;
+ if (!marked.contains(pred) && !domnodes.contains(pred)) {
+ lstNodes.add(pred);
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public void initDominators() {
+
+ final HashSet<VarVersionNode> roots = new HashSet<VarVersionNode>();
+
+ for (VarVersionNode node : nodes) {
+ if (node.preds.isEmpty()) {
+ roots.add(node);
+ }
+ }
+
+ engine = new GenericDominatorEngine(new IGraph() {
+ public List<? extends IGraphNode> getReversePostOrderList() {
+ return getReversedPostOrder(roots);
+ }
+
+ public Set<? extends IGraphNode> getRoots() {
+ return new HashSet<IGraphNode>(roots);
+ }
+ });
+
+ engine.initialize();
+ }
+
+ private static LinkedList<VarVersionNode> getReversedPostOrder(Collection<VarVersionNode> roots) {
+
+ LinkedList<VarVersionNode> lst = new LinkedList<VarVersionNode>();
+ HashSet<VarVersionNode> setVisited = new HashSet<VarVersionNode>();
+
+ for (VarVersionNode root : roots) {
+
+ LinkedList<VarVersionNode> lstTemp = new LinkedList<VarVersionNode>();
+ addToReversePostOrderListIterative(root, lstTemp, setVisited);
+
+ lst.addAll(lstTemp);
+ }
+
+ return lst;
+ }
+
+ private static void addToReversePostOrderListIterative(VarVersionNode root, List<VarVersionNode> lst, HashSet<VarVersionNode> setVisited) {
+
+ HashMap<VarVersionNode, List<VarVersionEdge>> mapNodeSuccs = new HashMap<VarVersionNode, List<VarVersionEdge>>();
+
+ LinkedList<VarVersionNode> stackNode = new LinkedList<VarVersionNode>();
+ LinkedList<Integer> stackIndex = new LinkedList<Integer>();
+
+ stackNode.add(root);
+ stackIndex.add(0);
+
+ while (!stackNode.isEmpty()) {
+
+ VarVersionNode node = stackNode.getLast();
+ int index = stackIndex.removeLast();
+
+ setVisited.add(node);
+
+ List<VarVersionEdge> lstSuccs = mapNodeSuccs.get(node);
+ if (lstSuccs == null) {
+ mapNodeSuccs.put(node, lstSuccs = new ArrayList<VarVersionEdge>(node.succs));
+ }
+
+ for (; index < lstSuccs.size(); index++) {
+ VarVersionNode succ = lstSuccs.get(index).dest;
+
+ if (!setVisited.contains(succ)) {
+ stackIndex.add(index + 1);
+
+ stackNode.add(succ);
+ stackIndex.add(0);
+
+ break;
+ }
+ }
+
+ if (index == lstSuccs.size()) {
+ lst.add(0, node);
+
+ stackNode.removeLast();
+ }
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsProcessor.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsProcessor.java
new file mode 100644
index 000000000000..06b7216c86fa
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/decompiler/vars/VarVersionsProcessor.java
@@ -0,0 +1,334 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.decompiler.vars;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.main.collectors.CounterContainer;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.ConstExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent;
+import org.jetbrains.java.decompiler.modules.decompiler.sforms.DirectGraph;
+import org.jetbrains.java.decompiler.modules.decompiler.sforms.FlattenStatementsHelper;
+import org.jetbrains.java.decompiler.modules.decompiler.sforms.SSAConstructorSparseEx;
+import org.jetbrains.java.decompiler.modules.decompiler.stats.RootStatement;
+import org.jetbrains.java.decompiler.struct.StructMethod;
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+import org.jetbrains.java.decompiler.util.FastSparseSetFactory.FastSparseSet;
+
+import java.util.*;
+import java.util.Map.Entry;
+
+public class VarVersionsProcessor {
+
+ private HashMap<Integer, Integer> mapOriginalVarIndices = new HashMap<Integer, Integer>();
+
+ private VarTypeProcessor typeproc;
+
+ public void setVarVersions(RootStatement root) {
+
+ StructMethod mt = (StructMethod)DecompilerContext.getProperty(DecompilerContext.CURRENT_METHOD);
+
+ SSAConstructorSparseEx ssa = new SSAConstructorSparseEx();
+ ssa.splitVariables(root, mt);
+
+ FlattenStatementsHelper flatthelper = new FlattenStatementsHelper();
+ DirectGraph dgraph = flatthelper.buildDirectGraph(root);
+
+ // System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
+
+ mergePhiVersions(ssa, dgraph);
+
+ // System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
+
+ typeproc = new VarTypeProcessor();
+ typeproc.calculateVarTypes(root, dgraph);
+
+ simpleMerge(typeproc, dgraph, mt);
+
+ // FIXME: advanced merging
+
+ eliminateNonJavaTypes(typeproc);
+
+ setNewVarIndices(typeproc, dgraph);
+ }
+
+ private static void mergePhiVersions(SSAConstructorSparseEx ssa, DirectGraph dgraph) {
+
+ // collect phi versions
+ List<HashSet<VarVersionPaar>> lst = new ArrayList<HashSet<VarVersionPaar>>();
+ for (Entry<VarVersionPaar, FastSparseSet<Integer>> ent : ssa.getPhi().entrySet()) {
+ HashSet<VarVersionPaar> set = new HashSet<VarVersionPaar>();
+ set.add(ent.getKey());
+ for (Integer vers : ent.getValue()) {
+ set.add(new VarVersionPaar(ent.getKey().var, vers.intValue()));
+ }
+
+ for (int i = lst.size() - 1; i >= 0; i--) {
+ HashSet<VarVersionPaar> tset = lst.get(i);
+ HashSet<VarVersionPaar> intersection = new HashSet<VarVersionPaar>(set);
+ intersection.retainAll(tset);
+
+ if (!intersection.isEmpty()) {
+ set.addAll(tset);
+ lst.remove(i);
+ }
+ }
+
+ lst.add(set);
+ }
+
+ final HashMap<VarVersionPaar, Integer> phivers = new HashMap<VarVersionPaar, Integer>();
+ for (HashSet<VarVersionPaar> set : lst) {
+ int min = Integer.MAX_VALUE;
+ for (VarVersionPaar paar : set) {
+ if (paar.version < min) {
+ min = paar.version;
+ }
+ }
+
+ for (VarVersionPaar paar : set) {
+ phivers.put(new VarVersionPaar(paar.var, paar.version), min);
+ }
+ }
+
+
+ dgraph.iterateExprents(new DirectGraph.ExprentIterator() {
+ public int processExprent(Exprent exprent) {
+ List<Exprent> lst = exprent.getAllExprents(true);
+ lst.add(exprent);
+
+ for (Exprent expr : lst) {
+ if (expr.type == Exprent.EXPRENT_VAR) {
+ VarExprent var = (VarExprent)expr;
+ Integer vers = phivers.get(new VarVersionPaar(var));
+ if (vers != null) {
+ var.setVersion(vers);
+ }
+ }
+ }
+ return 0;
+ }
+ });
+ }
+
+ private static void eliminateNonJavaTypes(VarTypeProcessor typeproc) {
+
+ HashMap<VarVersionPaar, VarType> mapExprentMaxTypes = typeproc.getMapExprentMaxTypes();
+ HashMap<VarVersionPaar, VarType> mapExprentMinTypes = typeproc.getMapExprentMinTypes();
+
+ HashSet<VarVersionPaar> set = new HashSet<VarVersionPaar>(mapExprentMinTypes.keySet());
+ for (VarVersionPaar paar : set) {
+ VarType type = mapExprentMinTypes.get(paar);
+ VarType maxtype = mapExprentMaxTypes.get(paar);
+
+ if (type.type == CodeConstants.TYPE_BYTECHAR || type.type == CodeConstants.TYPE_SHORTCHAR) {
+ if (maxtype != null && maxtype.type == CodeConstants.TYPE_CHAR) {
+ type = VarType.VARTYPE_CHAR;
+ }
+ else {
+ type = type.type == CodeConstants.TYPE_BYTECHAR ? VarType.VARTYPE_BYTE : VarType.VARTYPE_SHORT;
+ }
+ mapExprentMinTypes.put(paar, type);
+ //} else if(type.type == CodeConstants.TYPE_CHAR && (maxtype == null || maxtype.type == CodeConstants.TYPE_INT)) { // when possible, lift char to int
+ // mapExprentMinTypes.put(paar, VarType.VARTYPE_INT);
+ }
+ else if (type.type == CodeConstants.TYPE_NULL) {
+ mapExprentMinTypes.put(paar, VarType.VARTYPE_OBJECT);
+ }
+ }
+ }
+
+ private static void simpleMerge(VarTypeProcessor typeproc, DirectGraph dgraph, StructMethod mt) {
+
+ HashMap<VarVersionPaar, VarType> mapExprentMaxTypes = typeproc.getMapExprentMaxTypes();
+ HashMap<VarVersionPaar, VarType> mapExprentMinTypes = typeproc.getMapExprentMinTypes();
+
+ HashMap<Integer, HashSet<Integer>> mapVarVersions = new HashMap<Integer, HashSet<Integer>>();
+
+ for (VarVersionPaar varpaar : mapExprentMinTypes.keySet()) {
+ if (varpaar.version >= 0) { // don't merge constants
+ HashSet<Integer> set = mapVarVersions.get(varpaar.var);
+ if (set == null) {
+ set = new HashSet<Integer>();
+ mapVarVersions.put(varpaar.var, set);
+ }
+ set.add(varpaar.version);
+ }
+ }
+
+ boolean is_method_static = mt.hasModifier(CodeConstants.ACC_STATIC);
+
+ final HashMap<VarVersionPaar, Integer> mapMergedVersions = new HashMap<VarVersionPaar, Integer>();
+
+ for (Entry<Integer, HashSet<Integer>> ent : mapVarVersions.entrySet()) {
+
+ if (ent.getValue().size() > 1) {
+ List<Integer> lstVersions = new ArrayList<Integer>(ent.getValue());
+ Collections.sort(lstVersions);
+
+ for (int i = 0; i < lstVersions.size(); i++) {
+ VarVersionPaar firstpaar = new VarVersionPaar(ent.getKey(), lstVersions.get(i));
+ VarType firsttype = mapExprentMinTypes.get(firstpaar);
+
+ if (firstpaar.var == 0 && firstpaar.version == 1 && !is_method_static) {
+ continue; // don't merge 'this' variable
+ }
+
+ for (int j = i + 1; j < lstVersions.size(); j++) {
+ VarVersionPaar secpaar = new VarVersionPaar(ent.getKey(), lstVersions.get(j));
+ VarType sectype = mapExprentMinTypes.get(secpaar);
+
+ if (firsttype.equals(sectype) || (firsttype.equals(VarType.VARTYPE_NULL) && sectype.type == CodeConstants.TYPE_OBJECT)
+ || (sectype.equals(VarType.VARTYPE_NULL) && firsttype.type == CodeConstants.TYPE_OBJECT)) {
+
+ VarType firstMaxType = mapExprentMaxTypes.get(firstpaar);
+ VarType secMaxType = mapExprentMaxTypes.get(secpaar);
+ mapExprentMaxTypes.put(firstpaar, firstMaxType == null ? secMaxType :
+ (secMaxType == null ? firstMaxType : VarType.getCommonMinType(firstMaxType, secMaxType)));
+
+
+ mapMergedVersions.put(secpaar, firstpaar.version);
+ mapExprentMaxTypes.remove(secpaar);
+ mapExprentMinTypes.remove(secpaar);
+
+ if (firsttype.equals(VarType.VARTYPE_NULL)) {
+ mapExprentMinTypes.put(firstpaar, sectype);
+ firsttype = sectype;
+ }
+
+ typeproc.getMapFinalVars().put(firstpaar, VarTypeProcessor.VAR_NONFINAL);
+
+ lstVersions.remove(j);
+ j--;
+ }
+ }
+ }
+ }
+ }
+
+ if (!mapMergedVersions.isEmpty()) {
+ dgraph.iterateExprents(new DirectGraph.ExprentIterator() {
+ public int processExprent(Exprent exprent) {
+ List<Exprent> lst = exprent.getAllExprents(true);
+ lst.add(exprent);
+
+ for (Exprent expr : lst) {
+ if (expr.type == Exprent.EXPRENT_VAR) {
+ VarExprent varex = (VarExprent)expr;
+ Integer newversion = mapMergedVersions.get(new VarVersionPaar(varex));
+ if (newversion != null) {
+ varex.setVersion(newversion);
+ }
+ }
+ }
+
+ return 0;
+ }
+ });
+ }
+ }
+
+ private void setNewVarIndices(VarTypeProcessor typeproc, DirectGraph dgraph) {
+
+ final HashMap<VarVersionPaar, VarType> mapExprentMaxTypes = typeproc.getMapExprentMaxTypes();
+ HashMap<VarVersionPaar, VarType> mapExprentMinTypes = typeproc.getMapExprentMinTypes();
+ HashMap<VarVersionPaar, Integer> mapFinalVars = typeproc.getMapFinalVars();
+
+ CounterContainer ccon = DecompilerContext.getCounterContainer();
+
+ final HashMap<VarVersionPaar, Integer> mapVarPaar = new HashMap<VarVersionPaar, Integer>();
+ HashMap<Integer, Integer> mapOriginalVarIndices = new HashMap<Integer, Integer>();
+
+ // map var-version paars on new var indexes
+ HashSet<VarVersionPaar> set = new HashSet<VarVersionPaar>(mapExprentMinTypes.keySet());
+ for (VarVersionPaar vpaar : set) {
+
+ if (vpaar.version >= 0) {
+ int newindex = vpaar.version == 1 ? vpaar.var :
+ ccon.getCounterAndIncrement(CounterContainer.VAR_COUNTER);
+
+ VarVersionPaar newvar = new VarVersionPaar(newindex, 0);
+
+ mapExprentMinTypes.put(newvar, mapExprentMinTypes.get(vpaar));
+ mapExprentMaxTypes.put(newvar, mapExprentMaxTypes.get(vpaar));
+
+ if (mapFinalVars.containsKey(vpaar)) {
+ mapFinalVars.put(newvar, mapFinalVars.remove(vpaar));
+ }
+
+ mapVarPaar.put(vpaar, newindex);
+ mapOriginalVarIndices.put(newindex, vpaar.var);
+ }
+ }
+
+ // set new vars
+ dgraph.iterateExprents(new DirectGraph.ExprentIterator() {
+ public int processExprent(Exprent exprent) {
+ List<Exprent> lst = exprent.getAllExprents(true);
+ lst.add(exprent);
+
+ for (Exprent expr : lst) {
+ if (expr.type == Exprent.EXPRENT_VAR) {
+ VarExprent varex = (VarExprent)expr;
+ Integer newvarindex = mapVarPaar.get(new VarVersionPaar(varex));
+ if (newvarindex != null) {
+ varex.setIndex(newvarindex);
+ varex.setVersion(0);
+ }
+ }
+ else if (expr.type == Exprent.EXPRENT_CONST) {
+ VarType maxType = mapExprentMaxTypes.get(new VarVersionPaar(expr.id, -1));
+ if (maxType != null && maxType.equals(VarType.VARTYPE_CHAR)) {
+ ((ConstExprent)expr).setConsttype(maxType);
+ }
+ }
+ }
+
+ return 0;
+ }
+ });
+
+ this.mapOriginalVarIndices = mapOriginalVarIndices;
+ }
+
+ public VarType getVarType(VarVersionPaar varpaar) {
+ return typeproc == null ? null : typeproc.getVarType(varpaar);
+ }
+
+ public void setVarType(VarVersionPaar varpaar, VarType type) {
+ typeproc.setVarType(varpaar, type);
+ }
+
+ public int getVarFinal(VarVersionPaar varpaar) {
+
+ int ret = VarTypeProcessor.VAR_FINAL;
+ if (typeproc != null) {
+ Integer fin = typeproc.getMapFinalVars().get(varpaar);
+ ret = fin == null ? VarTypeProcessor.VAR_FINAL : fin.intValue();
+ }
+
+ return ret;
+ }
+
+ public void setVarFinal(VarVersionPaar varpaar, int finaltype) {
+ typeproc.getMapFinalVars().put(varpaar, finaltype);
+ }
+
+ public HashMap<Integer, Integer> getMapOriginalVarIndices() {
+ return mapOriginalVarIndices;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/renamer/ClassWrapperNode.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/renamer/ClassWrapperNode.java
new file mode 100644
index 000000000000..273579a56373
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/renamer/ClassWrapperNode.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.renamer;
+
+import org.jetbrains.java.decompiler.struct.StructClass;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ClassWrapperNode {
+
+ private StructClass classStruct;
+
+ private ClassWrapperNode superclass;
+
+ private List<ClassWrapperNode> subclasses = new ArrayList<ClassWrapperNode>();
+
+ public ClassWrapperNode(StructClass cl) {
+ this.classStruct = cl;
+ }
+
+ public void addSubclass(ClassWrapperNode node) {
+ node.setSuperclass(this);
+ subclasses.add(node);
+ }
+
+ public StructClass getClassStruct() {
+ return classStruct;
+ }
+
+ public List<ClassWrapperNode> getSubclasses() {
+ return subclasses;
+ }
+
+ public ClassWrapperNode getSuperclass() {
+ return superclass;
+ }
+
+ public void setSuperclass(ClassWrapperNode superclass) {
+ this.superclass = superclass;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/renamer/ConverterHelper.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/renamer/ConverterHelper.java
new file mode 100644
index 000000000000..f2cb1ec0e657
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/renamer/ConverterHelper.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.renamer;
+
+import org.jetbrains.java.decompiler.main.extern.IIdentifierRenamer;
+
+import java.util.HashSet;
+
+public class ConverterHelper implements IIdentifierRenamer {
+
+ private static HashSet<String> setReserved = new HashSet<String>();
+
+ static {
+ setReserved.add("abstract");
+ setReserved.add("do");
+ setReserved.add("if");
+ setReserved.add("package");
+ setReserved.add("synchronized");
+ setReserved.add("boolean");
+ setReserved.add("double");
+ setReserved.add("implements");
+ setReserved.add("private");
+ setReserved.add("this");
+ setReserved.add("break");
+ setReserved.add("else");
+ setReserved.add("import");
+ setReserved.add("protected");
+ setReserved.add("throw");
+ setReserved.add("byte");
+ setReserved.add("extends");
+ setReserved.add("instanceof");
+ setReserved.add("public");
+ setReserved.add("throws");
+ setReserved.add("case");
+ setReserved.add("false");
+ setReserved.add("int");
+ setReserved.add("return");
+ setReserved.add("transient");
+ setReserved.add("catch");
+ setReserved.add("final");
+ setReserved.add("interface");
+ setReserved.add("short");
+ setReserved.add("true");
+ setReserved.add("char");
+ setReserved.add("finally");
+ setReserved.add("long");
+ setReserved.add("static");
+ setReserved.add("try");
+ setReserved.add("class");
+ setReserved.add("float");
+ setReserved.add("native");
+ setReserved.add("strictfp");
+ setReserved.add("void");
+ setReserved.add("const");
+ setReserved.add("for");
+ setReserved.add("new");
+ setReserved.add("super");
+ setReserved.add("volatile");
+ setReserved.add("continue");
+ setReserved.add("goto");
+ setReserved.add("null");
+ setReserved.add("switch");
+ setReserved.add("while");
+ setReserved.add("default");
+ setReserved.add("assert");
+ setReserved.add("enum");
+ }
+
+ private int class_counter = 0;
+
+ private int field_counter = 0;
+
+ private int method_counter = 0;
+
+ private HashSet<String> setNonStandardClassNames = new HashSet<String>();
+
+ public boolean toBeRenamed(int element_type, String classname, String element, String descriptor) {
+ String value = (element_type == IIdentifierRenamer.ELEMENT_CLASS) ? classname : element;
+ return value == null || value.length() == 0 || value.length() <= 2 || setReserved.contains(value) || Character.isDigit(value.charAt(0));
+ }
+
+ // TODO: consider possible conflicts with not renamed classes, fields and methods!
+ // We should get all relevant information here.
+ public String getNextClassname(String fullname, String shortname) {
+
+ if (shortname == null) {
+ return "class_" + (class_counter++);
+ }
+
+ int index = 0;
+ while (Character.isDigit(shortname.charAt(index))) {
+ index++;
+ }
+
+ if (index == 0 || index == shortname.length()) {
+ return "class_" + (class_counter++);
+ }
+ else {
+ String name = shortname.substring(index);
+
+ if (setNonStandardClassNames.contains(name)) {
+ return "Inner" + name + "_" + (class_counter++);
+ }
+ else {
+ setNonStandardClassNames.add(name);
+ return "Inner" + name;
+ }
+ }
+ }
+
+ public String getNextFieldname(String classname, String field, String descriptor) {
+ return "field_" + (field_counter++);
+ }
+
+ public String getNextMethodname(String classname, String method, String descriptor) {
+ return "method_" + (method_counter++);
+ }
+
+ // *****************************************************************************
+ // static methods
+ // *****************************************************************************
+
+ public static String getSimpleClassName(String fullname) {
+ return fullname.substring(fullname.lastIndexOf('/') + 1);
+ }
+
+ public static String replaceSimpleClassName(String fullname, String newname) {
+ return fullname.substring(0, fullname.lastIndexOf('/') + 1) + newname;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/renamer/IdentifierConverter.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/renamer/IdentifierConverter.java
new file mode 100644
index 000000000000..9ed3578d3d55
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/renamer/IdentifierConverter.java
@@ -0,0 +1,463 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.renamer;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
+import org.jetbrains.java.decompiler.main.extern.IIdentifierRenamer;
+import org.jetbrains.java.decompiler.struct.StructClass;
+import org.jetbrains.java.decompiler.struct.StructContext;
+import org.jetbrains.java.decompiler.struct.StructField;
+import org.jetbrains.java.decompiler.struct.StructMethod;
+import org.jetbrains.java.decompiler.struct.gen.FieldDescriptor;
+import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+import org.jetbrains.java.decompiler.util.VBStyleCollection;
+
+import java.io.IOException;
+import java.util.*;
+
+public class IdentifierConverter {
+
+ private StructContext context;
+
+ private IIdentifierRenamer helper;
+
+ private PoolInterceptor interceptor;
+
+ private List<ClassWrapperNode> rootClasses = new ArrayList<ClassWrapperNode>();
+
+ private List<ClassWrapperNode> rootInterfaces = new ArrayList<ClassWrapperNode>();
+
+ private HashMap<String, HashMap<String, String>> interfaceNameMaps = new HashMap<String, HashMap<String, String>>();
+
+ public void rename(StructContext context) {
+
+ try {
+ this.context = context;
+
+ String user_class = (String)DecompilerContext.getProperty(IFernflowerPreferences.USER_RENAMER_CLASS);
+ if (user_class != null) {
+ try {
+ helper = (IIdentifierRenamer)IdentifierConverter.class.getClassLoader().loadClass(user_class).newInstance();
+ }
+ catch (Exception ex) {
+ // ignore errors
+ }
+ }
+
+ if (helper == null) {
+ helper = new ConverterHelper();
+ }
+
+ interceptor = new PoolInterceptor(helper);
+
+ buildInheritanceTree();
+
+ renameAllClasses();
+
+ renameInterfaces();
+
+ renameClasses();
+
+ DecompilerContext.setPoolInterceptor(interceptor);
+ context.reloadContext();
+ }
+ catch (IOException ex) {
+ throw new RuntimeException("Renaming failed!");
+ }
+ }
+
+ private void renameClasses() {
+
+ List<ClassWrapperNode> lstClasses = getReversePostOrderListIterative(rootClasses);
+
+ HashMap<String, HashMap<String, String>> classNameMaps = new HashMap<String, HashMap<String, String>>();
+
+ for (ClassWrapperNode node : lstClasses) {
+
+ StructClass cl = node.getClassStruct();
+ HashMap<String, String> names = new HashMap<String, String>();
+
+ // merge informations on super class
+ if (cl.superClass != null) {
+ HashMap<String, String> mapClass = classNameMaps.get(cl.superClass.getString());
+ if (mapClass != null) {
+ names.putAll(mapClass);
+ }
+ }
+
+ // merge informations on interfaces
+ for (String intrName : cl.getInterfaceNames()) {
+ HashMap<String, String> mapInt = interfaceNameMaps.get(intrName);
+ if (mapInt != null) {
+ names.putAll(mapInt);
+ }
+ else {
+ StructClass clintr = context.getClass(intrName);
+ if (clintr != null) {
+ names.putAll(processExternalInterface(clintr));
+ }
+ }
+ }
+
+ renameClassIdentifiers(cl, names);
+
+ if (!node.getSubclasses().isEmpty()) {
+ classNameMaps.put(cl.qualifiedName, names);
+ }
+ }
+ }
+
+ private HashMap<String, String> processExternalInterface(StructClass cl) {
+
+ HashMap<String, String> names = new HashMap<String, String>();
+
+ for (String intrName : cl.getInterfaceNames()) {
+
+ HashMap<String, String> mapInt = interfaceNameMaps.get(intrName);
+ if (mapInt != null) {
+ names.putAll(mapInt);
+ }
+ else {
+ StructClass clintr = context.getClass(intrName);
+ if (clintr != null) {
+ names.putAll(processExternalInterface(clintr));
+ }
+ }
+ }
+
+ renameClassIdentifiers(cl, names);
+
+ return names;
+ }
+
+ private void renameInterfaces() {
+
+ List<ClassWrapperNode> lstInterfaces = getReversePostOrderListIterative(rootInterfaces);
+
+ HashMap<String, HashMap<String, String>> interfaceNameMaps = new HashMap<String, HashMap<String, String>>();
+
+ // rename methods and fields
+ for (ClassWrapperNode node : lstInterfaces) {
+
+ StructClass cl = node.getClassStruct();
+ HashMap<String, String> names = new HashMap<String, String>();
+
+ // merge informations on super interfaces
+ for (String intrName : cl.getInterfaceNames()) {
+ HashMap<String, String> mapInt = interfaceNameMaps.get(intrName);
+ if (mapInt != null) {
+ names.putAll(mapInt);
+ }
+ }
+
+ renameClassIdentifiers(cl, names);
+
+ interfaceNameMaps.put(cl.qualifiedName, names);
+ }
+
+ this.interfaceNameMaps = interfaceNameMaps;
+ }
+
+ private void renameAllClasses() {
+
+ // order not important
+ List<ClassWrapperNode> lstAllClasses = new ArrayList<ClassWrapperNode>(getReversePostOrderListIterative(rootInterfaces));
+ lstAllClasses.addAll(getReversePostOrderListIterative(rootClasses));
+
+ // rename all interfaces and classes
+ for (ClassWrapperNode node : lstAllClasses) {
+ renameClass(node.getClassStruct());
+ }
+ }
+
+ private void renameClass(StructClass cl) {
+
+ if (!cl.isOwn()) {
+ return;
+ }
+
+ String classOldFullName = cl.qualifiedName;
+
+ // TODO: rename packages
+ String clsimplename = ConverterHelper.getSimpleClassName(classOldFullName);
+ if (helper.toBeRenamed(IIdentifierRenamer.ELEMENT_CLASS, clsimplename, null, null)) {
+ String classNewFullName;
+
+ do {
+ classNewFullName = ConverterHelper.replaceSimpleClassName(classOldFullName,
+ helper.getNextClassname(classOldFullName, ConverterHelper
+ .getSimpleClassName(classOldFullName)));
+ }
+ while (context.getClasses().containsKey(classNewFullName));
+
+ interceptor.addName(classOldFullName, classNewFullName);
+ }
+ }
+
+ private void renameClassIdentifiers(StructClass cl, HashMap<String, String> names) {
+
+ // all classes are already renamed
+ String classOldFullName = cl.qualifiedName;
+ String classNewFullName = interceptor.getName(classOldFullName);
+
+ if (classNewFullName == null) {
+ classNewFullName = classOldFullName;
+ }
+
+ // methods
+ HashSet<String> setMethodNames = new HashSet<String>();
+ for (StructMethod md : cl.getMethods()) {
+ setMethodNames.add(md.getName());
+ }
+
+ VBStyleCollection<StructMethod, String> methods = cl.getMethods();
+ for (int i = 0; i < methods.size(); i++) {
+
+ StructMethod mt = methods.get(i);
+ String key = methods.getKey(i);
+
+ boolean isPrivate = mt.hasModifier(CodeConstants.ACC_PRIVATE);
+
+ String name = mt.getName();
+ if (!cl.isOwn() || mt.hasModifier(CodeConstants.ACC_NATIVE)) {
+ // external and native methods must not be renamed
+ if (!isPrivate) {
+ names.put(key, name);
+ }
+ }
+ else if (helper.toBeRenamed(IIdentifierRenamer.ELEMENT_METHOD, classOldFullName, name, mt.getDescriptor())) {
+ if (isPrivate || !names.containsKey(key)) {
+ do {
+ name = helper.getNextMethodname(classOldFullName, name, mt.getDescriptor());
+ }
+ while (setMethodNames.contains(name));
+
+ if (!isPrivate) {
+ names.put(key, name);
+ }
+ }
+ else {
+ name = names.get(key);
+ }
+
+ interceptor.addName(classOldFullName + " " + mt.getName() + " " + mt.getDescriptor(),
+ classNewFullName + " " + name + " " + buildNewDescriptor(false, mt.getDescriptor()));
+ }
+ }
+
+ // external fields are not being renamed
+ if (!cl.isOwn()) {
+ return;
+ }
+
+ // fields
+ // FIXME: should overloaded fields become the same name?
+ HashSet<String> setFieldNames = new HashSet<String>();
+ for (StructField fd : cl.getFields()) {
+ setFieldNames.add(fd.getName());
+ }
+
+ for (StructField fd : cl.getFields()) {
+ if (helper.toBeRenamed(IIdentifierRenamer.ELEMENT_FIELD, classOldFullName, fd.getName(), fd.getDescriptor())) {
+ String newname;
+
+ do {
+ newname = helper.getNextFieldname(classOldFullName, fd.getName(), fd.getDescriptor());
+ }
+ while (setFieldNames.contains(newname));
+
+ interceptor.addName(classOldFullName + " " + fd.getName() + " " + fd.getDescriptor(),
+ classNewFullName + " " + newname + " " + buildNewDescriptor(true, fd.getDescriptor()));
+ }
+ }
+ }
+
+ private String buildNewDescriptor(boolean isField, String descriptor) {
+
+ boolean updated = false;
+
+ if (isField) {
+ FieldDescriptor fd = FieldDescriptor.parseDescriptor(descriptor);
+
+ VarType ftype = fd.type;
+ if (ftype.type == CodeConstants.TYPE_OBJECT) {
+ String newclname = interceptor.getName(ftype.value);
+ if (newclname != null) {
+ ftype.value = newclname;
+ updated = true;
+ }
+ }
+
+ if (updated) {
+ return fd.getDescriptor();
+ }
+ }
+ else {
+
+ MethodDescriptor md = MethodDescriptor.parseDescriptor(descriptor);
+ // params
+ for (VarType partype : md.params) {
+ if (partype.type == CodeConstants.TYPE_OBJECT) {
+ String newclname = interceptor.getName(partype.value);
+ if (newclname != null) {
+ partype.value = newclname;
+ updated = true;
+ }
+ }
+ }
+
+ // return value
+ if (md.ret.type == CodeConstants.TYPE_OBJECT) {
+ String newclname = interceptor.getName(md.ret.value);
+ if (newclname != null) {
+ md.ret.value = newclname;
+ updated = true;
+ }
+ }
+
+ if (updated) {
+ return md.getDescriptor();
+ }
+ }
+
+ return descriptor;
+ }
+
+ private static List<ClassWrapperNode> getReversePostOrderListIterative(List<ClassWrapperNode> roots) {
+
+ List<ClassWrapperNode> res = new ArrayList<ClassWrapperNode>();
+
+ LinkedList<ClassWrapperNode> stackNode = new LinkedList<ClassWrapperNode>();
+ LinkedList<Integer> stackIndex = new LinkedList<Integer>();
+
+ HashSet<ClassWrapperNode> setVisited = new HashSet<ClassWrapperNode>();
+
+ for (ClassWrapperNode root : roots) {
+ stackNode.add(root);
+ stackIndex.add(0);
+ }
+
+ while (!stackNode.isEmpty()) {
+
+ ClassWrapperNode node = stackNode.getLast();
+ int index = stackIndex.removeLast();
+
+ setVisited.add(node);
+
+ List<ClassWrapperNode> lstSubs = node.getSubclasses();
+
+ for (; index < lstSubs.size(); index++) {
+ ClassWrapperNode sub = lstSubs.get(index);
+ if (!setVisited.contains(sub)) {
+ stackIndex.add(index + 1);
+
+ stackNode.add(sub);
+ stackIndex.add(0);
+
+ break;
+ }
+ }
+
+ if (index == lstSubs.size()) {
+ res.add(0, node);
+
+ stackNode.removeLast();
+ }
+ }
+
+ return res;
+ }
+
+
+ private void buildInheritanceTree() {
+
+ Map<String, ClassWrapperNode> nodes = new HashMap<String, ClassWrapperNode>();
+ Map<String, StructClass> classes = context.getClasses();
+
+ List<ClassWrapperNode> rootClasses = new ArrayList<ClassWrapperNode>();
+ List<ClassWrapperNode> rootInterfaces = new ArrayList<ClassWrapperNode>();
+
+ for (StructClass cl : classes.values()) {
+
+ if (!cl.isOwn()) {
+ continue;
+ }
+
+ LinkedList<StructClass> stack = new LinkedList<StructClass>();
+ LinkedList<ClassWrapperNode> stackSubnodes = new LinkedList<ClassWrapperNode>();
+
+ stack.add(cl);
+ stackSubnodes.add(null);
+
+ while (!stack.isEmpty()) {
+
+ StructClass clstr = stack.removeFirst();
+ ClassWrapperNode child = stackSubnodes.removeFirst();
+
+ ClassWrapperNode node = nodes.get(clstr.qualifiedName);
+ boolean isNewNode = (node == null);
+
+ if (isNewNode) {
+ nodes.put(clstr.qualifiedName, node = new ClassWrapperNode(clstr));
+ }
+
+ if (child != null) {
+ node.addSubclass(child);
+ }
+
+ if (!isNewNode) {
+ break;
+ }
+ else {
+ boolean isInterface = clstr.hasModifier(CodeConstants.ACC_INTERFACE);
+ boolean found_parent = false;
+
+ if (isInterface) {
+ for (String intrName : clstr.getInterfaceNames()) {
+ StructClass clparent = classes.get(intrName);
+ if (clparent != null) {
+ stack.add(clparent);
+ stackSubnodes.add(node);
+ found_parent = true;
+ }
+ }
+ }
+ else {
+ if (clstr.superClass != null) { // null iff java/lang/Object
+ StructClass clparent = classes.get(clstr.superClass.getString());
+
+ if (clparent != null) {
+ stack.add(clparent);
+ stackSubnodes.add(node);
+ found_parent = true;
+ }
+ }
+ }
+
+ if (!found_parent) { // no super class or interface
+ (isInterface ? rootInterfaces : rootClasses).add(node);
+ }
+ }
+ }
+ }
+
+ this.rootClasses = rootClasses;
+ this.rootInterfaces = rootInterfaces;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/renamer/PoolInterceptor.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/renamer/PoolInterceptor.java
new file mode 100644
index 000000000000..74e2ed8e6fd3
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/modules/renamer/PoolInterceptor.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.modules.renamer;
+
+import org.jetbrains.java.decompiler.main.extern.IIdentifierRenamer;
+
+import java.util.HashMap;
+
+public class PoolInterceptor {
+
+ private IIdentifierRenamer helper;
+
+ private HashMap<String, String> mapOldToNewNames = new HashMap<String, String>();
+
+ private HashMap<String, String> mapNewToOldNames = new HashMap<String, String>();
+
+ public PoolInterceptor(IIdentifierRenamer helper) {
+ this.helper = helper;
+ }
+
+ public void addName(String oldName, String newName) {
+ mapOldToNewNames.put(oldName, newName);
+ mapNewToOldNames.put(newName, oldName);
+ }
+
+ public String getName(String oldName) {
+ return mapOldToNewNames.get(oldName);
+ }
+
+ public String getOldName(String newName) {
+ return mapNewToOldNames.get(newName);
+ }
+
+ public IIdentifierRenamer getHelper() {
+ return helper;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/ContextUnit.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/ContextUnit.java
new file mode 100644
index 000000000000..819ae6446d07
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/ContextUnit.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.struct;
+
+import org.jetbrains.java.decompiler.main.extern.IResultSaver;
+import org.jetbrains.java.decompiler.struct.lazy.LazyLoader;
+import org.jetbrains.java.decompiler.struct.lazy.LazyLoader.Link;
+import org.jetbrains.java.decompiler.util.DataInputFullStream;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+
+public class ContextUnit {
+
+ public static final int TYPE_FOLDER = 0;
+ public static final int TYPE_JAR = 1;
+ public static final int TYPE_ZIP = 2;
+
+ private final int type;
+ private final boolean own;
+
+ private final String archivePath; // relative path to jar/zip
+ private final String filename; // folder: relative path, archive: file name
+ private final IResultSaver resultSaver;
+ private final IDecompiledData decompiledData;
+
+ private final List<String> classEntries = new ArrayList<String>(); // class file or jar/zip entry
+ private final List<String> dirEntries = new ArrayList<String>();
+ private final List<String[]> otherEntries = new ArrayList<String[]>();
+
+ private List<StructClass> classes = new ArrayList<StructClass>();
+ private Manifest manifest;
+
+ public ContextUnit(int type, String archivePath, String filename, boolean own, IResultSaver resultSaver, IDecompiledData decompiledData) {
+ this.type = type;
+ this.own = own;
+ this.archivePath = archivePath;
+ this.filename = filename;
+ this.resultSaver = resultSaver;
+ this.decompiledData = decompiledData;
+ }
+
+ public void addClass(StructClass cl, String entryName) {
+ classes.add(cl);
+ classEntries.add(entryName);
+ }
+
+ public void addDirEntry(String entry) {
+ dirEntries.add(entry);
+ }
+
+ public void addOtherEntry(String fullPath, String entry) {
+ otherEntries.add(new String[]{fullPath, entry});
+ }
+
+ public void reload(LazyLoader loader) throws IOException {
+ List<StructClass> lstClasses = new ArrayList<StructClass>();
+
+ for (StructClass cl : classes) {
+ String oldName = cl.qualifiedName;
+
+ StructClass newCl;
+ DataInputFullStream in = loader.getClassStream(oldName);
+ try {
+ newCl = new StructClass(in, cl.isOwn(), loader);
+ }
+ finally {
+ in.close();
+ }
+
+ lstClasses.add(newCl);
+
+ Link lnk = loader.getClassLink(oldName);
+ loader.removeClassLink(oldName);
+ loader.addClassLink(newCl.qualifiedName, lnk);
+ }
+
+ classes = lstClasses;
+ }
+
+ public void save() {
+ switch (type) {
+ case TYPE_FOLDER:
+ // create folder
+ resultSaver.saveFolder(filename);
+
+ // non-class files
+ for (String[] pair : otherEntries) {
+ resultSaver.copyFile(pair[0], filename, pair[1]);
+ }
+
+ // classes
+ for (int i = 0; i < classes.size(); i++) {
+ StructClass cl = classes.get(i);
+ String entryName = decompiledData.getClassEntryName(cl, classEntries.get(i));
+ if (entryName != null) {
+ String content = decompiledData.getClassContent(cl);
+ if (content != null) {
+ resultSaver.saveClassFile(filename, cl.qualifiedName, entryName, content);
+ }
+ }
+ }
+
+ break;
+
+ case TYPE_JAR:
+ case TYPE_ZIP:
+ // create archive file
+ resultSaver.saveFolder(archivePath);
+ resultSaver.createArchive(archivePath, filename, manifest);
+
+ // directory entries
+ for (String dirEntry : dirEntries) {
+ resultSaver.saveDirEntry(archivePath, filename, dirEntry);
+ }
+
+ // non-class entries
+ for (String[] pair : otherEntries) {
+ if (type != TYPE_JAR || !JarFile.MANIFEST_NAME.equalsIgnoreCase(pair[1])) {
+ resultSaver.copyEntry(pair[0], archivePath, filename, pair[1]);
+ }
+ }
+
+ // classes
+ for (int i = 0; i < classes.size(); i++) {
+ StructClass cl = classes.get(i);
+ String entryName = decompiledData.getClassEntryName(cl, classEntries.get(i));
+ if (entryName != null) {
+ String content = decompiledData.getClassContent(cl);
+ resultSaver.saveClassEntry(archivePath, filename, cl.qualifiedName, entryName, content);
+ }
+ }
+
+ resultSaver.closeArchive(archivePath, filename);
+ }
+ }
+
+ public void setManifest(Manifest manifest) {
+ this.manifest = manifest;
+ }
+
+ public boolean isOwn() {
+ return own;
+ }
+
+ public List<StructClass> getClasses() {
+ return classes;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/IDecompiledData.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/IDecompiledData.java
new file mode 100644
index 000000000000..f309b0e17bc9
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/IDecompiledData.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.struct;
+
+public interface IDecompiledData {
+
+ String getClassEntryName(StructClass cl, String entryname);
+
+ String getClassContent(StructClass cl);
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/StructClass.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/StructClass.java
new file mode 100644
index 000000000000..cb24ff65db63
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/StructClass.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.struct;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
+import org.jetbrains.java.decompiler.struct.consts.PrimitiveConstant;
+import org.jetbrains.java.decompiler.struct.lazy.LazyLoader;
+import org.jetbrains.java.decompiler.util.DataInputFullStream;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import org.jetbrains.java.decompiler.util.VBStyleCollection;
+
+import java.io.IOException;
+
+/*
+ class_file {
+ u4 magic;
+ u2 minor_version;
+ u2 major_version;
+ u2 constant_pool_count;
+ cp_info constant_pool[constant_pool_count-1];
+ u2 access_flags;
+ u2 this_class;
+ u2 super_class;
+ u2 interfaces_count;
+ u2 interfaces[interfaces_count];
+ u2 fields_count;
+ field_info fields[fields_count];
+ u2 methods_count;
+ method_info methods[methods_count];
+ u2 attributes_count;
+ attribute_info attributes[attributes_count];
+ }
+*/
+public class StructClass extends StructMember {
+
+ public final String qualifiedName;
+ public final PrimitiveConstant superClass;
+
+ private final boolean own;
+ private final LazyLoader loader;
+ private final int minorVersion;
+ private final int majorVersion;
+ private final int[] interfaces;
+ private final String[] interfaceNames;
+ private final VBStyleCollection<StructField, String> fields;
+ private final VBStyleCollection<StructMethod, String> methods;
+
+ private ConstantPool pool;
+
+ public StructClass(byte[] bytes, boolean own, LazyLoader loader) throws IOException {
+ this(new DataInputFullStream(bytes), own, loader);
+ }
+
+ public StructClass(DataInputFullStream in, boolean own, LazyLoader loader) throws IOException {
+ this.own = own;
+ this.loader = loader;
+
+ in.discard(4);
+
+ minorVersion = in.readUnsignedShort();
+ majorVersion = in.readUnsignedShort();
+
+ pool = new ConstantPool(in);
+
+ accessFlags = in.readUnsignedShort();
+ int thisClassIdx = in.readUnsignedShort();
+ int superClassIdx = in.readUnsignedShort();
+ qualifiedName = pool.getPrimitiveConstant(thisClassIdx).getString();
+ superClass = pool.getPrimitiveConstant(superClassIdx);
+
+ // interfaces
+ int length = in.readUnsignedShort();
+ interfaces = new int[length];
+ interfaceNames = new String[length];
+ for (int i = 0; i < length; i++) {
+ interfaces[i] = in.readUnsignedShort();
+ interfaceNames[i] = pool.getPrimitiveConstant(interfaces[i]).getString();
+ }
+
+ // fields
+ length = in.readUnsignedShort();
+ fields = new VBStyleCollection<StructField, String>();
+ for (int i = 0; i < length; i++) {
+ StructField field = new StructField(in, this);
+ fields.addWithKey(field, InterpreterUtil.makeUniqueKey(field.getName(), field.getDescriptor()));
+ }
+
+ // methods
+ length = in.readUnsignedShort();
+ methods = new VBStyleCollection<StructMethod, String>();
+ for (int i = 0; i < length; i++) {
+ StructMethod method = new StructMethod(in, this);
+ methods.addWithKey(method, InterpreterUtil.makeUniqueKey(method.getName(), method.getDescriptor()));
+ }
+
+ // attributes
+ attributes = readAttributes(in, pool);
+
+ releaseResources();
+ }
+
+ public boolean hasField(String name, String descriptor) {
+ return getField(name, descriptor) != null;
+ }
+
+ public StructField getField(String name, String descriptor) {
+ return fields.getWithKey(InterpreterUtil.makeUniqueKey(name, descriptor));
+ }
+
+ public StructMethod getMethod(String key) {
+ return methods.getWithKey(key);
+ }
+
+ public StructMethod getMethod(String name, String descriptor) {
+ return methods.getWithKey(InterpreterUtil.makeUniqueKey(name, descriptor));
+ }
+
+ public String getInterface(int i) {
+ return interfaceNames[i];
+ }
+
+ public void releaseResources() {
+ if (loader != null) {
+ pool = null;
+ }
+ }
+
+ public ConstantPool getPool() {
+ if (pool == null && loader != null) {
+ pool = loader.loadPool(qualifiedName);
+ }
+ return pool;
+ }
+
+ public int[] getInterfaces() {
+ return interfaces;
+ }
+
+ public String[] getInterfaceNames() {
+ return interfaceNames;
+ }
+
+ public VBStyleCollection<StructMethod, String> getMethods() {
+ return methods;
+ }
+
+ public VBStyleCollection<StructField, String> getFields() {
+ return fields;
+ }
+
+ public boolean isOwn() {
+ return own;
+ }
+
+ public LazyLoader getLoader() {
+ return loader;
+ }
+
+ public boolean isVersionGE_1_5() {
+ return (majorVersion > 48 || (majorVersion == 48 && minorVersion > 0)); // FIXME: check second condition
+ }
+
+ public boolean isVersionGE_1_7() {
+ return (majorVersion >= 51);
+ }
+
+ public int getBytecodeVersion() {
+ switch (majorVersion) {
+ case 52:
+ return CodeConstants.BYTECODE_JAVA_8;
+ case 51:
+ return CodeConstants.BYTECODE_JAVA_7;
+ case 50:
+ return CodeConstants.BYTECODE_JAVA_6;
+ case 49:
+ return CodeConstants.BYTECODE_JAVA_5;
+ }
+
+ return CodeConstants.BYTECODE_JAVA_LE_4;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/StructContext.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/StructContext.java
new file mode 100644
index 000000000000..7bfb139ede30
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/StructContext.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.struct;
+
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.main.extern.IResultSaver;
+import org.jetbrains.java.decompiler.struct.lazy.LazyLoader;
+import org.jetbrains.java.decompiler.util.DataInputFullStream;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.jar.JarFile;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+public class StructContext {
+
+ private final IResultSaver saver;
+ private final IDecompiledData decompiledData;
+ private final LazyLoader loader;
+ private final Map<String, ContextUnit> units = new HashMap<String, ContextUnit>();
+ private final Map<String, StructClass> classes = new HashMap<String, StructClass>();
+
+ public StructContext(IResultSaver saver, IDecompiledData decompiledData, LazyLoader loader) {
+ this.saver = saver;
+ this.decompiledData = decompiledData;
+ this.loader = loader;
+
+ ContextUnit defaultUnit = new ContextUnit(ContextUnit.TYPE_FOLDER, null, "", true, saver, decompiledData);
+ units.put("", defaultUnit);
+ }
+
+ public StructClass getClass(String name) {
+ return classes.get(name);
+ }
+
+ public void reloadContext() throws IOException {
+ for (ContextUnit unit : units.values()) {
+ for (StructClass cl : unit.getClasses()) {
+ classes.remove(cl.qualifiedName);
+ }
+
+ unit.reload(loader);
+
+ // adjust global class collection
+ for (StructClass cl : unit.getClasses()) {
+ classes.put(cl.qualifiedName, cl);
+ }
+ }
+ }
+
+ public void saveContext() {
+ for (ContextUnit unit : units.values()) {
+ if (unit.isOwn()) {
+ unit.save();
+ }
+ }
+ }
+
+ public void addSpace(File file, boolean isOwn) {
+ addSpace("", file, isOwn, 0);
+ }
+
+ private void addSpace(String path, File file, boolean isOwn, int level) {
+ if (file.isDirectory()) {
+ if (level == 1) path += file.getName();
+ else if (level > 1) path += "/" + file.getName();
+
+ File[] files = file.listFiles();
+ if (files != null) {
+ for (int i = files.length - 1; i >= 0; i--) {
+ addSpace(path, files[i], isOwn, level + 1);
+ }
+ }
+ }
+ else {
+ String filename = file.getName();
+
+ boolean isArchive = false;
+ try {
+ if (filename.endsWith(".jar")) {
+ isArchive = true;
+ addArchive(path, file, ContextUnit.TYPE_JAR, isOwn);
+ }
+ else if (filename.endsWith(".zip")) {
+ isArchive = true;
+ addArchive(path, file, ContextUnit.TYPE_ZIP, isOwn);
+ }
+ }
+ catch (IOException ex) {
+ String message = "Corrupted archive file: " + file;
+ DecompilerContext.getLogger().writeMessage(message, ex);
+ }
+ if (isArchive) {
+ return;
+ }
+
+ ContextUnit unit = units.get(path);
+ if (unit == null) {
+ unit = new ContextUnit(ContextUnit.TYPE_FOLDER, null, path, isOwn, saver, decompiledData);
+ units.put(path, unit);
+ }
+
+ if (filename.endsWith(".class")) {
+ try {
+ DataInputFullStream in = loader.getClassStream(file.getAbsolutePath(), null);
+ try {
+ StructClass cl = new StructClass(in, isOwn, loader);
+ classes.put(cl.qualifiedName, cl);
+ unit.addClass(cl, filename);
+ loader.addClassLink(cl.qualifiedName, new LazyLoader.Link(LazyLoader.Link.CLASS, file.getAbsolutePath(), null));
+ }
+ finally {
+ in.close();
+ }
+ }
+ catch (IOException ex) {
+ String message = "Corrupted class file: " + file;
+ DecompilerContext.getLogger().writeMessage(message, ex);
+ }
+ }
+ else {
+ unit.addOtherEntry(file.getAbsolutePath(), filename);
+ }
+ }
+ }
+
+ private void addArchive(String path, File file, int type, boolean isOwn) throws IOException {
+ @SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
+ ZipFile archive = type == ContextUnit.TYPE_JAR ? new JarFile(file) : new ZipFile(file);
+
+ try {
+ Enumeration<? extends ZipEntry> entries = archive.entries();
+ while (entries.hasMoreElements()) {
+ ZipEntry entry = entries.nextElement();
+
+ ContextUnit unit = units.get(path + "/" + file.getName());
+ if (unit == null) {
+ unit = new ContextUnit(type, path, file.getName(), isOwn, saver, decompiledData);
+ if (type == ContextUnit.TYPE_JAR) {
+ unit.setManifest(((JarFile)archive).getManifest());
+ }
+ units.put(path + "/" + file.getName(), unit);
+ }
+
+ String name = entry.getName();
+ if (!entry.isDirectory()) {
+ if (name.endsWith(".class")) {
+ byte[] bytes = InterpreterUtil.getBytes(archive, entry);
+ StructClass cl = new StructClass(bytes, isOwn, loader);
+ classes.put(cl.qualifiedName, cl);
+ unit.addClass(cl, name);
+ loader.addClassLink(cl.qualifiedName, new LazyLoader.Link(LazyLoader.Link.ENTRY, file.getAbsolutePath(), name));
+ }
+ else {
+ unit.addOtherEntry(file.getAbsolutePath(), name);
+ }
+ }
+ else {
+ unit.addDirEntry(name);
+ }
+ }
+ }
+ finally {
+ archive.close();
+ }
+ }
+
+ public Map<String, StructClass> getClasses() {
+ return classes;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/StructField.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/StructField.java
new file mode 100644
index 000000000000..796d77f1c9a3
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/StructField.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.struct;
+
+import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
+import org.jetbrains.java.decompiler.util.DataInputFullStream;
+
+import java.io.IOException;
+
+/*
+ field_info {
+ u2 access_flags;
+ u2 name_index;
+ u2 descriptor_index;
+ u2 attributes_count;
+ attribute_info attributes[attributes_count];
+ }
+*/
+public class StructField extends StructMember {
+
+ private final String name;
+ private final String descriptor;
+
+
+ public StructField(DataInputFullStream in, StructClass clStruct) throws IOException {
+ accessFlags = in.readUnsignedShort();
+ int nameIndex = in.readUnsignedShort();
+ int descriptorIndex = in.readUnsignedShort();
+
+ ConstantPool pool = clStruct.getPool();
+ String[] values = pool.getClassElement(ConstantPool.FIELD, clStruct.qualifiedName, nameIndex, descriptorIndex);
+ name = values[0];
+ descriptor = values[1];
+
+ attributes = readAttributes(in, pool);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getDescriptor() {
+ return descriptor;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/StructMember.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/StructMember.java
new file mode 100644
index 000000000000..f681e19604b3
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/StructMember.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.struct;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute;
+import org.jetbrains.java.decompiler.struct.attr.StructLocalVariableTableAttribute;
+import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
+import org.jetbrains.java.decompiler.util.DataInputFullStream;
+import org.jetbrains.java.decompiler.util.VBStyleCollection;
+
+import java.io.IOException;
+
+public class StructMember {
+
+ protected int accessFlags;
+ protected VBStyleCollection<StructGeneralAttribute, String> attributes;
+
+
+ public int getAccessFlags() {
+ return accessFlags;
+ }
+
+ public VBStyleCollection<StructGeneralAttribute, String> getAttributes() {
+ return attributes;
+ }
+
+ public boolean hasModifier(int modifier) {
+ return (accessFlags & modifier) == modifier;
+ }
+
+ public boolean isSynthetic() {
+ return hasModifier(CodeConstants.ACC_SYNTHETIC) || attributes.containsKey(StructGeneralAttribute.ATTRIBUTE_SYNTHETIC);
+ }
+
+ protected VBStyleCollection<StructGeneralAttribute, String> readAttributes(DataInputFullStream in, ConstantPool pool) throws IOException {
+ VBStyleCollection<StructGeneralAttribute, String> attributes = new VBStyleCollection<StructGeneralAttribute, String>();
+
+ int length = in.readUnsignedShort();
+ for (int i = 0; i < length; i++) {
+ int nameIndex = in.readUnsignedShort();
+ String name = pool.getPrimitiveConstant(nameIndex).getString();
+
+ StructGeneralAttribute attribute = readAttribute(in, pool, name);
+
+ if (attribute != null) {
+ if (StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TABLE.equals(name) && attributes.containsKey(name)) {
+ // merge all variable tables
+ StructLocalVariableTableAttribute table = (StructLocalVariableTableAttribute)attributes.getWithKey(name);
+ table.addLocalVariableTable((StructLocalVariableTableAttribute)attribute);
+ }
+ else {
+ attributes.addWithKey(attribute, attribute.getName());
+ }
+ }
+ }
+
+ return attributes;
+ }
+
+ protected StructGeneralAttribute readAttribute(DataInputFullStream in, ConstantPool pool, String name) throws IOException {
+ StructGeneralAttribute attribute = StructGeneralAttribute.createAttribute(name);
+ if (attribute == null) {
+ in.discard(in.readInt());
+ }
+ else {
+ byte[] data = new byte[in.readInt()];
+ in.readFull(data);
+ attribute.setInfo(data);
+ attribute.initContent(pool);
+ }
+ return attribute;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/StructMethod.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/StructMethod.java
new file mode 100644
index 000000000000..2b5249f59d5a
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/StructMethod.java
@@ -0,0 +1,392 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.struct;
+
+import org.jetbrains.java.decompiler.code.*;
+import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute;
+import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
+import org.jetbrains.java.decompiler.util.DataInputFullStream;
+import org.jetbrains.java.decompiler.util.VBStyleCollection;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.jetbrains.java.decompiler.code.CodeConstants.*;
+
+/*
+ method_info {
+ u2 access_flags;
+ u2 name_index;
+ u2 descriptor_index;
+ u2 attributes_count;
+ attribute_info attributes[attributes_count];
+ }
+*/
+public class StructMethod extends StructMember {
+
+ private static final int[] opr_iconst = {-1, 0, 1, 2, 3, 4, 5};
+ private static final int[] opr_loadstore = {0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3};
+ private static final int[] opcs_load = {opc_iload, opc_lload, opc_fload, opc_dload, opc_aload};
+ private static final int[] opcs_store = {opc_istore, opc_lstore, opc_fstore, opc_dstore, opc_astore};
+
+ private final StructClass classStruct;
+ private final String name;
+ private final String descriptor;
+
+ private boolean containsCode = false;
+ private int localVariables = 0;
+ private int codeLength = 0;
+ private int codeFullLength = 0;
+ private InstructionSequence seq;
+ private boolean expanded = false;
+ private VBStyleCollection<StructGeneralAttribute, String> codeAttributes;
+
+ public StructMethod(DataInputFullStream in, StructClass clStruct) throws IOException {
+ classStruct = clStruct;
+
+ accessFlags = in.readUnsignedShort();
+ int nameIndex = in.readUnsignedShort();
+ int descriptorIndex = in.readUnsignedShort();
+
+ ConstantPool pool = clStruct.getPool();
+ String[] values = pool.getClassElement(ConstantPool.METHOD, clStruct.qualifiedName, nameIndex, descriptorIndex);
+ name = values[0];
+ descriptor = values[1];
+
+ attributes = readAttributes(in, pool);
+ if (codeAttributes != null) {
+ attributes.addAllWithKey(codeAttributes);
+ codeAttributes = null;
+ }
+ }
+
+ @Override
+ protected StructGeneralAttribute readAttribute(DataInputFullStream in, ConstantPool pool, String name) throws IOException {
+ if (StructGeneralAttribute.ATTRIBUTE_CODE.equals(name)) {
+ if (!classStruct.isOwn()) {
+ // skip code in foreign classes
+ in.discard(8);
+ in.discard(in.readInt());
+ in.discard(8 * in.readUnsignedShort());
+ }
+ else {
+ containsCode = true;
+ in.discard(6);
+ localVariables = in.readUnsignedShort();
+ codeLength = in.readInt();
+ in.discard(codeLength);
+ int excLength = in.readUnsignedShort();
+ in.discard(excLength * 8);
+ codeFullLength = codeLength + excLength * 8 + 2;
+ }
+
+ codeAttributes = readAttributes(in, pool);
+
+ return null;
+ }
+
+ return super.readAttribute(in, pool, name);
+ }
+
+ public void expandData() throws IOException {
+ if (containsCode && !expanded) {
+ byte[] code = classStruct.getLoader().loadBytecode(this, codeFullLength);
+ seq = parseBytecode(new DataInputFullStream(code), codeLength, classStruct.getPool());
+ expanded = true;
+ }
+ }
+
+ public void releaseResources() throws IOException {
+ if (containsCode && expanded) {
+ seq = null;
+ expanded = false;
+ }
+ }
+
+ @SuppressWarnings("AssignmentToForLoopParameter")
+ private InstructionSequence parseBytecode(DataInputFullStream in, int length, ConstantPool pool) throws IOException {
+ VBStyleCollection<Instruction, Integer> instructions = new VBStyleCollection<Instruction, Integer>();
+
+ int bytecode_version = classStruct.getBytecodeVersion();
+
+ for (int i = 0; i < length; ) {
+
+ int offset = i;
+
+ int opcode = in.readUnsignedByte();
+ int group = GROUP_GENERAL;
+
+ boolean wide = (opcode == opc_wide);
+
+ if (wide) {
+ i++;
+ opcode = in.readUnsignedByte();
+ }
+
+ List<Integer> operands = new ArrayList<Integer>();
+
+ if (opcode >= opc_iconst_m1 && opcode <= opc_iconst_5) {
+ operands.add(new Integer(opr_iconst[opcode - opc_iconst_m1]));
+ opcode = opc_bipush;
+ }
+ else if (opcode >= opc_iload_0 && opcode <= opc_aload_3) {
+ operands.add(new Integer(opr_loadstore[opcode - opc_iload_0]));
+ opcode = opcs_load[(opcode - opc_iload_0) / 4];
+ }
+ else if (opcode >= opc_istore_0 && opcode <= opc_astore_3) {
+ operands.add(new Integer(opr_loadstore[opcode - opc_istore_0]));
+ opcode = opcs_store[(opcode - opc_istore_0) / 4];
+ }
+ else {
+ switch (opcode) {
+ case opc_bipush:
+ operands.add(new Integer(in.readByte()));
+ i++;
+ break;
+ case opc_ldc:
+ case opc_newarray:
+ operands.add(new Integer(in.readUnsignedByte()));
+ i++;
+ break;
+ case opc_sipush:
+ case opc_ifeq:
+ case opc_ifne:
+ case opc_iflt:
+ case opc_ifge:
+ case opc_ifgt:
+ case opc_ifle:
+ case opc_if_icmpeq:
+ case opc_if_icmpne:
+ case opc_if_icmplt:
+ case opc_if_icmpge:
+ case opc_if_icmpgt:
+ case opc_if_icmple:
+ case opc_if_acmpeq:
+ case opc_if_acmpne:
+ case opc_goto:
+ case opc_jsr:
+ case opc_ifnull:
+ case opc_ifnonnull:
+ if (opcode != opc_sipush) {
+ group = GROUP_JUMP;
+ }
+ operands.add(new Integer(in.readShort()));
+ i += 2;
+ break;
+ case opc_ldc_w:
+ case opc_ldc2_w:
+ case opc_getstatic:
+ case opc_putstatic:
+ case opc_getfield:
+ case opc_putfield:
+ case opc_invokevirtual:
+ case opc_invokespecial:
+ case opc_invokestatic:
+ case opc_new:
+ case opc_anewarray:
+ case opc_checkcast:
+ case opc_instanceof:
+ operands.add(new Integer(in.readUnsignedShort()));
+ i += 2;
+ if (opcode >= opc_getstatic && opcode <= opc_putfield) {
+ group = GROUP_FIELDACCESS;
+ }
+ else if (opcode >= opc_invokevirtual && opcode <= opc_invokestatic) {
+ group = GROUP_INVOCATION;
+ }
+ break;
+ case opc_invokedynamic:
+ if (classStruct.isVersionGE_1_7()) { // instruction unused in Java 6 and before
+ operands.add(new Integer(in.readUnsignedShort()));
+ in.discard(2);
+ group = GROUP_INVOCATION;
+ i += 4;
+ }
+ break;
+ case opc_iload:
+ case opc_lload:
+ case opc_fload:
+ case opc_dload:
+ case opc_aload:
+ case opc_istore:
+ case opc_lstore:
+ case opc_fstore:
+ case opc_dstore:
+ case opc_astore:
+ case opc_ret:
+ if (wide) {
+ operands.add(new Integer(in.readUnsignedShort()));
+ i += 2;
+ }
+ else {
+ operands.add(new Integer(in.readUnsignedByte()));
+ i++;
+ }
+ if (opcode == opc_ret) {
+ group = GROUP_RETURN;
+ }
+ break;
+ case opc_iinc:
+ if (wide) {
+ operands.add(new Integer(in.readUnsignedShort()));
+ operands.add(new Integer(in.readShort()));
+ i += 4;
+ }
+ else {
+ operands.add(new Integer(in.readUnsignedByte()));
+ operands.add(new Integer(in.readByte()));
+ i += 2;
+ }
+ break;
+ case opc_goto_w:
+ case opc_jsr_w:
+ opcode = opcode == opc_jsr_w ? opc_jsr : opc_goto;
+ operands.add(new Integer(in.readInt()));
+ group = GROUP_JUMP;
+ i += 4;
+ break;
+ case opc_invokeinterface:
+ operands.add(new Integer(in.readUnsignedShort()));
+ operands.add(new Integer(in.readUnsignedByte()));
+ in.discard(1);
+ group = GROUP_INVOCATION;
+ i += 4;
+ break;
+ case opc_multianewarray:
+ operands.add(new Integer(in.readUnsignedShort()));
+ operands.add(new Integer(in.readUnsignedByte()));
+ i += 3;
+ break;
+ case opc_tableswitch:
+ in.discard((4 - (i + 1) % 4) % 4);
+ i += ((4 - (i + 1) % 4) % 4); // padding
+ operands.add(new Integer(in.readInt()));
+ i += 4;
+ int low = in.readInt();
+ operands.add(new Integer(low));
+ i += 4;
+ int high = in.readInt();
+ operands.add(new Integer(high));
+ i += 4;
+
+ for (int j = 0; j < high - low + 1; j++) {
+ operands.add(new Integer(in.readInt()));
+ i += 4;
+ }
+ group = GROUP_SWITCH;
+
+ break;
+ case opc_lookupswitch:
+ in.discard((4 - (i + 1) % 4) % 4);
+ i += ((4 - (i + 1) % 4) % 4); // padding
+ operands.add(new Integer(in.readInt()));
+ i += 4;
+ int npairs = in.readInt();
+ operands.add(new Integer(npairs));
+ i += 4;
+
+ for (int j = 0; j < npairs; j++) {
+ operands.add(new Integer(in.readInt()));
+ i += 4;
+ operands.add(new Integer(in.readInt()));
+ i += 4;
+ }
+ group = GROUP_SWITCH;
+ break;
+ case opc_ireturn:
+ case opc_lreturn:
+ case opc_freturn:
+ case opc_dreturn:
+ case opc_areturn:
+ case opc_return:
+ case opc_athrow:
+ group = GROUP_RETURN;
+ }
+ }
+
+ int[] ops = new int[operands.size()];
+ for (int j = 0; j < operands.size(); j++) {
+ ops[j] = operands.get(j).intValue();
+ }
+
+ Instruction instr = ConstantsUtil.getInstructionInstance(opcode, wide, group, bytecode_version, ops);
+
+ instructions.addWithKey(instr, new Integer(offset));
+
+ i++;
+ }
+
+ // initialize exception table
+ List<ExceptionHandler> lstHandlers = new ArrayList<ExceptionHandler>();
+
+ int exception_count = in.readUnsignedShort();
+ for (int i = 0; i < exception_count; i++) {
+ ExceptionHandler handler = new ExceptionHandler();
+ handler.from = in.readUnsignedShort();
+ handler.to = in.readUnsignedShort();
+ handler.handler = in.readUnsignedShort();
+
+ int excclass = in.readUnsignedShort();
+ handler.class_index = excclass;
+ if (excclass != 0) {
+ handler.exceptionClass = pool.getPrimitiveConstant(excclass).getString();
+ }
+
+ lstHandlers.add(handler);
+ }
+
+ InstructionSequence seq = new FullInstructionSequence(instructions, new ExceptionTable(lstHandlers));
+
+ // initialize instructions
+ int i = seq.length() - 1;
+ seq.setPointer(i);
+
+ while (i >= 0) {
+ Instruction instr = seq.getInstr(i--);
+ if (instr.group != GROUP_GENERAL) {
+ instr.initInstruction(seq);
+ }
+ seq.addToPointer(-1);
+ }
+
+ return seq;
+ }
+
+ public StructClass getClassStruct() {
+ return classStruct;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getDescriptor() {
+ return descriptor;
+ }
+
+ public boolean containsCode() {
+ return containsCode;
+ }
+
+ public int getLocalVariables() {
+ return localVariables;
+ }
+
+ public InstructionSequence getInstructionSequence() {
+ return seq;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructAnnDefaultAttribute.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructAnnDefaultAttribute.java
new file mode 100644
index 000000000000..fbad47e912db
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructAnnDefaultAttribute.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.struct.attr;
+
+import org.jetbrains.java.decompiler.modules.decompiler.exps.Exprent;
+import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
+
+import java.io.IOException;
+
+public class StructAnnDefaultAttribute extends StructGeneralAttribute {
+
+ private Exprent defaultValue;
+
+ @Override
+ public void initContent(ConstantPool pool) throws IOException {
+ defaultValue = StructAnnotationAttribute.parseAnnotationElement(stream(), pool);
+ }
+
+ public Exprent getDefaultValue() {
+ return defaultValue;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructAnnotationAttribute.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructAnnotationAttribute.java
new file mode 100644
index 000000000000..d04cb04166d5
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructAnnotationAttribute.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.struct.attr;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.modules.decompiler.exps.*;
+import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
+import org.jetbrains.java.decompiler.struct.consts.PrimitiveConstant;
+import org.jetbrains.java.decompiler.struct.gen.FieldDescriptor;
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class StructAnnotationAttribute extends StructGeneralAttribute {
+
+ private List<AnnotationExprent> annotations;
+
+ @Override
+ public void initContent(ConstantPool pool) throws IOException {
+ annotations = parseAnnotations(pool, stream());
+ }
+
+ public static List<AnnotationExprent> parseAnnotations(ConstantPool pool, DataInputStream data) throws IOException {
+ int len = data.readUnsignedShort();
+ if (len > 0) {
+ List<AnnotationExprent> annotations = new ArrayList<AnnotationExprent>(len);
+ for (int i = 0; i < len; i++) {
+ annotations.add(parseAnnotation(data, pool));
+ }
+ return annotations;
+ }
+ else {
+ return Collections.emptyList();
+ }
+ }
+
+ public static AnnotationExprent parseAnnotation(DataInputStream data, ConstantPool pool) throws IOException {
+ String className = pool.getPrimitiveConstant(data.readUnsignedShort()).getString();
+
+ List<String> names;
+ List<Exprent> values;
+ int len = data.readUnsignedShort();
+ if (len > 0) {
+ names = new ArrayList<String>(len);
+ values = new ArrayList<Exprent>(len);
+ for (int i = 0; i < len; i++) {
+ names.add(pool.getPrimitiveConstant(data.readUnsignedShort()).getString());
+ values.add(parseAnnotationElement(data, pool));
+ }
+ }
+ else {
+ names = Collections.emptyList();
+ values = Collections.emptyList();
+ }
+
+ return new AnnotationExprent(new VarType(className).value, names, values);
+ }
+
+ public static Exprent parseAnnotationElement(DataInputStream data, ConstantPool pool) throws IOException {
+ int tag = data.readUnsignedByte();
+
+ switch (tag) {
+ case 'e': // enum constant
+ String className = pool.getPrimitiveConstant(data.readUnsignedShort()).getString();
+ String constName = pool.getPrimitiveConstant(data.readUnsignedShort()).getString();
+ FieldDescriptor descr = FieldDescriptor.parseDescriptor(className);
+ return new FieldExprent(constName, descr.type.value, true, null, descr);
+
+ case 'c': // class
+ String descriptor = pool.getPrimitiveConstant(data.readUnsignedShort()).getString();
+ VarType type = FieldDescriptor.parseDescriptor(descriptor).type;
+
+ String value;
+ switch (type.type) {
+ case CodeConstants.TYPE_OBJECT:
+ value = type.value;
+ break;
+ case CodeConstants.TYPE_BYTE:
+ value = byte.class.getName();
+ break;
+ case CodeConstants.TYPE_CHAR:
+ value = char.class.getName();
+ break;
+ case CodeConstants.TYPE_DOUBLE:
+ value = double.class.getName();
+ break;
+ case CodeConstants.TYPE_FLOAT:
+ value = float.class.getName();
+ break;
+ case CodeConstants.TYPE_INT:
+ value = int.class.getName();
+ break;
+ case CodeConstants.TYPE_LONG:
+ value = long.class.getName();
+ break;
+ case CodeConstants.TYPE_SHORT:
+ value = short.class.getName();
+ break;
+ case CodeConstants.TYPE_BOOLEAN:
+ value = boolean.class.getName();
+ break;
+ case CodeConstants.TYPE_VOID:
+ value = void.class.getName();
+ break;
+ default:
+ throw new RuntimeException("invalid class type: " + type.type);
+ }
+ return new ConstExprent(VarType.VARTYPE_CLASS, value);
+
+ case '[': // array
+ List<Exprent> elements = Collections.emptyList();
+ int len = data.readUnsignedShort();
+ if (len > 0) {
+ elements = new ArrayList<Exprent>(len);
+ for (int i = 0; i < len; i++) {
+ elements.add(parseAnnotationElement(data, pool));
+ }
+ }
+
+ VarType newType;
+ if (elements.isEmpty()) {
+ newType = new VarType(CodeConstants.TYPE_OBJECT, 1, "java/lang/Object");
+ }
+ else {
+ VarType elementType = elements.get(0).getExprType();
+ newType = new VarType(elementType.type, 1, elementType.value);
+ }
+
+ NewExprent newExpr = new NewExprent(newType, Collections.<Exprent>emptyList());
+ newExpr.setDirectArrayInit(true);
+ newExpr.setLstArrayElements(elements);
+ return newExpr;
+
+ case '@': // annotation
+ return parseAnnotation(data, pool);
+
+ default:
+ PrimitiveConstant cn = pool.getPrimitiveConstant(data.readUnsignedShort());
+ switch (tag) {
+ case 'B':
+ return new ConstExprent(VarType.VARTYPE_BYTE, cn.value);
+ case 'C':
+ return new ConstExprent(VarType.VARTYPE_CHAR, cn.value);
+ case 'D':
+ return new ConstExprent(VarType.VARTYPE_DOUBLE, cn.value);
+ case 'F':
+ return new ConstExprent(VarType.VARTYPE_FLOAT, cn.value);
+ case 'I':
+ return new ConstExprent(VarType.VARTYPE_INT, cn.value);
+ case 'J':
+ return new ConstExprent(VarType.VARTYPE_LONG, cn.value);
+ case 'S':
+ return new ConstExprent(VarType.VARTYPE_SHORT, cn.value);
+ case 'Z':
+ return new ConstExprent(VarType.VARTYPE_BOOLEAN, cn.value);
+ case 's':
+ return new ConstExprent(VarType.VARTYPE_STRING, cn.value);
+ default:
+ throw new RuntimeException("invalid element type!");
+ }
+ }
+ }
+
+ public List<AnnotationExprent> getAnnotations() {
+ return annotations;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructAnnotationParameterAttribute.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructAnnotationParameterAttribute.java
new file mode 100644
index 000000000000..a33c7bbebe06
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructAnnotationParameterAttribute.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.struct.attr;
+
+import org.jetbrains.java.decompiler.modules.decompiler.exps.AnnotationExprent;
+import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class StructAnnotationParameterAttribute extends StructGeneralAttribute {
+
+ private List<List<AnnotationExprent>> paramAnnotations;
+
+ @Override
+ public void initContent(ConstantPool pool) throws IOException {
+ DataInputStream data = stream();
+
+ int len = data.readUnsignedByte();
+ if (len > 0) {
+ paramAnnotations = new ArrayList<List<AnnotationExprent>>(len);
+ for (int i = 0; i < len; i++) {
+ List<AnnotationExprent> annotations = StructAnnotationAttribute.parseAnnotations(pool, data);
+ paramAnnotations.add(annotations);
+ }
+ }
+ else {
+ paramAnnotations = Collections.emptyList();
+ }
+ }
+
+ public List<List<AnnotationExprent>> getParamAnnotations() {
+ return paramAnnotations;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructAnnotationTypeAttribute.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructAnnotationTypeAttribute.java
new file mode 100644
index 000000000000..59324e35654d
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructAnnotationTypeAttribute.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.struct.attr;
+
+import org.jetbrains.java.decompiler.modules.decompiler.exps.AnnotationExprent;
+import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class StructAnnotationTypeAttribute extends StructGeneralAttribute {
+
+ private static final int ANNOTATION_TARGET_TYPE_GENERIC_CLASS = 0x00;
+ private static final int ANNOTATION_TARGET_TYPE_GENERIC_METHOD = 0x01;
+ private static final int ANNOTATION_TARGET_TYPE_EXTENDS_IMPLEMENTS = 0x10;
+ private static final int ANNOTATION_TARGET_TYPE_GENERIC_CLASS_BOUND = 0x11;
+ private static final int ANNOTATION_TARGET_TYPE_GENERIC_METHOD_BOUND = 0x12;
+ private static final int ANNOTATION_TARGET_TYPE_FIELD = 0x13;
+ private static final int ANNOTATION_TARGET_TYPE_RETURN = 0x14;
+ private static final int ANNOTATION_TARGET_TYPE_RECEIVER = 0x15;
+ private static final int ANNOTATION_TARGET_TYPE_FORMAL = 0x16;
+ private static final int ANNOTATION_TARGET_TYPE_THROWS = 0x17;
+ private static final int ANNOTATION_TARGET_TYPE_LOCAL_VARIABLE = 0x40;
+ private static final int ANNOTATION_TARGET_TYPE_RESOURCE_VARIABLE = 0x41;
+ private static final int ANNOTATION_TARGET_TYPE_EXCEPTION = 0x42;
+ private static final int ANNOTATION_TARGET_TYPE_INSTANCEOF = 0x43;
+ private static final int ANNOTATION_TARGET_TYPE_NEW = 0x44;
+ private static final int ANNOTATION_TARGET_TYPE_DOUBLE_COLON_NEW = 0x45;
+ private static final int ANNOTATION_TARGET_TYPE_DOUBLE_COLON_ID = 0x46;
+ private static final int ANNOTATION_TARGET_TYPE_CAST = 0x47;
+ private static final int ANNOTATION_TARGET_TYPE_INVOCATION_CONSTRUCTOR = 0x48;
+ private static final int ANNOTATION_TARGET_TYPE_INVOCATION_METHOD = 0x49;
+ private static final int ANNOTATION_TARGET_TYPE_GENERIC_DOUBLE_COLON_NEW = 0x4A;
+ private static final int ANNOTATION_TARGET_TYPE_GENERIC_DOUBLE_COLON_ID = 0x4B;
+
+ private static final int ANNOTATION_TARGET_UNION_TYPE_PARAMETER = 1;
+ private static final int ANNOTATION_TARGET_UNION_SUPERTYPE = 2;
+ private static final int ANNOTATION_TARGET_UNION_TYPE_PARAMETER_BOUND = 3;
+ private static final int ANNOTATION_TARGET_UNION_EMPTY = 4;
+ private static final int ANNOTATION_TARGET_UNION_FORMAL_PARAMETER = 5;
+ private static final int ANNOTATION_TARGET_UNION_THROWS = 6;
+ private static final int ANNOTATION_TARGET_UNION_LOCAL_VAR = 7;
+ private static final int ANNOTATION_TARGET_UNION_CATCH = 8;
+ private static final int ANNOTATION_TARGET_UNION_OFFSET = 9;
+ private static final int ANNOTATION_TARGET_UNION_TYPE_ARGUMENT = 10;
+
+ @SuppressWarnings("FieldCanBeLocal") private List<AnnotationLocation> locations;
+ @SuppressWarnings("FieldCanBeLocal") private List<AnnotationExprent> annotations;
+
+ @Override
+ public void initContent(ConstantPool pool) throws IOException {
+ DataInputStream data = stream();
+
+ int len = data.readUnsignedByte();
+ if (len > 0) {
+ locations = new ArrayList<AnnotationLocation>(len);
+ annotations = new ArrayList<AnnotationExprent>(len);
+ for (int i = 0; i < len; i++) {
+ locations.add(parseAnnotationLocation(data));
+ annotations.add(StructAnnotationAttribute.parseAnnotation(data, pool));
+ }
+ }
+ else {
+ locations = Collections.emptyList();
+ annotations = Collections.emptyList();
+ }
+ }
+
+ private static AnnotationLocation parseAnnotationLocation(DataInputStream data) throws IOException {
+ AnnotationLocation ann_location = new AnnotationLocation();
+
+ // target type
+ ann_location.target_type = data.readUnsignedByte();
+
+ // target union
+ switch (ann_location.target_type) {
+ case ANNOTATION_TARGET_TYPE_GENERIC_CLASS:
+ case ANNOTATION_TARGET_TYPE_GENERIC_METHOD:
+ ann_location.target_union = ANNOTATION_TARGET_UNION_TYPE_PARAMETER;
+ break;
+ case ANNOTATION_TARGET_TYPE_EXTENDS_IMPLEMENTS:
+ ann_location.target_union = ANNOTATION_TARGET_UNION_SUPERTYPE;
+ break;
+ case ANNOTATION_TARGET_TYPE_GENERIC_CLASS_BOUND:
+ case ANNOTATION_TARGET_TYPE_GENERIC_METHOD_BOUND:
+ ann_location.target_union = ANNOTATION_TARGET_UNION_TYPE_PARAMETER_BOUND;
+ break;
+ case ANNOTATION_TARGET_TYPE_FIELD:
+ case ANNOTATION_TARGET_TYPE_RETURN:
+ case ANNOTATION_TARGET_TYPE_RECEIVER:
+ ann_location.target_union = ANNOTATION_TARGET_UNION_EMPTY;
+ break;
+ case ANNOTATION_TARGET_TYPE_FORMAL:
+ ann_location.target_union = ANNOTATION_TARGET_UNION_FORMAL_PARAMETER;
+ break;
+ case ANNOTATION_TARGET_TYPE_THROWS:
+ ann_location.target_union = ANNOTATION_TARGET_UNION_THROWS;
+ break;
+ case ANNOTATION_TARGET_TYPE_LOCAL_VARIABLE:
+ case ANNOTATION_TARGET_TYPE_RESOURCE_VARIABLE:
+ ann_location.target_union = ANNOTATION_TARGET_UNION_LOCAL_VAR;
+ break;
+ case ANNOTATION_TARGET_TYPE_EXCEPTION:
+ ann_location.target_union = ANNOTATION_TARGET_UNION_CATCH;
+ break;
+ case ANNOTATION_TARGET_TYPE_INSTANCEOF:
+ case ANNOTATION_TARGET_TYPE_NEW:
+ case ANNOTATION_TARGET_TYPE_DOUBLE_COLON_NEW:
+ case ANNOTATION_TARGET_TYPE_DOUBLE_COLON_ID:
+ ann_location.target_union = ANNOTATION_TARGET_UNION_OFFSET;
+ break;
+ case ANNOTATION_TARGET_TYPE_CAST:
+ case ANNOTATION_TARGET_TYPE_INVOCATION_CONSTRUCTOR:
+ case ANNOTATION_TARGET_TYPE_INVOCATION_METHOD:
+ case ANNOTATION_TARGET_TYPE_GENERIC_DOUBLE_COLON_NEW:
+ case ANNOTATION_TARGET_TYPE_GENERIC_DOUBLE_COLON_ID:
+ ann_location.target_union = ANNOTATION_TARGET_UNION_TYPE_ARGUMENT;
+ break;
+ default:
+ throw new RuntimeException("Unknown target type in a type annotation!");
+ }
+
+ // target union data
+
+ switch (ann_location.target_union) {
+ case ANNOTATION_TARGET_UNION_TYPE_PARAMETER:
+ case ANNOTATION_TARGET_UNION_FORMAL_PARAMETER:
+ ann_location.data = new int[]{data.readUnsignedByte()};
+ break;
+ case ANNOTATION_TARGET_UNION_SUPERTYPE:
+ case ANNOTATION_TARGET_UNION_THROWS:
+ case ANNOTATION_TARGET_UNION_CATCH:
+ case ANNOTATION_TARGET_UNION_OFFSET:
+ ann_location.data = new int[]{data.readUnsignedShort()};
+ break;
+ case ANNOTATION_TARGET_UNION_TYPE_PARAMETER_BOUND:
+ ann_location.data = new int[]{data.readUnsignedByte(), data.readUnsignedByte()};
+ break;
+ case ANNOTATION_TARGET_UNION_EMPTY:
+ break;
+ case ANNOTATION_TARGET_UNION_LOCAL_VAR:
+ int table_length = data.readUnsignedShort();
+
+ ann_location.data = new int[table_length * 3 + 1];
+ ann_location.data[0] = table_length;
+
+ for (int i = 0; i < table_length; ++i) {
+ ann_location.data[3 * i + 1] = data.readUnsignedShort();
+ ann_location.data[3 * i + 2] = data.readUnsignedShort();
+ ann_location.data[3 * i + 3] = data.readUnsignedShort();
+ }
+ break;
+ case ANNOTATION_TARGET_UNION_TYPE_ARGUMENT:
+ ann_location.data = new int[]{data.readUnsignedShort(), data.readUnsignedByte()};
+ }
+
+ // target path
+ int path_length = data.readUnsignedByte();
+
+ ann_location.target_path_kind = new int[path_length];
+ ann_location.target_argument_index = new int[path_length];
+
+ for (int i = 0; i < path_length; ++i) {
+ ann_location.target_path_kind[i] = data.readUnsignedByte();
+ ann_location.target_argument_index[i] = data.readUnsignedByte();
+ }
+
+ return ann_location;
+ }
+
+ private static class AnnotationLocation {
+ public int target_type;
+ public int target_union;
+ public int[] data;
+ public int[] target_path_kind;
+ public int[] target_argument_index;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructBootstrapMethodsAttribute.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructBootstrapMethodsAttribute.java
new file mode 100644
index 000000000000..840acc7456f4
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructBootstrapMethodsAttribute.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.struct.attr;
+
+import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
+import org.jetbrains.java.decompiler.struct.consts.LinkConstant;
+import org.jetbrains.java.decompiler.struct.consts.PooledConstant;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class StructBootstrapMethodsAttribute extends StructGeneralAttribute {
+
+ private List<LinkConstant> methodRefs = new ArrayList<LinkConstant>();
+ private List<List<PooledConstant>> methodArguments = new ArrayList<List<PooledConstant>>();
+
+ @Override
+ public void initContent(ConstantPool pool) throws IOException {
+ DataInputStream data = stream();
+
+ int method_number = data.readUnsignedShort();
+
+ for (int i = 0; i < method_number; ++i) {
+ int bootstrap_method_ref = data.readUnsignedShort();
+ int num_bootstrap_arguments = data.readUnsignedShort();
+
+ List<PooledConstant> list_arguments = new ArrayList<PooledConstant>();
+
+ for (int j = 0; j < num_bootstrap_arguments; ++j) {
+ int bootstrap_argument_ref = data.readUnsignedShort();
+
+ list_arguments.add(pool.getConstant(bootstrap_argument_ref));
+ }
+
+ methodRefs.add(pool.getLinkConstant(bootstrap_method_ref));
+ methodArguments.add(list_arguments);
+ }
+ }
+
+ public int getMethodsNumber() {
+ return methodRefs.size();
+ }
+
+ public LinkConstant getMethodReference(int index) {
+ return methodRefs.get(index);
+ }
+
+ public List<PooledConstant> getMethodArguments(int index) {
+ return methodArguments.get(index);
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructConstantValueAttribute.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructConstantValueAttribute.java
new file mode 100644
index 000000000000..07a507329dba
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructConstantValueAttribute.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.struct.attr;
+
+import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
+
+import java.io.IOException;
+
+public class StructConstantValueAttribute extends StructGeneralAttribute {
+
+ private int index;
+
+ @Override
+ public void initContent(ConstantPool pool) throws IOException {
+ index = stream().readUnsignedShort();
+ }
+
+ public int getIndex() {
+ return index;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructEnclosingMethodAttribute.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructEnclosingMethodAttribute.java
new file mode 100644
index 000000000000..c9b9ebb680ea
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructEnclosingMethodAttribute.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.struct.attr;
+
+import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
+import org.jetbrains.java.decompiler.struct.consts.LinkConstant;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+public class StructEnclosingMethodAttribute extends StructGeneralAttribute {
+
+ private String className;
+ private String methodName;
+ private String methodDescriptor;
+
+ @Override
+ public void initContent(ConstantPool pool) throws IOException {
+ DataInputStream data = stream();
+ int classIndex = data.readUnsignedShort();
+ int methodIndex = data.readUnsignedShort();
+
+ className = pool.getPrimitiveConstant(classIndex).getString();
+ if (methodIndex != 0) {
+ LinkConstant lk = pool.getLinkConstant(methodIndex);
+ methodName = lk.elementname;
+ methodDescriptor = lk.descriptor;
+ }
+ }
+
+ public String getClassName() {
+ return className;
+ }
+
+ public String getMethodDescriptor() {
+ return methodDescriptor;
+ }
+
+ public String getMethodName() {
+ return methodName;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructExceptionsAttribute.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructExceptionsAttribute.java
new file mode 100644
index 000000000000..5eda047ca5f9
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructExceptionsAttribute.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.struct.attr;
+
+import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class StructExceptionsAttribute extends StructGeneralAttribute {
+
+ private List<Integer> throwsExceptions;
+
+ @Override
+ public void initContent(ConstantPool pool) throws IOException {
+ DataInputStream data = stream();
+ int len = data.readUnsignedShort();
+ if (len > 0) {
+ throwsExceptions = new ArrayList<Integer>(len);
+ for (int i = 0; i < len; i++) {
+ throwsExceptions.add(data.readUnsignedShort());
+ }
+ }
+ else {
+ throwsExceptions = Collections.emptyList();
+ }
+ }
+
+ public String getExcClassname(int index, ConstantPool pool) {
+ return pool.getPrimitiveConstant(throwsExceptions.get(index).intValue()).getString();
+ }
+
+ public List<Integer> getThrowsExceptions() {
+ return throwsExceptions;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructGeneralAttribute.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructGeneralAttribute.java
new file mode 100644
index 000000000000..2cdc524e37a1
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructGeneralAttribute.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.struct.attr;
+
+import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
+import org.jetbrains.java.decompiler.util.DataInputFullStream;
+
+import java.io.IOException;
+
+/*
+ attribute_info {
+ u2 attribute_name_index;
+ u4 attribute_length;
+ u1 info[attribute_length];
+ }
+*/
+public class StructGeneralAttribute {
+
+ public static final String ATTRIBUTE_CODE = "Code";
+ public static final String ATTRIBUTE_INNER_CLASSES = "InnerClasses";
+ public static final String ATTRIBUTE_SIGNATURE = "Signature";
+ public static final String ATTRIBUTE_ANNOTATION_DEFAULT = "AnnotationDefault";
+ public static final String ATTRIBUTE_EXCEPTIONS = "Exceptions";
+ public static final String ATTRIBUTE_ENCLOSING_METHOD = "EnclosingMethod";
+ public static final String ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS = "RuntimeVisibleAnnotations";
+ public static final String ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS = "RuntimeInvisibleAnnotations";
+ public static final String ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS = "RuntimeVisibleParameterAnnotations";
+ public static final String ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS = "RuntimeInvisibleParameterAnnotations";
+ public static final String ATTRIBUTE_RUNTIME_VISIBLE_TYPE_ANNOTATIONS = "RuntimeVisibleTypeAnnotations";
+ public static final String ATTRIBUTE_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS = "RuntimeInvisibleTypeAnnotations";
+ public static final String ATTRIBUTE_LOCAL_VARIABLE_TABLE = "LocalVariableTable";
+ public static final String ATTRIBUTE_CONSTANT_VALUE = "ConstantValue";
+ public static final String ATTRIBUTE_BOOTSTRAP_METHODS = "BootstrapMethods";
+ public static final String ATTRIBUTE_SYNTHETIC = "Synthetic";
+ public static final String ATTRIBUTE_DEPRECATED = "Deprecated";
+
+ private String name;
+ private byte[] info;
+
+ public static StructGeneralAttribute createAttribute(String name) {
+ StructGeneralAttribute attr;
+
+ if (ATTRIBUTE_INNER_CLASSES.equals(name)) {
+ attr = new StructInnerClassesAttribute();
+ }
+ else if (ATTRIBUTE_CONSTANT_VALUE.equals(name)) {
+ attr = new StructConstantValueAttribute();
+ }
+ else if (ATTRIBUTE_SIGNATURE.equals(name)) {
+ attr = new StructGenericSignatureAttribute();
+ }
+ else if (ATTRIBUTE_ANNOTATION_DEFAULT.equals(name)) {
+ attr = new StructAnnDefaultAttribute();
+ }
+ else if (ATTRIBUTE_EXCEPTIONS.equals(name)) {
+ attr = new StructExceptionsAttribute();
+ }
+ else if (ATTRIBUTE_ENCLOSING_METHOD.equals(name)) {
+ attr = new StructEnclosingMethodAttribute();
+ }
+ else if (ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS.equals(name) ||
+ ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS.equals(name)) {
+ attr = new StructAnnotationAttribute();
+ }
+ else if (ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS.equals(name) ||
+ ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS.equals(name)) {
+ attr = new StructAnnotationParameterAttribute();
+ }
+ else if (ATTRIBUTE_RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(name) ||
+ ATTRIBUTE_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(name)) {
+ attr = new StructAnnotationTypeAttribute();
+ }
+ else if (ATTRIBUTE_LOCAL_VARIABLE_TABLE.equals(name)) {
+ attr = new StructLocalVariableTableAttribute();
+ }
+ else if (ATTRIBUTE_BOOTSTRAP_METHODS.equals(name)) {
+ attr = new StructBootstrapMethodsAttribute();
+ }
+ else if (ATTRIBUTE_SYNTHETIC.equals(name) ||
+ ATTRIBUTE_DEPRECATED.equals(name)) {
+ attr = new StructGeneralAttribute();
+ }
+ else {
+ // unsupported attribute
+ return null;
+ }
+
+ attr.name = name;
+ return attr;
+ }
+
+ protected DataInputFullStream stream() {
+ return new DataInputFullStream(info);
+ }
+
+ public void initContent(ConstantPool pool) throws IOException { }
+
+ public void setInfo(byte[] info) {
+ this.info = info;
+ }
+
+ public String getName() {
+ return name;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructGenericSignatureAttribute.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructGenericSignatureAttribute.java
new file mode 100644
index 000000000000..62c892f83b1a
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructGenericSignatureAttribute.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.struct.attr;
+
+import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
+
+import java.io.IOException;
+
+public class StructGenericSignatureAttribute extends StructGeneralAttribute {
+
+ private String signature;
+
+ @Override
+ public void initContent(ConstantPool pool) throws IOException {
+ int index = stream().readUnsignedShort();
+ signature = pool.getPrimitiveConstant(index).getString();
+ }
+
+ public String getSignature() {
+ return signature;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructInnerClassesAttribute.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructInnerClassesAttribute.java
new file mode 100644
index 000000000000..596948790460
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructInnerClassesAttribute.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.struct.attr;
+
+import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class StructInnerClassesAttribute extends StructGeneralAttribute {
+
+ private List<int[]> classEntries;
+ private List<String[]> stringEntries;
+
+ @Override
+ public void initContent(ConstantPool pool) throws IOException {
+ DataInputStream data = stream();
+
+ int len = data.readUnsignedShort();
+ if (len > 0) {
+ classEntries = new ArrayList<int[]>(len);
+ stringEntries = new ArrayList<String[]>(len);
+
+ for (int i = 0; i < len; i++) {
+ int[] classEntry = new int[4];
+ for (int j = 0; j < 4; j++) {
+ classEntry[j] = data.readUnsignedShort();
+ }
+ classEntries.add(classEntry);
+
+ // inner name, enclosing class, original simple name
+ String[] stringEntry = new String[3];
+ stringEntry[0] = pool.getPrimitiveConstant(classEntry[0]).getString();
+ if (classEntry[1] != 0) {
+ stringEntry[1] = pool.getPrimitiveConstant(classEntry[1]).getString();
+ }
+ if (classEntry[2] != 0) {
+ stringEntry[2] = pool.getPrimitiveConstant(classEntry[2]).getString();
+ }
+ stringEntries.add(stringEntry);
+ }
+ }
+ else {
+ classEntries = Collections.emptyList();
+ stringEntries = Collections.emptyList();
+ }
+ }
+
+ public List<int[]> getClassEntries() {
+ return classEntries;
+ }
+
+ public List<String[]> getStringEntries() {
+ return stringEntries;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTableAttribute.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTableAttribute.java
new file mode 100644
index 000000000000..60e40c013db6
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/attr/StructLocalVariableTableAttribute.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.struct.attr;
+
+import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
+import org.jetbrains.java.decompiler.util.DataInputFullStream;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/*
+ u2 local_variable_table_length;
+ local_variable {
+ u2 start_pc;
+ u2 length;
+ u2 name_index;
+ u2 descriptor_index;
+ u2 index;
+ }
+*/
+public class StructLocalVariableTableAttribute extends StructGeneralAttribute {
+
+ private Map<Integer, String> mapVarNames = new HashMap<Integer, String>();
+
+ @Override
+ public void initContent(ConstantPool pool) throws IOException {
+ DataInputFullStream data = stream();
+
+ int len = data.readUnsignedShort();
+ if (len > 0) {
+ mapVarNames = new HashMap<Integer, String>(len);
+ for (int i = 0; i < len; i++) {
+ data.discard(4);
+ int nameIndex = data.readUnsignedShort();
+ data.discard(2);
+ int varIndex = data.readUnsignedShort();
+ mapVarNames.put(varIndex, pool.getPrimitiveConstant(nameIndex).getString());
+ }
+ }
+ else {
+ mapVarNames = Collections.emptyMap();
+ }
+ }
+
+ public void addLocalVariableTable(StructLocalVariableTableAttribute attr) {
+ mapVarNames.putAll(attr.getMapVarNames());
+ }
+
+ public Map<Integer, String> getMapVarNames() {
+ return mapVarNames;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/consts/ConstantPool.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/consts/ConstantPool.java
new file mode 100644
index 000000000000..d534e6df6d3c
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/consts/ConstantPool.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.struct.consts;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.modules.renamer.PoolInterceptor;
+import org.jetbrains.java.decompiler.struct.gen.FieldDescriptor;
+import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor;
+import org.jetbrains.java.decompiler.struct.gen.VarType;
+import org.jetbrains.java.decompiler.util.DataInputFullStream;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class ConstantPool {
+
+ public static final int FIELD = 1;
+ public static final int METHOD = 2;
+
+ private List<PooledConstant> pool = new ArrayList<PooledConstant>();
+ private PoolInterceptor interceptor;
+
+
+ public ConstantPool(DataInputStream in) throws IOException {
+ int size = in.readUnsignedShort();
+ int[] pass = new int[size];
+
+ // first dummy constant
+ pool.add(null);
+
+ // first pass: read the elements
+ for (int i = 1; i < size; i++) {
+ byte tag = (byte)in.readUnsignedByte();
+
+ switch (tag) {
+ case CodeConstants.CONSTANT_Utf8:
+ pool.add(new PrimitiveConstant(CodeConstants.CONSTANT_Utf8, in.readUTF()));
+ break;
+ case CodeConstants.CONSTANT_Integer:
+ pool.add(new PrimitiveConstant(CodeConstants.CONSTANT_Integer, new Integer(in.readInt())));
+ break;
+ case CodeConstants.CONSTANT_Float:
+ pool.add(new PrimitiveConstant(CodeConstants.CONSTANT_Float, new Float(in.readFloat())));
+ break;
+ case CodeConstants.CONSTANT_Long:
+ pool.add(new PrimitiveConstant(CodeConstants.CONSTANT_Long, new Long(in.readLong())));
+ pool.add(null);
+ i++;
+ break;
+ case CodeConstants.CONSTANT_Double:
+ pool.add(new PrimitiveConstant(CodeConstants.CONSTANT_Double, new Double(in.readDouble())));
+ pool.add(null);
+ i++;
+ break;
+ case CodeConstants.CONSTANT_Class:
+ case CodeConstants.CONSTANT_String:
+ case CodeConstants.CONSTANT_MethodType:
+ pool.add(new PrimitiveConstant(tag, in.readUnsignedShort()));
+ pass[i] = 1;
+ break;
+ case CodeConstants.CONSTANT_Fieldref:
+ case CodeConstants.CONSTANT_Methodref:
+ case CodeConstants.CONSTANT_InterfaceMethodref:
+ case CodeConstants.CONSTANT_NameAndType:
+ case CodeConstants.CONSTANT_InvokeDynamic:
+ pool.add(new LinkConstant(tag, in.readUnsignedShort(), in.readUnsignedShort()));
+ if (tag == CodeConstants.CONSTANT_NameAndType) {
+ pass[i] = 1;
+ }
+ else {
+ pass[i] = 2;
+ }
+ break;
+ case CodeConstants.CONSTANT_MethodHandle:
+ pool.add(new LinkConstant(tag, in.readUnsignedByte(), in.readUnsignedShort()));
+ pass[i] = 3;
+ break;
+ }
+ }
+
+ // resolving complex pool elements
+ for (int passIndex = 1; passIndex <= 3; passIndex++) {
+ for (int i = 1; i < size; i++) {
+ if (pass[i] == passIndex) {
+ pool.get(i).resolveConstant(this);
+ }
+ }
+ }
+
+ // get global constant pool interceptor instance, if any available
+ interceptor = DecompilerContext.getPoolInterceptor();
+ }
+
+ public static void skipPool(DataInputFullStream in) throws IOException {
+ int size = in.readUnsignedShort();
+
+ for (int i = 1; i < size; i++) {
+ switch (in.readUnsignedByte()) {
+ case CodeConstants.CONSTANT_Utf8:
+ in.readUTF();
+ break;
+ case CodeConstants.CONSTANT_Integer:
+ case CodeConstants.CONSTANT_Float:
+ case CodeConstants.CONSTANT_Fieldref:
+ case CodeConstants.CONSTANT_Methodref:
+ case CodeConstants.CONSTANT_InterfaceMethodref:
+ case CodeConstants.CONSTANT_NameAndType:
+ case CodeConstants.CONSTANT_InvokeDynamic:
+ in.discard(4);
+ break;
+ case CodeConstants.CONSTANT_Long:
+ case CodeConstants.CONSTANT_Double:
+ in.discard(8);
+ i++;
+ break;
+ case CodeConstants.CONSTANT_Class:
+ case CodeConstants.CONSTANT_String:
+ case CodeConstants.CONSTANT_MethodType:
+ in.discard(2);
+ break;
+ case CodeConstants.CONSTANT_MethodHandle:
+ in.discard(3);
+ }
+ }
+ }
+
+ public int size() {
+ return pool.size();
+ }
+
+ public String[] getClassElement(int elementType, String className, int nameIndex, int descriptorIndex) {
+ String elementName = ((PrimitiveConstant)getConstant(nameIndex)).getString();
+ String descriptor = ((PrimitiveConstant)getConstant(descriptorIndex)).getString();
+
+ if (interceptor != null) {
+ String newElement = interceptor.getName(className + " " + elementName + " " + descriptor);
+ if (newElement != null) {
+ elementName = newElement.split(" ")[1];
+ }
+
+ int type = elementType == FIELD ? CodeConstants.CONSTANT_Fieldref : CodeConstants.CONSTANT_Methodref;
+ String newDescriptor = buildNewDescriptor(type, descriptor);
+ if (newDescriptor != null) {
+ descriptor = newDescriptor;
+ }
+ }
+
+ return new String[]{elementName, descriptor};
+ }
+
+ public PooledConstant getConstant(int index) {
+ return pool.get(index);
+ }
+
+ public PrimitiveConstant getPrimitiveConstant(int index) {
+ PrimitiveConstant cn = (PrimitiveConstant)getConstant(index);
+
+ if (cn != null && interceptor != null) {
+ if (cn.type == CodeConstants.CONSTANT_Class) {
+ String newName = buildNewClassname(cn.getString());
+ if (newName != null) {
+ cn = new PrimitiveConstant(CodeConstants.CONSTANT_Class, newName);
+ }
+ }
+ }
+
+ return cn;
+ }
+
+ public LinkConstant getLinkConstant(int index) {
+ LinkConstant ln = (LinkConstant)getConstant(index);
+
+ if (ln != null && interceptor != null &&
+ (ln.type == CodeConstants.CONSTANT_Fieldref ||
+ ln.type == CodeConstants.CONSTANT_Methodref ||
+ ln.type == CodeConstants.CONSTANT_InterfaceMethodref)) {
+ String newClassName = buildNewClassname(ln.classname);
+ String newElement = interceptor.getName(ln.classname + " " + ln.elementname + " " + ln.descriptor);
+ String newDescriptor = buildNewDescriptor(ln.type, ln.descriptor);
+
+ if (newClassName != null || newElement != null || newDescriptor != null) {
+ String className = newClassName == null ? ln.classname : newClassName;
+ String elementName = newElement == null ? ln.elementname : newElement.split(" ")[1];
+ String descriptor = newDescriptor == null ? ln.descriptor : newDescriptor;
+ ln = new LinkConstant(ln.type, className, elementName, descriptor);
+ }
+ }
+
+ return ln;
+ }
+
+ private String buildNewClassname(String className) {
+ VarType vt = new VarType(className, true);
+
+ String newName = interceptor.getName(vt.value);
+ if (newName != null) {
+ StringBuilder buffer = new StringBuilder();
+
+ if (vt.arraydim > 0) {
+ for (int i = 0; i < vt.arraydim; i++) {
+ buffer.append("[");
+ }
+
+ buffer.append("L").append(newName).append(";");
+ }
+ else {
+ buffer.append(newName);
+ }
+
+ return buffer.toString();
+ }
+
+ return null;
+ }
+
+ private String buildNewDescriptor(int type, String descriptor) {
+ boolean updated = false;
+
+ if (type == CodeConstants.CONSTANT_Fieldref) {
+ FieldDescriptor fd = FieldDescriptor.parseDescriptor(descriptor);
+
+ VarType fType = fd.type;
+ if (fType.type == CodeConstants.TYPE_OBJECT) {
+ String newClassName = buildNewClassname(fType.value);
+ if (newClassName != null) {
+ fType.value = newClassName;
+ updated = true;
+ }
+ }
+
+ if (updated) {
+ return fd.getDescriptor();
+ }
+ }
+ else {
+ MethodDescriptor md = MethodDescriptor.parseDescriptor(descriptor);
+
+ // parameters
+ for (VarType paramType : md.params) {
+ if (paramType.type == CodeConstants.TYPE_OBJECT) {
+ String newClassName = buildNewClassname(paramType.value);
+ if (newClassName != null) {
+ paramType.value = newClassName;
+ updated = true;
+ }
+ }
+ }
+
+ // return value
+ if (md.ret.type == CodeConstants.TYPE_OBJECT) {
+ String newClassName = buildNewClassname(md.ret.value);
+ if (newClassName != null) {
+ md.ret.value = newClassName;
+ updated = true;
+ }
+ }
+
+ if (updated) {
+ return md.getDescriptor();
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/consts/LinkConstant.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/consts/LinkConstant.java
new file mode 100644
index 000000000000..71bf14615558
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/consts/LinkConstant.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.struct.consts;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+/*
+ * NameAndType, FieldRef, MethodRef, InterfaceMethodref
+ * InvokeDynamic, MethodHandle
+ */
+
+public class LinkConstant extends PooledConstant {
+
+ // *****************************************************************************
+ // public fields
+ // *****************************************************************************
+
+ public int index1, index2;
+
+ public String classname;
+
+ public String elementname;
+
+ public String descriptor;
+
+ public int paramCount = 0;
+
+ public boolean isVoid = false;
+
+ public boolean returnCategory2 = false;
+
+
+ // *****************************************************************************
+ // constructors
+ // *****************************************************************************
+
+ public LinkConstant(int type, String classname, String elementname, String descriptor) {
+ this.type = type;
+ this.classname = classname;
+ this.elementname = elementname;
+ this.descriptor = descriptor;
+
+ initConstant();
+ }
+
+ public LinkConstant(int type, int index1, int index2) {
+ this.type = type;
+ this.index1 = index1;
+ this.index2 = index2;
+ }
+
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public void resolveConstant(ConstantPool pool) {
+
+ if (type == CONSTANT_NameAndType) {
+ elementname = pool.getPrimitiveConstant(index1).getString();
+ descriptor = pool.getPrimitiveConstant(index2).getString();
+ }
+ else if (type == CONSTANT_MethodHandle) {
+ LinkConstant ref_info = pool.getLinkConstant(index2);
+
+ classname = ref_info.classname;
+ elementname = ref_info.elementname;
+ descriptor = ref_info.descriptor;
+ }
+ else {
+ if (type != CONSTANT_InvokeDynamic) {
+ classname = pool.getPrimitiveConstant(index1).getString();
+ }
+
+ LinkConstant nametype = pool.getLinkConstant(index2);
+ elementname = nametype.elementname;
+ descriptor = nametype.descriptor;
+ }
+
+ initConstant();
+ }
+
+ public void writeToStream(DataOutputStream out) throws IOException {
+ out.writeByte(type);
+ if (type == CONSTANT_MethodHandle) {
+ out.writeByte(index1);
+ }
+ else {
+ out.writeShort(index1);
+ }
+ out.writeShort(index2);
+ }
+
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof LinkConstant)) return false;
+
+ LinkConstant cn = (LinkConstant)o;
+ return this.type == cn.type &&
+ this.elementname.equals(cn.elementname) &&
+ this.descriptor.equals(cn.descriptor) &&
+ (this.type != CONSTANT_NameAndType || this.classname.equals(cn.classname));
+ }
+
+ // *****************************************************************************
+ // private methods
+ // *****************************************************************************
+
+ private void initConstant() {
+
+ if (type == CONSTANT_Methodref ||
+ type == CONSTANT_InterfaceMethodref ||
+ type == CONSTANT_InvokeDynamic ||
+ type == CONSTANT_MethodHandle) {
+ resolveDescriptor(descriptor);
+ }
+ else if (type == CONSTANT_Fieldref) {
+ returnCategory2 = ("D".equals(descriptor) || "J".equals(descriptor));
+ }
+ }
+
+ private void resolveDescriptor(String descr) {
+
+ String[] arr = descr.split("[()]");
+ String par = arr[1];
+
+ int index = 0, counter = 0;
+ int len = par.length();
+
+ while (index < len) {
+
+ char c = par.charAt(index);
+ if (c == 'L') {
+ index = par.indexOf(";", index);
+ }
+ else if (c == '[') {
+ index++;
+ continue;
+ }
+
+ counter++;
+ index++;
+ }
+
+ paramCount = counter;
+ isVoid = "V".equals(arr[2]);
+ returnCategory2 = ("D".equals(arr[2]) || "J".equals(arr[2]));
+ }
+}
+
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/consts/PooledConstant.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/consts/PooledConstant.java
new file mode 100644
index 000000000000..d3d30c0d1540
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/consts/PooledConstant.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.struct.consts;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+/*
+ cp_info {
+ u1 tag;
+ u1 info[];
+ }
+
+*/
+
+public class PooledConstant implements CodeConstants, VariableTypeEnum {
+
+ // *****************************************************************************
+ // public fields
+ // *****************************************************************************
+
+ public int type;
+
+ public boolean own = false;
+
+ public int returnType;
+
+
+ // *****************************************************************************
+ // private fields
+ // *****************************************************************************
+
+ private Object[] values;
+
+ // *****************************************************************************
+ // constructors
+ // *****************************************************************************
+
+ public PooledConstant() {
+ }
+
+ public PooledConstant(int type, Object[] values) {
+ this.type = type;
+ this.values = values;
+ this.returnType = poolTypeToIntern(type);
+ }
+
+ public PooledConstant(int type, boolean own, Object[] values) {
+ this.type = type;
+ this.own = own;
+ this.values = values;
+ this.returnType = poolTypeToIntern(type);
+ }
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public void resolveConstant(ConstantPool pool) {
+ // to be overwritten
+ }
+
+ public void writeToStream(DataOutputStream out) throws IOException {
+ // to be overwritten
+ }
+
+ public int poolTypeToIntern(int type) {
+
+ switch (type) {
+ case CONSTANT_Integer:
+ return INT;
+ case CONSTANT_Float:
+ return FLOAT;
+ case CONSTANT_Long:
+ return LONG;
+ case CONSTANT_Double:
+ return DOUBLE;
+ case CONSTANT_String:
+ case CONSTANT_Class: // 1.5 -> ldc class
+ return REFERENCE;
+ default:
+ throw new RuntimeException("Huh?? What are you trying to load?");
+ }
+ }
+
+ public Object getValue(int index) {
+ return values[index];
+ }
+
+
+ // *****************************************************************************
+ // getter and setter methods
+ // *****************************************************************************
+
+ public Object[] getValues() {
+ return values;
+ }
+
+ public void setValues(Object[] values) {
+ this.values = values;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/consts/PrimitiveConstant.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/consts/PrimitiveConstant.java
new file mode 100644
index 000000000000..4cd4dd88dff7
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/consts/PrimitiveConstant.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.struct.consts;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+/*
+ * Integer, Long, Float, Double, String, Class, UTF8
+ */
+
+public class PrimitiveConstant extends PooledConstant {
+
+ // *****************************************************************************
+ // public fields
+ // *****************************************************************************
+
+ public int index;
+
+ public Object value;
+
+ public boolean isArray;
+
+ // *****************************************************************************
+ // constructors
+ // *****************************************************************************
+
+ public PrimitiveConstant(int type, Object value) {
+ this.type = type;
+ this.value = value;
+
+ initConstant();
+ }
+
+ public PrimitiveConstant(int type, int index) {
+ this.type = type;
+ this.index = index;
+ }
+
+ // *****************************************************************************
+ // public methods
+ // *****************************************************************************
+
+ public int getInt() {
+ return ((Integer)value).intValue();
+ }
+
+ public long getLong() {
+ return ((Long)value).longValue();
+ }
+
+ public float getFloat() {
+ return ((Float)value).floatValue();
+ }
+
+ public double getDouble() {
+ return ((Double)value).doubleValue();
+ }
+
+ public String getString() {
+ return (String)value;
+ }
+
+ public void resolveConstant(ConstantPool pool) {
+
+ if (type == CONSTANT_Class || type == CONSTANT_String || type == CONSTANT_MethodType) {
+ value = pool.getPrimitiveConstant(index).getString();
+ initConstant();
+ }
+ }
+
+ public void writeToStream(DataOutputStream out) throws IOException {
+
+ out.writeByte(type);
+ switch (type) {
+ case CONSTANT_Integer:
+ out.writeInt(getInt());
+ break;
+ case CONSTANT_Float:
+ out.writeFloat(getFloat());
+ break;
+ case CONSTANT_Long:
+ out.writeLong(getLong());
+ break;
+ case CONSTANT_Double:
+ out.writeDouble(getDouble());
+ break;
+ case CONSTANT_Utf8:
+ out.writeUTF(getString());
+ break;
+ default: // CONSTANT_Class, CONSTANT_String, CONSTANT_MethodType
+ out.writeShort(index);
+ }
+ }
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof PrimitiveConstant)) return false;
+
+ PrimitiveConstant cn = (PrimitiveConstant)o;
+ return this.type == cn.type &&
+ this.isArray == cn.isArray &&
+ this.value.equals(cn.value);
+ }
+
+ private void initConstant() {
+ if (type == CONSTANT_Class) {
+ String className = getString();
+ isArray =
+ (className.length() > 0 && className.charAt(0) == '['); // empty string for a class name seems to be possible in some android files
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/consts/VariableTypeEnum.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/consts/VariableTypeEnum.java
new file mode 100644
index 000000000000..7950d5bad47b
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/consts/VariableTypeEnum.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.struct.consts;
+
+public interface VariableTypeEnum {
+
+ int BOOLEAN = 1;
+ int BYTE = 2;
+ int CHAR = 3;
+ int SHORT = 4;
+ int INT = 5;
+ int FLOAT = 6;
+ int LONG = 7;
+ int DOUBLE = 8;
+ int RETURN_ADDRESS = 9;
+ int REFERENCE = 10;
+ int INSTANCE_UNINITIALIZED = 11;
+ int VALUE_UNKNOWN = 12;
+ int VOID = 13;
+
+ Integer BOOLEAN_OBJ = new Integer(BOOLEAN);
+ Integer BYTE_OBJ = new Integer(BYTE);
+ Integer CHAR_OBJ = new Integer(CHAR);
+ Integer SHORT_OBJ = new Integer(SHORT);
+ Integer INT_OBJ = new Integer(INT);
+ Integer FLOAT_OBJ = new Integer(FLOAT);
+ Integer LONG_OBJ = new Integer(LONG);
+ Integer DOUBLE_OBJ = new Integer(DOUBLE);
+ Integer RETURN_ADDRESS_OBJ = new Integer(RETURN_ADDRESS);
+ Integer REFERENCE_OBJ = new Integer(REFERENCE);
+ Integer INSTANCE_UNINITIALIZED_OBJ = new Integer(INSTANCE_UNINITIALIZED);
+ Integer VALUE_UNKNOWN_OBJ = new Integer(VALUE_UNKNOWN);
+ Integer VOID_OBJ = new Integer(VOID);
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/DataPoint.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/DataPoint.java
new file mode 100644
index 000000000000..65a621308087
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/DataPoint.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.struct.gen;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.struct.StructMethod;
+import org.jetbrains.java.decompiler.util.ListStack;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class DataPoint {
+
+ private List<VarType> localVariables = new ArrayList<VarType>();
+
+ private ListStack<VarType> stack = new ListStack<VarType>();
+
+
+ public void setVariable(int index, VarType value) {
+ if (index >= localVariables.size()) {
+ for (int i = localVariables.size(); i <= index; i++) {
+ localVariables.add(new VarType(CodeConstants.TYPE_NOTINITIALIZED));
+ }
+ }
+
+ localVariables.set(index, value);
+ }
+
+ public VarType getVariable(int index) {
+ if (index < localVariables.size()) {
+ return localVariables.get(index);
+ }
+ else if (index < 0) {
+ throw new IndexOutOfBoundsException();
+ }
+ else {
+ return new VarType(CodeConstants.TYPE_NOTINITIALIZED);
+ }
+ }
+
+ public DataPoint copy() {
+ DataPoint point = new DataPoint();
+ point.setLocalVariables(new ArrayList<VarType>(localVariables));
+ point.setStack(stack.clone());
+ return point;
+ }
+
+ public static DataPoint getInitialDataPoint(StructMethod mt) {
+
+ DataPoint point = new DataPoint();
+
+ MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
+
+ int k = 0;
+ if (!mt.hasModifier(CodeConstants.ACC_STATIC)) {
+ point.setVariable(k++, new VarType(CodeConstants.TYPE_OBJECT, 0, null));
+ }
+
+ for (int i = 0; i < md.params.length; i++) {
+ VarType var = md.params[i];
+
+ point.setVariable(k++, var);
+ if (var.stack_size == 2) {
+ point.setVariable(k++, new VarType(CodeConstants.TYPE_GROUP2EMPTY));
+ }
+ }
+
+ return point;
+ }
+
+
+ public List<VarType> getLocalVariables() {
+ return localVariables;
+ }
+
+ public void setLocalVariables(List<VarType> localVariables) {
+ this.localVariables = localVariables;
+ }
+
+ public ListStack<VarType> getStack() {
+ return stack;
+ }
+
+ public void setStack(ListStack<VarType> stack) {
+ this.stack = stack;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/FieldDescriptor.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/FieldDescriptor.java
new file mode 100644
index 000000000000..fd213f05293a
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/FieldDescriptor.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.struct.gen;
+
+public class FieldDescriptor {
+
+ public static final FieldDescriptor INTEGER_DESCRIPTOR = parseDescriptor("Ljava/lang/Integer;");
+ public static final FieldDescriptor LONG_DESCRIPTOR = parseDescriptor("Ljava/lang/Long;");
+ public static final FieldDescriptor FLOAT_DESCRIPTOR = parseDescriptor("Ljava/lang/Float;");
+ public static final FieldDescriptor DOUBLE_DESCRIPTOR = parseDescriptor("Ljava/lang/Double;");
+
+ public VarType type;
+
+ public String descriptorString;
+
+ private FieldDescriptor() {
+ }
+
+ public static FieldDescriptor parseDescriptor(String descr) {
+
+ FieldDescriptor fd = new FieldDescriptor();
+
+ fd.type = new VarType(descr);
+ fd.descriptorString = descr;
+
+ return fd;
+ }
+
+ public String getDescriptor() {
+ return type.toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof FieldDescriptor)) return false;
+
+ FieldDescriptor fd = (FieldDescriptor)o;
+ return type.equals(fd.type);
+ }
+
+ @Override
+ public int hashCode() {
+ return type.hashCode();
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/MethodDescriptor.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/MethodDescriptor.java
new file mode 100644
index 000000000000..7dbc16c317f2
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/MethodDescriptor.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.struct.gen;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class MethodDescriptor {
+
+ public VarType[] params;
+
+ public VarType ret;
+
+
+ public static MethodDescriptor parseDescriptor(String mdescr) {
+
+ MethodDescriptor md = new MethodDescriptor();
+
+ List<String> lst = new ArrayList<String>();
+ String[] pars = mdescr.split("[()]");
+
+ String par = pars[1];
+
+ int indexFrom = -1, ind, index = 0;
+ int len = par.length();
+
+ for (; index < len; index++) {
+
+ switch (par.charAt(index)) {
+ case '[':
+ if (indexFrom < 0) {
+ indexFrom = index;
+ }
+ break;
+ case 'L':
+ ind = par.indexOf(";", index);
+ lst.add(par.substring(indexFrom < 0 ? index : indexFrom, ind + 1));
+ index = ind;
+ indexFrom = -1;
+ break;
+ default:
+ lst.add(par.substring(indexFrom < 0 ? index : indexFrom, index + 1));
+ indexFrom = -1;
+ }
+ }
+
+ lst.add(pars[2]);
+
+
+ md.params = new VarType[lst.size() - 1];
+
+ int i = 0;
+ for (; i < lst.size() - 1; i++) {
+ md.params[i] = new VarType(lst.get(i));
+ }
+ md.ret = new VarType(lst.get(i));
+
+ return md;
+ }
+
+ public String getDescriptor() {
+ String res = "(";
+
+ for (int j = 0; j < params.length; j++) {
+ res += params[j].toString();
+ }
+
+ res += ")" + ret.toString();
+
+ return res;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof MethodDescriptor)) return false;
+
+ MethodDescriptor md = (MethodDescriptor)o;
+ return ret.equals(md.ret) && Arrays.equals(params, md.params);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = ret.hashCode();
+ result = 31 * result + params.length;
+ return result;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/VarType.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/VarType.java
new file mode 100644
index 000000000000..a58898a1906d
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/VarType.java
@@ -0,0 +1,422 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.struct.gen;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+
+public class VarType { // TODO: optimize switch
+
+ public static final int FALSEBOOLEAN = 1;
+
+ public static final VarType VARTYPE_UNKNOWN = new VarType(CodeConstants.TYPE_UNKNOWN);
+ public static final VarType VARTYPE_INT = new VarType(CodeConstants.TYPE_INT);
+ public static final VarType VARTYPE_FLOAT = new VarType(CodeConstants.TYPE_FLOAT);
+ public static final VarType VARTYPE_LONG = new VarType(CodeConstants.TYPE_LONG);
+ public static final VarType VARTYPE_DOUBLE = new VarType(CodeConstants.TYPE_DOUBLE);
+ public static final VarType VARTYPE_BYTE = new VarType(CodeConstants.TYPE_BYTE);
+ public static final VarType VARTYPE_CHAR = new VarType(CodeConstants.TYPE_CHAR);
+ public static final VarType VARTYPE_SHORT = new VarType(CodeConstants.TYPE_SHORT);
+ public static final VarType VARTYPE_BOOLEAN = new VarType(CodeConstants.TYPE_BOOLEAN);
+ public static final VarType VARTYPE_BYTECHAR = new VarType(CodeConstants.TYPE_BYTECHAR);
+ public static final VarType VARTYPE_SHORTCHAR = new VarType(CodeConstants.TYPE_SHORTCHAR);
+
+ public static final VarType VARTYPE_NULL = new VarType(CodeConstants.TYPE_NULL, 0, null);
+ public static final VarType VARTYPE_GROUP2EMPTY = new VarType(CodeConstants.TYPE_GROUP2EMPTY);
+ public static final VarType VARTYPE_STRING = new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/String");
+ public static final VarType VARTYPE_CLASS = new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/Class");
+ public static final VarType VARTYPE_OBJECT = new VarType(CodeConstants.TYPE_OBJECT, 0, "java/lang/Object");
+ public static final VarType VARTYPE_VOID = new VarType(CodeConstants.TYPE_VOID);
+
+ public int type;
+
+ public int type_family;
+
+ public int arraydim;
+
+ public String value;
+
+ public int stack_size;
+
+ public int convinfo;
+
+ public VarType(int type) {
+ this.type = type;
+ this.arraydim = 0;
+
+ value = getChar(type);
+ setStackSize(type);
+ setFamily();
+ }
+
+ public VarType(int type, int arraydim) {
+ this(type);
+ this.arraydim = arraydim;
+ setFamily();
+ }
+
+ public VarType(int type, int arraydim, String value) {
+ this(type);
+ this.arraydim = arraydim;
+ this.value = value;
+ setFamily();
+ }
+
+ public VarType(String strtype) {
+ this(strtype, false);
+ }
+
+ public VarType(String strtype, boolean cltype) {
+ parseTypeString(strtype, cltype);
+ setStackSize(type);
+ setFamily();
+ }
+
+ public void decArrayDim() {
+ if (arraydim > 0) {
+ arraydim--;
+ setFamily();
+ }
+ else {
+ // throw new RuntimeException("array dimension equals 0!"); FIXME: investigate this case
+ }
+ }
+
+ public String toString() {
+ String res = "";
+
+ for (int i = 0; i < arraydim; i++) {
+ res += "[";
+ }
+
+ if (type == CodeConstants.TYPE_OBJECT) {
+ res += "L" + value + ";";
+ }
+ else {
+ res += value;
+ }
+
+ return res;
+ }
+
+ public VarType copy() {
+ VarType v = new VarType(type, arraydim, value);
+ v.convinfo = convinfo;
+ return v;
+ }
+
+ public boolean isFalseBoolean() {
+ return (convinfo & FALSEBOOLEAN) != 0;
+ }
+
+ public boolean isSuperset(VarType val) {
+
+ return this.equals(val) || this.isStrictSuperset(val);
+ }
+
+ public boolean isStrictSuperset(VarType val) {
+
+ int valtype = val.type;
+
+ if (valtype == CodeConstants.TYPE_UNKNOWN && type != CodeConstants.TYPE_UNKNOWN) {
+ return true;
+ }
+
+ if (val.arraydim > 0) {
+ return this.equals(VARTYPE_OBJECT);
+ }
+ else if (arraydim > 0) {
+ return (valtype == CodeConstants.TYPE_NULL);
+ }
+
+ boolean res = false;
+
+ switch (type) {
+ case CodeConstants.TYPE_INT:
+ res |= (valtype == CodeConstants.TYPE_SHORT ||
+ valtype == CodeConstants.TYPE_CHAR);
+ case CodeConstants.TYPE_SHORT:
+ res |= (valtype == CodeConstants.TYPE_BYTE);
+ case CodeConstants.TYPE_CHAR:
+ res |= (valtype == CodeConstants.TYPE_SHORTCHAR);
+ case CodeConstants.TYPE_BYTE:
+ case CodeConstants.TYPE_SHORTCHAR:
+ res |= (valtype == CodeConstants.TYPE_BYTECHAR);
+ case CodeConstants.TYPE_BYTECHAR:
+ res |= (valtype == CodeConstants.TYPE_BOOLEAN);
+ break;
+ case CodeConstants.TYPE_OBJECT:
+ if (valtype == CodeConstants.TYPE_NULL) {
+ return true;
+ }
+ else if (this.equals(VARTYPE_OBJECT)) {
+ return valtype == CodeConstants.TYPE_OBJECT &&
+ !val.equals(VARTYPE_OBJECT);
+ }
+ }
+
+ return res;
+ }
+
+ // type1 and type2 must not be null
+ public static VarType getCommonMinType(VarType type1, VarType type2) {
+
+ if (type1.type == CodeConstants.TYPE_BOOLEAN && type2.type == CodeConstants.TYPE_BOOLEAN) { // special case booleans
+ return type1.isFalseBoolean() ? type2 : type1;
+ }
+
+ if (type1.isSuperset(type2)) {
+ return type2;
+ }
+ else if (type2.isSuperset(type1)) {
+ return type1;
+ }
+ else if (type1.type_family == type2.type_family) {
+ switch (type1.type_family) {
+ case CodeConstants.TYPE_FAMILY_INTEGER:
+ if ((type1.type == CodeConstants.TYPE_CHAR && type2.type == CodeConstants.TYPE_SHORT)
+ || (type1.type == CodeConstants.TYPE_SHORT && type2.type == CodeConstants.TYPE_CHAR)) {
+ return VARTYPE_SHORTCHAR;
+ }
+ else {
+ return VARTYPE_BYTECHAR;
+ }
+ case CodeConstants.TYPE_FAMILY_OBJECT:
+ return VARTYPE_NULL;
+ }
+ }
+
+ return null;
+ }
+
+ // type1 and type2 must not be null
+ public static VarType getCommonSupertype(VarType type1, VarType type2) {
+
+ if (type1.type == CodeConstants.TYPE_BOOLEAN && type2.type == CodeConstants.TYPE_BOOLEAN) { // special case booleans
+ return type1.isFalseBoolean() ? type1 : type2;
+ }
+
+ if (type1.isSuperset(type2)) {
+ return type1;
+ }
+ else if (type2.isSuperset(type1)) {
+ return type2;
+ }
+ else if (type1.type_family == type2.type_family) {
+ switch (type1.type_family) {
+ case CodeConstants.TYPE_FAMILY_INTEGER:
+ if ((type1.type == CodeConstants.TYPE_SHORTCHAR && type2.type == CodeConstants.TYPE_BYTE)
+ || (type1.type == CodeConstants.TYPE_BYTE && type2.type == CodeConstants.TYPE_SHORTCHAR)) {
+ return VARTYPE_SHORT;
+ }
+ else {
+ return VARTYPE_INT;
+ }
+ case CodeConstants.TYPE_FAMILY_OBJECT:
+ return VARTYPE_OBJECT;
+ }
+ }
+
+ return null;
+ }
+
+ public static VarType getMinTypeInFamily(int family) {
+ switch (family) {
+ case CodeConstants.TYPE_FAMILY_BOOLEAN:
+ return VARTYPE_BOOLEAN;
+ case CodeConstants.TYPE_FAMILY_INTEGER:
+ return VARTYPE_BYTECHAR;
+ case CodeConstants.TYPE_FAMILY_OBJECT:
+ return VARTYPE_NULL;
+ case CodeConstants.TYPE_FAMILY_FLOAT:
+ return VARTYPE_FLOAT;
+ case CodeConstants.TYPE_FAMILY_LONG:
+ return VARTYPE_LONG;
+ case CodeConstants.TYPE_FAMILY_DOUBLE:
+ return VARTYPE_DOUBLE;
+ case CodeConstants.TYPE_FAMILY_UNKNOWN:
+ return VARTYPE_UNKNOWN;
+ default:
+ throw new RuntimeException("invalid type family!");
+ }
+ }
+
+ public boolean equals(Object o) {
+
+ if (o == this) {
+ return true;
+ }
+
+ if (o == null || !(o instanceof VarType)) {
+ return false;
+ }
+
+ VarType vt = (VarType)o;
+ return type == vt.type && arraydim == vt.arraydim && InterpreterUtil.equalObjects(value, vt.value);
+ }
+
+ private void parseTypeString(String strtype, boolean cltype) {
+
+ for (int i = 0; i < strtype.length(); i++) {
+ switch (strtype.charAt(i)) {
+ case '[':
+ arraydim++;
+ break;
+ case 'L':
+ if (strtype.charAt(strtype.length() - 1) == ';') {
+ type = CodeConstants.TYPE_OBJECT;
+ value = strtype.substring(i + 1, strtype.length() - 1);
+ return;
+ }
+ default:
+ value = strtype.substring(i, strtype.length());
+ if ((cltype && i == 0) || value.length() > 1) {
+ type = CodeConstants.TYPE_OBJECT;
+ }
+ else {
+ type = getType(value.charAt(0));
+ }
+ return;
+ }
+ }
+ }
+
+ private void setStackSize(int type) {
+ if (arraydim > 0) {
+ stack_size = 1;
+ }
+ else {
+ stack_size = (type == CodeConstants.TYPE_DOUBLE ||
+ type == CodeConstants.TYPE_LONG) ? 2 :
+ ((type == CodeConstants.TYPE_VOID ||
+ type == CodeConstants.TYPE_GROUP2EMPTY) ? 0 : 1);
+ }
+ }
+
+ private static int getType(char c) {
+ switch (c) {
+ case 'B':
+ return CodeConstants.TYPE_BYTE;
+ case 'C':
+ return CodeConstants.TYPE_CHAR;
+ case 'D':
+ return CodeConstants.TYPE_DOUBLE;
+ case 'F':
+ return CodeConstants.TYPE_FLOAT;
+ case 'I':
+ return CodeConstants.TYPE_INT;
+ case 'J':
+ return CodeConstants.TYPE_LONG;
+ case 'S':
+ return CodeConstants.TYPE_SHORT;
+ case 'Z':
+ return CodeConstants.TYPE_BOOLEAN;
+ case 'V':
+ return CodeConstants.TYPE_VOID;
+ case 'G':
+ return CodeConstants.TYPE_GROUP2EMPTY;
+ case 'N':
+ return CodeConstants.TYPE_NOTINITIALIZED;
+ case 'A':
+ return CodeConstants.TYPE_ADDRESS;
+ case 'X':
+ return CodeConstants.TYPE_BYTECHAR;
+ case 'Y':
+ return CodeConstants.TYPE_SHORTCHAR;
+ case 'U':
+ return CodeConstants.TYPE_UNKNOWN;
+ default:
+ throw new RuntimeException("Invalid type");
+ }
+ }
+
+ private static String getChar(int type) {
+ switch (type) {
+ case CodeConstants.TYPE_BYTE:
+ return "B";
+ case CodeConstants.TYPE_CHAR:
+ return "C";
+ case CodeConstants.TYPE_DOUBLE:
+ return "D";
+ case CodeConstants.TYPE_FLOAT:
+ return "F";
+ case CodeConstants.TYPE_INT:
+ return "I";
+ case CodeConstants.TYPE_LONG:
+ return "J";
+ case CodeConstants.TYPE_SHORT:
+ return "S";
+ case CodeConstants.TYPE_BOOLEAN:
+ return "Z";
+ case CodeConstants.TYPE_VOID:
+ return "V";
+ case CodeConstants.TYPE_GROUP2EMPTY:
+ return "G";
+ case CodeConstants.TYPE_NOTINITIALIZED:
+ return "N";
+ case CodeConstants.TYPE_ADDRESS:
+ return "A";
+ case CodeConstants.TYPE_BYTECHAR:
+ return "X";
+ case CodeConstants.TYPE_SHORTCHAR:
+ return "Y";
+ case CodeConstants.TYPE_UNKNOWN:
+ return "U";
+ case CodeConstants.TYPE_NULL:
+ case CodeConstants.TYPE_OBJECT:
+ return null;
+ default:
+ throw new RuntimeException("Invalid type");
+ }
+ }
+
+ public void setFamily() {
+
+ if (arraydim > 0) {
+ this.type_family = CodeConstants.TYPE_FAMILY_OBJECT;
+ return;
+ }
+
+ switch (type) {
+ case CodeConstants.TYPE_BYTE:
+ case CodeConstants.TYPE_BYTECHAR:
+ case CodeConstants.TYPE_SHORTCHAR:
+ case CodeConstants.TYPE_CHAR:
+ case CodeConstants.TYPE_SHORT:
+ case CodeConstants.TYPE_INT:
+ this.type_family = CodeConstants.TYPE_FAMILY_INTEGER;
+ break;
+ case CodeConstants.TYPE_DOUBLE:
+ this.type_family = CodeConstants.TYPE_FAMILY_DOUBLE;
+ break;
+ case CodeConstants.TYPE_FLOAT:
+ this.type_family = CodeConstants.TYPE_FAMILY_FLOAT;
+ break;
+ case CodeConstants.TYPE_LONG:
+ this.type_family = CodeConstants.TYPE_FAMILY_LONG;
+ break;
+ case CodeConstants.TYPE_BOOLEAN:
+ this.type_family = CodeConstants.TYPE_FAMILY_BOOLEAN;
+ break;
+ case CodeConstants.TYPE_NULL:
+ case CodeConstants.TYPE_OBJECT:
+ this.type_family = CodeConstants.TYPE_FAMILY_OBJECT;
+ break;
+ default:
+ this.type_family = CodeConstants.TYPE_FAMILY_UNKNOWN;
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericClassDescriptor.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericClassDescriptor.java
new file mode 100644
index 000000000000..66fab96d35c3
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericClassDescriptor.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.struct.gen.generics;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class GenericClassDescriptor {
+
+ public GenericType superclass;
+
+ public List<GenericType> superinterfaces = new ArrayList<GenericType>();
+
+ public List<String> fparameters = new ArrayList<String>();
+
+ public List<List<GenericType>> fbounds = new ArrayList<List<GenericType>>();
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericFieldDescriptor.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericFieldDescriptor.java
new file mode 100644
index 000000000000..598d17bef2d0
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericFieldDescriptor.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.struct.gen.generics;
+
+public class GenericFieldDescriptor {
+
+ public GenericType type;
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericMain.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericMain.java
new file mode 100644
index 000000000000..3082ecaf9ddd
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericMain.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.struct.gen.generics;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
+import org.jetbrains.java.decompiler.struct.StructClass;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class GenericMain {
+
+ private static final String[] typeNames = {
+ "byte",
+ "char",
+ "double",
+ "float",
+ "int",
+ "long",
+ "short",
+ "boolean",
+ };
+
+ public static GenericClassDescriptor parseClassSignature(String signature) {
+ String original = signature;
+ try {
+ GenericClassDescriptor descriptor = new GenericClassDescriptor();
+
+ signature = parseFormalParameters(signature, descriptor.fparameters, descriptor.fbounds);
+
+ String superCl = GenericType.getNextType(signature);
+ descriptor.superclass = new GenericType(superCl);
+
+ signature = signature.substring(superCl.length());
+ while (signature.length() > 0) {
+ String superIf = GenericType.getNextType(signature);
+ descriptor.superinterfaces.add(new GenericType(superIf));
+ signature = signature.substring(superIf.length());
+ }
+
+ return descriptor;
+ }
+ catch (RuntimeException e) {
+ DecompilerContext.getLogger().writeMessage("Invalid signature: " + original, IFernflowerLogger.Severity.WARN);
+ return null;
+ }
+ }
+
+ public static GenericFieldDescriptor parseFieldSignature(String signature) {
+ try {
+ GenericFieldDescriptor descriptor = new GenericFieldDescriptor();
+ descriptor.type = new GenericType(signature);
+ return descriptor;
+ }
+ catch (RuntimeException e) {
+ DecompilerContext.getLogger().writeMessage("Invalid signature: " + signature, IFernflowerLogger.Severity.WARN);
+ return null;
+ }
+ }
+
+ public static GenericMethodDescriptor parseMethodSignature(String signature) {
+ String original = signature;
+ try {
+ GenericMethodDescriptor descriptor = new GenericMethodDescriptor();
+
+ signature = parseFormalParameters(signature, descriptor.fparameters, descriptor.fbounds);
+
+ int to = signature.indexOf(")");
+ String pars = signature.substring(1, to);
+ signature = signature.substring(to + 1);
+
+ while (pars.length() > 0) {
+ String par = GenericType.getNextType(pars);
+ descriptor.params.add(new GenericType(par));
+ pars = pars.substring(par.length());
+ }
+
+ String par = GenericType.getNextType(signature);
+ descriptor.ret = new GenericType(par);
+ signature = signature.substring(par.length());
+
+ if (signature.length() > 0) {
+ String[] exceptions = signature.split("\\^");
+
+ for (int i = 1; i < exceptions.length; i++) {
+ descriptor.exceptions.add(new GenericType(exceptions[i]));
+ }
+ }
+
+ return descriptor;
+ }
+ catch (RuntimeException e) {
+ DecompilerContext.getLogger().writeMessage("Invalid signature: " + original, IFernflowerLogger.Severity.WARN);
+ return null;
+ }
+ }
+
+ private static String parseFormalParameters(String signature, List<String> parameters, List<List<GenericType>> bounds) {
+ if (signature.charAt(0) != '<') {
+ return signature;
+ }
+
+ int counter = 1;
+ int index = 1;
+
+ loop:
+ while (index < signature.length()) {
+ switch (signature.charAt(index)) {
+ case '<':
+ counter++;
+ break;
+ case '>':
+ counter--;
+ if (counter == 0) {
+ break loop;
+ }
+ }
+
+ index++;
+ }
+
+ String value = signature.substring(1, index);
+ signature = signature.substring(index + 1);
+
+ while (value.length() > 0) {
+ int to = value.indexOf(":");
+
+ String param = value.substring(0, to);
+ value = value.substring(to + 1);
+
+ List<GenericType> lstBounds = new ArrayList<GenericType>();
+
+ while (true) {
+ if (value.charAt(0) == ':') {
+ // empty superclass, skip
+ value = value.substring(1);
+ }
+
+ String bound = GenericType.getNextType(value);
+ lstBounds.add(new GenericType(bound));
+ value = value.substring(bound.length());
+
+
+ if (value.length() == 0 || value.charAt(0) != ':') {
+ break;
+ }
+ else {
+ value = value.substring(1);
+ }
+ }
+
+ parameters.add(param);
+ bounds.add(lstBounds);
+ }
+
+ return signature;
+ }
+
+ public static String getGenericCastTypeName(GenericType type) {
+ String s = getTypeName(type);
+ int dim = type.arraydim;
+ while (dim-- > 0) {
+ s += "[]";
+ }
+ return s;
+ }
+
+ private static String getTypeName(GenericType type) {
+ int tp = type.type;
+ if (tp <= CodeConstants.TYPE_BOOLEAN) {
+ return typeNames[tp];
+ }
+ else if (tp == CodeConstants.TYPE_VOID) {
+ return "void";
+ }
+ else if (tp == CodeConstants.TYPE_GENVAR) {
+ return type.value;
+ }
+ else if (tp == CodeConstants.TYPE_OBJECT) {
+ StringBuilder buffer = new StringBuilder();
+ buffer.append(DecompilerContext.getImportCollector().getShortName(buildJavaClassName(type)));
+
+ if (!type.getArguments().isEmpty()) {
+ buffer.append("<");
+ for (int i = 0; i < type.getArguments().size(); i++) {
+ if (i > 0) {
+ buffer.append(", ");
+ }
+ int wildcard = type.getWildcards().get(i);
+ if (wildcard != GenericType.WILDCARD_NO) {
+ buffer.append("?");
+
+ switch (wildcard) {
+ case GenericType.WILDCARD_EXTENDS:
+ buffer.append(" extends ");
+ break;
+ case GenericType.WILDCARD_SUPER:
+ buffer.append(" super ");
+ }
+ }
+
+ GenericType genPar = type.getArguments().get(i);
+ if (genPar != null) {
+ buffer.append(getGenericCastTypeName(genPar));
+ }
+ }
+ buffer.append(">");
+ }
+
+ return buffer.toString();
+ }
+
+ throw new RuntimeException("Invalid type: " + type);
+ }
+
+ private static String buildJavaClassName(GenericType type) {
+ String name = "";
+ for (GenericType tp : type.getEnclosingClasses()) {
+ name += tp.value + "$";
+ }
+ name += type.value;
+
+ String res = name.replace('/', '.');
+
+ if (res.contains("$")) {
+ StructClass cl = DecompilerContext.getStructContext().getClass(name);
+ if (cl == null || !cl.isOwn()) {
+ res = res.replace('$', '.');
+ }
+ }
+
+ return res;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericMethodDescriptor.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericMethodDescriptor.java
new file mode 100644
index 000000000000..7b4c9dc381f1
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericMethodDescriptor.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.struct.gen.generics;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class GenericMethodDescriptor {
+
+ public List<String> fparameters = new ArrayList<String>();
+
+ public List<List<GenericType>> fbounds = new ArrayList<List<GenericType>>();
+
+ public List<GenericType> params = new ArrayList<GenericType>();
+
+ public GenericType ret;
+
+ public List<GenericType> exceptions = new ArrayList<GenericType>();
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericType.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericType.java
new file mode 100644
index 000000000000..160a0ac46035
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/gen/generics/GenericType.java
@@ -0,0 +1,268 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.struct.gen.generics;
+
+import org.jetbrains.java.decompiler.code.CodeConstants;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class GenericType {
+
+ public static final int WILDCARD_EXTENDS = 1;
+ public static final int WILDCARD_SUPER = 2;
+ public static final int WILDCARD_UNBOUND = 3;
+ public static final int WILDCARD_NO = 4;
+
+ public int type;
+
+ public int arraydim;
+
+ public String value;
+
+
+ private List<GenericType> enclosingClasses = new ArrayList<GenericType>();
+
+ private List<GenericType> arguments = new ArrayList<GenericType>();
+
+ private List<Integer> wildcards = new ArrayList<Integer>();
+
+
+ public GenericType(int type, int arraydim, String value) {
+ this.type = type;
+ this.arraydim = arraydim;
+ this.value = value;
+ }
+
+
+ public GenericType(String strtype) {
+
+ parseSignature(strtype);
+ }
+
+ private void parseSignature(String sig) {
+
+ int index = 0;
+ while (index < sig.length()) {
+
+ switch (sig.charAt(index)) {
+ case '[':
+ arraydim++;
+ break;
+ case 'T':
+ type = CodeConstants.TYPE_GENVAR;
+ value = sig.substring(index + 1, sig.length() - 1);
+ return;
+ case 'L':
+ type = CodeConstants.TYPE_OBJECT;
+ sig = sig.substring(index + 1, sig.length() - 1);
+
+ while (true) {
+ String cl = getNextClassSignature(sig);
+
+ String name = cl;
+ String args = null;
+
+ int argfrom = cl.indexOf("<");
+ if (argfrom >= 0) {
+ name = cl.substring(0, argfrom);
+ args = cl.substring(argfrom + 1, cl.length() - 1);
+ }
+
+ if (cl.length() < sig.length()) {
+ sig = sig.substring(cl.length() + 1); // skip '.'
+ GenericType type = new GenericType(CodeConstants.TYPE_OBJECT, 0, name);
+ parseArgumentsList(args, type);
+ enclosingClasses.add(type);
+ }
+ else {
+ value = name;
+ parseArgumentsList(args, this);
+ break;
+ }
+ }
+
+ return;
+ default:
+ value = sig.substring(index, index + 1);
+ type = getType(value.charAt(0));
+ }
+
+ index++;
+ }
+ }
+
+ private static String getNextClassSignature(String value) {
+
+ int counter = 0;
+ int index = 0;
+
+ loop:
+ while (index < value.length()) {
+ switch (value.charAt(index)) {
+ case '<':
+ counter++;
+ break;
+ case '>':
+ counter--;
+ break;
+ case '.':
+ if (counter == 0) {
+ break loop;
+ }
+ }
+
+ index++;
+ }
+
+ return value.substring(0, index);
+ }
+
+ private static void parseArgumentsList(String value, GenericType type) {
+
+ if (value == null) {
+ return;
+ }
+
+ while (value.length() > 0) {
+
+ String tstr = getNextType(value);
+ int len = tstr.length();
+ int wildcard = WILDCARD_NO;
+
+ switch (tstr.charAt(0)) {
+ case '*':
+ wildcard = WILDCARD_UNBOUND;
+ break;
+ case '+':
+ wildcard = WILDCARD_EXTENDS;
+ break;
+ case '-':
+ wildcard = WILDCARD_SUPER;
+ break;
+ }
+
+ type.getWildcards().add(wildcard);
+
+ if (wildcard != WILDCARD_NO) {
+ tstr = tstr.substring(1);
+ }
+
+ type.getArguments().add(tstr.length() == 0 ? null : new GenericType(tstr));
+
+ value = value.substring(len);
+ }
+ }
+
+ public static String getNextType(String value) {
+
+ int counter = 0;
+ int index = 0;
+
+ boolean contmode = false;
+
+ loop:
+ while (index < value.length()) {
+ switch (value.charAt(index)) {
+ case '*':
+ if (!contmode) {
+ break loop;
+ }
+ break;
+ case 'L':
+ case 'T':
+ if (!contmode) {
+ contmode = true;
+ }
+ case '[':
+ case '+':
+ case '-':
+ break;
+ default:
+ if (!contmode) {
+ break loop;
+ }
+ break;
+ case '<':
+ counter++;
+ break;
+ case '>':
+ counter--;
+ break;
+ case ';':
+ if (counter == 0) {
+ break loop;
+ }
+ }
+
+ index++;
+ }
+
+ return value.substring(0, index + 1);
+ }
+
+ private static int getType(char c) {
+ switch (c) {
+ case 'B':
+ return CodeConstants.TYPE_BYTE;
+ case 'C':
+ return CodeConstants.TYPE_CHAR;
+ case 'D':
+ return CodeConstants.TYPE_DOUBLE;
+ case 'F':
+ return CodeConstants.TYPE_FLOAT;
+ case 'I':
+ return CodeConstants.TYPE_INT;
+ case 'J':
+ return CodeConstants.TYPE_LONG;
+ case 'S':
+ return CodeConstants.TYPE_SHORT;
+ case 'Z':
+ return CodeConstants.TYPE_BOOLEAN;
+ case 'V':
+ return CodeConstants.TYPE_VOID;
+ case 'G':
+ return CodeConstants.TYPE_GROUP2EMPTY;
+ case 'N':
+ return CodeConstants.TYPE_NOTINITIALIZED;
+ case 'A':
+ return CodeConstants.TYPE_ADDRESS;
+ case 'X':
+ return CodeConstants.TYPE_BYTECHAR;
+ case 'Y':
+ return CodeConstants.TYPE_SHORTCHAR;
+ case 'U':
+ return CodeConstants.TYPE_UNKNOWN;
+ default:
+ throw new RuntimeException("Invalid type");
+ }
+ }
+
+
+ public List<GenericType> getArguments() {
+ return arguments;
+ }
+
+
+ public List<GenericType> getEnclosingClasses() {
+ return enclosingClasses;
+ }
+
+
+ public List<Integer> getWildcards() {
+ return wildcards;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/lazy/LazyLoader.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/lazy/LazyLoader.java
new file mode 100644
index 000000000000..70254d82977a
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/lazy/LazyLoader.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.struct.lazy;
+
+import org.jetbrains.java.decompiler.main.extern.IBytecodeProvider;
+import org.jetbrains.java.decompiler.struct.StructMethod;
+import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute;
+import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
+import org.jetbrains.java.decompiler.util.DataInputFullStream;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+public class LazyLoader {
+
+ private final Map<String, Link> mapClassLinks = new HashMap<String, Link>();
+ private final IBytecodeProvider provider;
+
+ public LazyLoader(IBytecodeProvider provider) {
+ this.provider = provider;
+ }
+
+ public void addClassLink(String classname, Link link) {
+ mapClassLinks.put(classname, link);
+ }
+
+ public void removeClassLink(String classname) {
+ mapClassLinks.remove(classname);
+ }
+
+ public Link getClassLink(String classname) {
+ return mapClassLinks.get(classname);
+ }
+
+ public ConstantPool loadPool(String classname) {
+ try {
+ DataInputFullStream in = getClassStream(classname);
+ if (in == null) return null;
+
+ try {
+ in.discard(8);
+ return new ConstantPool(in);
+ }
+ finally {
+ in.close();
+ }
+ }
+ catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ public byte[] loadBytecode(StructMethod mt, int codeFullLength) {
+ String className = mt.getClassStruct().qualifiedName;
+
+ try {
+ DataInputFullStream in = getClassStream(className);
+ if (in == null) return null;
+
+ try {
+ in.discard(8);
+
+ ConstantPool pool = mt.getClassStruct().getPool();
+ if (pool == null) {
+ pool = new ConstantPool(in);
+ }
+ else {
+ ConstantPool.skipPool(in);
+ }
+
+ in.discard(6);
+
+ // interfaces
+ in.discard(in.readUnsignedShort() * 2);
+
+ // fields
+ int size = in.readUnsignedShort();
+ for (int i = 0; i < size; i++) {
+ in.discard(6);
+ skipAttributes(in);
+ }
+
+ // methods
+ size = in.readUnsignedShort();
+ for (int i = 0; i < size; i++) {
+ in.discard(2);
+
+ int nameIndex = in.readUnsignedShort();
+ int descriptorIndex = in.readUnsignedShort();
+
+ String[] values = pool.getClassElement(ConstantPool.METHOD, className, nameIndex, descriptorIndex);
+ if (!mt.getName().equals(values[0]) || !mt.getDescriptor().equals(values[1])) {
+ skipAttributes(in);
+ continue;
+ }
+
+ int attrSize = in.readUnsignedShort();
+ for (int j = 0; j < attrSize; j++) {
+ int attrNameIndex = in.readUnsignedShort();
+ String attrName = pool.getPrimitiveConstant(attrNameIndex).getString();
+ if (!StructGeneralAttribute.ATTRIBUTE_CODE.equals(attrName)) {
+ in.discard(in.readInt());
+ continue;
+ }
+
+ in.discard(12);
+ byte[] code = new byte[codeFullLength];
+ in.readFull(code);
+ return code;
+ }
+
+ break;
+ }
+ }
+ finally {
+ in.close();
+ }
+
+ return null;
+ }
+ catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ public DataInputFullStream getClassStream(String externalPath, String internalPath) throws IOException {
+ byte[] bytes = provider.getBytecode(externalPath, internalPath);
+ return new DataInputFullStream(bytes);
+ }
+
+ public DataInputFullStream getClassStream(String qualifiedClassName) throws IOException {
+ Link link = mapClassLinks.get(qualifiedClassName);
+ return link == null ? null : getClassStream(link.externalPath, link.internalPath);
+ }
+
+ public static void skipAttributes(DataInputFullStream in) throws IOException {
+ int length = in.readUnsignedShort();
+ for (int i = 0; i < length; i++) {
+ in.discard(2);
+ in.discard(in.readInt());
+ }
+ }
+
+
+ public static class Link {
+ public static final int CLASS = 1;
+ public static final int ENTRY = 2;
+
+ public int type;
+ public String externalPath;
+ public String internalPath;
+
+ public Link(int type, String externalPath, String internalPath) {
+ this.type = type;
+ this.externalPath = externalPath;
+ this.internalPath = internalPath;
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/DataInputFullStream.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/DataInputFullStream.java
new file mode 100644
index 000000000000..011eddea5c92
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/DataInputFullStream.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+
+public class DataInputFullStream extends DataInputStream {
+
+ public DataInputFullStream(byte[] bytes) {
+ super(new ByteArrayInputStream(bytes));
+ }
+
+ public int readFull(byte[] b) throws IOException {
+ int length = b.length;
+ byte[] temp = new byte[length];
+ int pos = 0;
+
+ int bytes_read;
+ while (true) {
+ bytes_read = read(temp, 0, length - pos);
+ if (bytes_read == -1) {
+ return -1;
+ }
+
+ System.arraycopy(temp, 0, b, pos, bytes_read);
+ pos += bytes_read;
+ if (pos == length) {
+ break;
+ }
+ }
+
+ return length;
+ }
+
+ public void discard(int n) throws IOException {
+ if (super.skip(n) != n) {
+ throw new IOException("Skip failed");
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/FastFixedSetFactory.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/FastFixedSetFactory.java
new file mode 100644
index 000000000000..a26b77e95ad7
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/FastFixedSetFactory.java
@@ -0,0 +1,360 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.util;
+
+import java.util.*;
+
+public class FastFixedSetFactory<E> {
+
+ private VBStyleCollection<int[], E> colValuesInternal = new VBStyleCollection<int[], E>();
+
+ private int dataLength;
+
+ public FastFixedSetFactory(Collection<E> set) {
+
+ dataLength = set.size() / 32 + 1;
+
+ int index = 0;
+ int mask = 1;
+
+ for (E element : set) {
+
+ int block = index / 32;
+
+ if (index % 32 == 0) {
+ mask = 1;
+ }
+
+ colValuesInternal.putWithKey(new int[]{block, mask}, element);
+
+ index++;
+ mask <<= 1;
+ }
+ }
+
+ public FastFixedSet<E> spawnEmptySet() {
+ return new FastFixedSet<E>(this);
+ }
+
+ private int getDataLength() {
+ return dataLength;
+ }
+
+ private VBStyleCollection<int[], E> getInternalValuesCollection() {
+ return colValuesInternal;
+ }
+
+ public static class FastFixedSet<E> implements Iterable<E> {
+
+ private FastFixedSetFactory<E> factory;
+
+ private VBStyleCollection<int[], E> colValuesInternal;
+
+ private int[] data;
+
+
+ private FastFixedSet(FastFixedSetFactory<E> factory) {
+ this.factory = factory;
+ this.colValuesInternal = factory.getInternalValuesCollection();
+ this.data = new int[factory.getDataLength()];
+ }
+
+ public FastFixedSet<E> getCopy() {
+
+ FastFixedSet<E> copy = new FastFixedSet<E>(factory);
+
+ int arrlength = data.length;
+ int[] cpdata = new int[arrlength];
+ System.arraycopy(data, 0, cpdata, 0, arrlength);
+ copy.setData(cpdata);
+
+ return copy;
+ }
+
+ public void setAllElements() {
+
+ int[] lastindex = colValuesInternal.get(colValuesInternal.size() - 1);
+
+ for (int i = lastindex[0] - 1; i >= 0; i--) {
+ data[i] = 0xFFFFFFFF;
+ }
+
+ data[lastindex[0]] = lastindex[1] | (lastindex[1] - 1);
+ }
+
+ public void add(E element) {
+ int[] index = colValuesInternal.getWithKey(element);
+ data[index[0]] |= index[1];
+ }
+
+ public void addAll(Collection<E> set) {
+ for (E element : set) {
+ add(element);
+ }
+ }
+
+ public void remove(E element) {
+ int[] index = colValuesInternal.getWithKey(element);
+ data[index[0]] &= ~index[1];
+ }
+
+ public void removeAll(Collection<E> set) {
+ for (E element : set) {
+ remove(element);
+ }
+ }
+
+ public boolean contains(E element) {
+ int[] index = colValuesInternal.getWithKey(element);
+ return (data[index[0]] & index[1]) != 0;
+ }
+
+ public boolean contains(FastFixedSet<E> set) {
+ int[] extdata = set.getData();
+ int[] intdata = data;
+
+ for (int i = intdata.length - 1; i >= 0; i--) {
+ if ((extdata[i] & ~intdata[i]) != 0) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public void union(FastFixedSet<E> set) {
+ int[] extdata = set.getData();
+ int[] intdata = data;
+
+ for (int i = intdata.length - 1; i >= 0; i--) {
+ intdata[i] |= extdata[i];
+ }
+ }
+
+ public void intersection(FastFixedSet<E> set) {
+ int[] extdata = set.getData();
+ int[] intdata = data;
+
+ for (int i = intdata.length - 1; i >= 0; i--) {
+ intdata[i] &= extdata[i];
+ }
+ }
+
+ public void symdiff(FastFixedSet<E> set) {
+ int[] extdata = set.getData();
+ int[] intdata = data;
+
+ for (int i = intdata.length - 1; i >= 0; i--) {
+ intdata[i] ^= extdata[i];
+ }
+ }
+
+ public void complement(FastFixedSet<E> set) {
+ int[] extdata = set.getData();
+ int[] intdata = data;
+
+ for (int i = intdata.length - 1; i >= 0; i--) {
+ intdata[i] &= ~extdata[i];
+ }
+ }
+
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof FastFixedSet)) return false;
+
+ int[] extdata = ((FastFixedSet)o).getData();
+ int[] intdata = data;
+
+ for (int i = intdata.length - 1; i >= 0; i--) {
+ if (intdata[i] != extdata[i]) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public boolean isEmpty() {
+ int[] intdata = data;
+
+ for (int i = intdata.length - 1; i >= 0; i--) {
+ if (intdata[i] != 0) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public Iterator<E> iterator() {
+ return new FastFixedSetIterator<E>(this);
+ }
+
+ public Set<E> toPlainSet() {
+ return toPlainCollection(new HashSet<E>());
+ }
+
+ public List<E> toPlainList() {
+ return toPlainCollection(new ArrayList<E>());
+ }
+
+
+ private <T extends Collection<E>> T toPlainCollection(T cl) {
+
+ int[] intdata = data;
+ for (int bindex = 0; bindex < intdata.length; bindex++) {
+ int block = intdata[bindex];
+ if (block != 0) {
+ int index = bindex << 5; // * 32
+ for (int i = 31; i >= 0; i--) {
+ if ((block & 1) != 0) {
+ cl.add(colValuesInternal.getKey(index));
+ }
+ index++;
+ block >>>= 1;
+ }
+ }
+ }
+
+ return cl;
+ }
+
+ public String toBinary() {
+
+ StringBuilder buffer = new StringBuilder();
+ int[] intdata = data;
+
+ for (int i = 0; i < intdata.length; i++) {
+ buffer.append(" ").append(Integer.toBinaryString(intdata[i]));
+ }
+
+ return buffer.toString();
+ }
+
+ public String toString() {
+
+ StringBuilder buffer = new StringBuilder("{");
+
+ int[] intdata = data;
+ boolean first = true;
+
+ for (int i = colValuesInternal.size() - 1; i >= 0; i--) {
+ int[] index = colValuesInternal.get(i);
+
+ if ((intdata[index[0]] & index[1]) != 0) {
+ if (first) {
+ first = false;
+ }
+ else {
+ buffer.append(",");
+ }
+ buffer.append(colValuesInternal.getKey(i));
+ }
+ }
+
+ buffer.append("}");
+
+ return buffer.toString();
+ }
+
+ private int[] getData() {
+ return data;
+ }
+
+ private void setData(int[] data) {
+ this.data = data;
+ }
+
+ public FastFixedSetFactory<E> getFactory() {
+ return factory;
+ }
+ }
+
+ public static class FastFixedSetIterator<E> implements Iterator<E> {
+
+ private VBStyleCollection<int[], E> colValuesInternal;
+ private int[] data;
+ private int size;
+
+ private int pointer = -1;
+ private int next_pointer = -1;
+
+ private FastFixedSetIterator(FastFixedSet<E> set) {
+ colValuesInternal = set.getFactory().getInternalValuesCollection();
+ data = set.getData();
+ size = colValuesInternal.size();
+ }
+
+ private int getNextIndex(int index) {
+
+ index++;
+ int ret = index;
+ int bindex = index / 32;
+ int dindex = index % 32;
+
+ while (bindex < data.length) {
+ int block = data[bindex];
+
+ if (block != 0) {
+ block >>>= dindex;
+ while (dindex < 32) {
+ if ((block & 1) != 0) {
+ return ret;
+ }
+ block >>>= 1;
+ dindex++;
+ ret++;
+ }
+ }
+ else {
+ ret += (32 - dindex);
+ }
+
+ dindex = 0;
+ bindex++;
+ }
+
+ return -1;
+ }
+
+ public boolean hasNext() {
+ next_pointer = getNextIndex(pointer);
+ return (next_pointer >= 0);
+ }
+
+ public E next() {
+ if (next_pointer >= 0) {
+ pointer = next_pointer;
+ }
+ else {
+ pointer = getNextIndex(pointer);
+ if (pointer == -1) {
+ pointer = size;
+ }
+ }
+
+ next_pointer = -1;
+ return pointer < size ? colValuesInternal.getKey(pointer) : null;
+ }
+
+ public void remove() {
+ int[] index = colValuesInternal.get(pointer);
+ data[index[0]] &= ~index[1];
+ }
+ }
+}
+
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/FastSetFactory.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/FastSetFactory.java
new file mode 100644
index 000000000000..e9cce03b827c
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/FastSetFactory.java
@@ -0,0 +1,489 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.util;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+public class FastSetFactory<E> {
+
+ private VBStyleCollection<int[], E> colValuesInternal = new VBStyleCollection<int[], E>();
+
+ private int lastBlock;
+
+ private int lastMask;
+
+ public FastSetFactory(Collection<E> set) {
+
+ int block = -1;
+ int mask = -1;
+ int index = 0;
+
+ for (E element : set) {
+
+ block = index / 32;
+
+ if (index % 32 == 0) {
+ mask = 1;
+ }
+ else {
+ mask <<= 1;
+ }
+
+ colValuesInternal.putWithKey(new int[]{block, mask}, element);
+
+ index++;
+ }
+
+ lastBlock = block;
+ lastMask = mask;
+ }
+
+ private int[] addElement(E element) {
+
+ if (lastMask == -1 || lastMask == 0x80000000) {
+ lastMask = 1;
+ lastBlock++;
+ }
+ else {
+ lastMask <<= 1;
+ }
+
+ int[] pointer = new int[]{lastBlock, lastMask};
+ colValuesInternal.putWithKey(pointer, element);
+
+ return pointer;
+ }
+
+ public FastSet<E> spawnEmptySet() {
+ return new FastSet<E>(this);
+ }
+
+ public int getLastBlock() {
+ return lastBlock;
+ }
+
+ public int getLastMask() {
+ return lastMask;
+ }
+
+ private VBStyleCollection<int[], E> getInternalValuesCollection() {
+ return colValuesInternal;
+ }
+
+
+ public static class FastSet<E> implements Iterable<E> {
+
+ private FastSetFactory<E> factory;
+
+ private VBStyleCollection<int[], E> colValuesInternal;
+
+ private int[] data;
+
+ private FastSet(FastSetFactory<E> factory) {
+ this.factory = factory;
+ this.colValuesInternal = factory.getInternalValuesCollection();
+ this.data = new int[factory.getLastBlock() + 1];
+ }
+
+ public FastSet<E> getCopy() {
+
+ FastSet<E> copy = new FastSet<E>(factory);
+
+ int arrlength = data.length;
+ int[] cpdata = new int[arrlength];
+
+ System.arraycopy(data, 0, cpdata, 0, arrlength);
+ copy.setData(cpdata);
+
+ return copy;
+ }
+
+ private int[] ensureCapacity(int index) {
+
+ int newlength = data.length;
+ if (newlength == 0) {
+ newlength = 1;
+ }
+
+ while (newlength <= index) {
+ newlength *= 2;
+ }
+
+ int[] newdata = new int[newlength];
+ System.arraycopy(data, 0, newdata, 0, data.length);
+
+ return data = newdata;
+ }
+
+ public void add(E element) {
+ int[] index = colValuesInternal.getWithKey(element);
+
+ if (index == null) {
+ index = factory.addElement(element);
+ }
+
+ if (index[0] >= data.length) {
+ ensureCapacity(index[0]);
+ }
+
+ data[index[0]] |= index[1];
+ }
+
+ public void setAllElements() {
+
+ int lastblock = factory.getLastBlock();
+ int lastmask = factory.getLastMask();
+
+ if (lastblock >= data.length) {
+ ensureCapacity(lastblock);
+ }
+
+ for (int i = lastblock - 1; i >= 0; i--) {
+ data[i] = 0xFFFFFFFF;
+ }
+
+ data[lastblock] = lastmask | (lastmask - 1);
+ }
+
+ public void addAll(Set<E> set) {
+ for (E element : set) {
+ add(element);
+ }
+ }
+
+ public void remove(E element) {
+ int[] index = colValuesInternal.getWithKey(element);
+
+ if (index == null) {
+ index = factory.addElement(element);
+ }
+
+ if (index[0] < data.length) {
+ data[index[0]] &= ~index[1];
+ }
+ }
+
+ public void removeAll(Set<E> set) {
+ for (E element : set) {
+ remove(element);
+ }
+ }
+
+ public boolean contains(E element) {
+ int[] index = colValuesInternal.getWithKey(element);
+
+ if (index == null) {
+ index = factory.addElement(element);
+ }
+
+ return index[0] >= data.length ? false : ((data[index[0]] & index[1]) != 0);
+ }
+
+ public boolean contains(FastSet<E> set) {
+ int[] extdata = set.getData();
+ int[] intdata = data;
+
+ int minlength = Math.min(extdata.length, intdata.length);
+
+ for (int i = minlength - 1; i >= 0; i--) {
+ if ((extdata[i] & ~intdata[i]) != 0) {
+ return false;
+ }
+ }
+
+ for (int i = extdata.length - 1; i >= minlength; i--) {
+ if (extdata[i] != 0) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public void union(FastSet<E> set) {
+
+ int[] extdata = set.getData();
+ int[] intdata = data;
+
+ int minlength = Math.min(extdata.length, intdata.length);
+
+ for (int i = minlength - 1; i >= 0; i--) {
+ intdata[i] |= extdata[i];
+ }
+
+ boolean expanded = false;
+ for (int i = extdata.length - 1; i >= minlength; i--) {
+ if (extdata[i] != 0) {
+ if (!expanded) {
+ intdata = ensureCapacity(extdata.length - 1);
+ }
+ intdata[i] = extdata[i];
+ }
+ }
+ }
+
+ public void intersection(FastSet<E> set) {
+ int[] extdata = set.getData();
+ int[] intdata = data;
+
+ int minlength = Math.min(extdata.length, intdata.length);
+
+ for (int i = minlength - 1; i >= 0; i--) {
+ intdata[i] &= extdata[i];
+ }
+
+ for (int i = intdata.length - 1; i >= minlength; i--) {
+ intdata[i] = 0;
+ }
+ }
+
+ public void symdiff(FastSet<E> set) {
+ int[] extdata = set.getData();
+ int[] intdata = data;
+
+ int minlength = Math.min(extdata.length, intdata.length);
+
+ for (int i = minlength - 1; i >= 0; i--) {
+ intdata[i] ^= extdata[i];
+ }
+
+ boolean expanded = false;
+ for (int i = extdata.length - 1; i >= minlength; i--) {
+ if (extdata[i] != 0) {
+ if (!expanded) {
+ intdata = ensureCapacity(extdata.length - 1);
+ }
+ intdata[i] = extdata[i];
+ }
+ }
+ }
+
+ public void complement(FastSet<E> set) {
+ int[] extdata = set.getData();
+ int[] intdata = data;
+
+ int minlength = Math.min(extdata.length, intdata.length);
+
+ for (int i = minlength - 1; i >= 0; i--) {
+ intdata[i] &= ~extdata[i];
+ }
+ }
+
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof FastSet)) return false;
+
+ int[] longdata = ((FastSet)o).getData();
+ int[] shortdata = data;
+
+ if (data.length > longdata.length) {
+ shortdata = longdata;
+ longdata = data;
+ }
+
+ for (int i = shortdata.length - 1; i >= 0; i--) {
+ if (shortdata[i] != longdata[i]) {
+ return false;
+ }
+ }
+
+ for (int i = longdata.length - 1; i >= shortdata.length; i--) {
+ if (longdata[i] != 0) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public int getCardinality() {
+
+ boolean found = false;
+ int[] intdata = data;
+
+ for (int i = intdata.length - 1; i >= 0; i--) {
+ int block = intdata[i];
+ if (block != 0) {
+ if (found) {
+ return 2;
+ }
+ else {
+ if ((block & (block - 1)) == 0) {
+ found = true;
+ }
+ else {
+ return 2;
+ }
+ }
+ }
+ }
+
+ return found ? 1 : 0;
+ }
+
+ public int size() {
+
+ int size = 0;
+ int[] intdata = data;
+
+ for (int i = intdata.length - 1; i >= 0; i--) {
+ size += Integer.bitCount(intdata[i]);
+ }
+
+ return size;
+ }
+
+ public boolean isEmpty() {
+ int[] intdata = data;
+
+ for (int i = intdata.length - 1; i >= 0; i--) {
+ if (intdata[i] != 0) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public Iterator<E> iterator() {
+ return new FastSetIterator<E>(this);
+ }
+
+ public Set<E> toPlainSet() {
+ HashSet<E> set = new HashSet<E>();
+
+ int[] intdata = data;
+
+ int size = data.length * 32;
+ if (size > colValuesInternal.size()) {
+ size = colValuesInternal.size();
+ }
+
+ for (int i = size - 1; i >= 0; i--) {
+ int[] index = colValuesInternal.get(i);
+
+ if ((intdata[index[0]] & index[1]) != 0) {
+ set.add(colValuesInternal.getKey(i));
+ }
+ }
+
+ return set;
+ }
+
+ public String toBinary() {
+
+ StringBuilder buffer = new StringBuilder();
+ int[] intdata = data;
+
+ for (int i = 0; i < intdata.length; i++) {
+ buffer.append(" ").append(Integer.toBinaryString(intdata[i]));
+ }
+
+ return buffer.toString();
+ }
+
+ private int[] getData() {
+ return data;
+ }
+
+ private void setData(int[] data) {
+ this.data = data;
+ }
+
+ public int[] getLoad() {
+ int[] intdata = data;
+ int notempty = 0;
+
+ for (int i = 0; i < intdata.length; i++) {
+ if (intdata[i] != 0) {
+ notempty++;
+ }
+ }
+
+ return new int[]{intdata.length, notempty};
+ }
+
+ public FastSetFactory<E> getFactory() {
+ return factory;
+ }
+ }
+
+ public static class FastSetIterator<E> implements Iterator<E> {
+
+ private VBStyleCollection<int[], E> colValuesInternal;
+ private int[] data;
+ private int size;
+
+ private int pointer = -1;
+ private int next_pointer = -1;
+
+ private FastSetIterator(FastSet<E> set) {
+ colValuesInternal = set.getFactory().getInternalValuesCollection();
+ data = set.getData();
+
+ size = colValuesInternal.size();
+ int datasize = data.length * 32;
+
+ if (datasize < size) {
+ size = datasize;
+ }
+ }
+
+ public boolean hasNext() {
+
+ next_pointer = pointer;
+
+ while (++next_pointer < size) {
+ int[] index = colValuesInternal.get(next_pointer);
+ if ((data[index[0]] & index[1]) != 0) {
+ return true;
+ }
+ }
+
+ next_pointer = -1;
+ return false;
+ }
+
+ public E next() {
+ if (next_pointer >= 0) {
+ pointer = next_pointer;
+ }
+ else {
+ while (++pointer < size) {
+ int[] index = colValuesInternal.get(pointer);
+ if ((data[index[0]] & index[1]) != 0) {
+ break;
+ }
+ }
+ }
+
+ next_pointer = -1;
+ return pointer < size ? colValuesInternal.getKey(pointer) : null;
+ }
+
+ public void remove() {
+ int[] index = colValuesInternal.get(pointer);
+ data[index[0]] &= ~index[1];
+
+ pointer--;
+ }
+ }
+}
+
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/FastSparseSetFactory.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/FastSparseSetFactory.java
new file mode 100644
index 000000000000..bf01035616a4
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/FastSparseSetFactory.java
@@ -0,0 +1,552 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.util;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+public class FastSparseSetFactory<E> {
+
+ private VBStyleCollection<int[], E> colValuesInternal = new VBStyleCollection<int[], E>();
+
+ private int lastBlock;
+
+ private int lastMask;
+
+ public FastSparseSetFactory(Collection<E> set) {
+
+ int block = -1;
+ int mask = -1;
+ int index = 0;
+
+ for (E element : set) {
+
+ block = index / 32;
+
+ if (index % 32 == 0) {
+ mask = 1;
+ }
+ else {
+ mask <<= 1;
+ }
+
+ colValuesInternal.putWithKey(new int[]{block, mask}, element);
+
+ index++;
+ }
+
+ lastBlock = block;
+ lastMask = mask;
+ }
+
+ private int[] addElement(E element) {
+
+ if (lastMask == -1 || lastMask == 0x80000000) {
+ lastMask = 1;
+ lastBlock++;
+ }
+ else {
+ lastMask <<= 1;
+ }
+
+ int[] pointer = new int[]{lastBlock, lastMask};
+ colValuesInternal.putWithKey(pointer, element);
+
+ return pointer;
+ }
+
+ public FastSparseSet<E> spawnEmptySet() {
+ return new FastSparseSet<E>(this);
+ }
+
+ public int getLastBlock() {
+ return lastBlock;
+ }
+
+ public int getLastMask() {
+ return lastMask;
+ }
+
+ private VBStyleCollection<int[], E> getInternalValuesCollection() {
+ return colValuesInternal;
+ }
+
+
+ public static class FastSparseSet<E> implements Iterable<E> {
+
+ private FastSparseSetFactory<E> factory;
+
+ private VBStyleCollection<int[], E> colValuesInternal;
+
+ private int[] data;
+ private int[] next;
+
+ private FastSparseSet(FastSparseSetFactory<E> factory) {
+ this.factory = factory;
+ this.colValuesInternal = factory.getInternalValuesCollection();
+
+ int length = factory.getLastBlock() + 1;
+ this.data = new int[length];
+ this.next = new int[length];
+ }
+
+ private FastSparseSet(FastSparseSetFactory<E> factory, int[] data, int[] next) {
+ this.factory = factory;
+ this.colValuesInternal = factory.getInternalValuesCollection();
+
+ this.data = data;
+ this.next = next;
+ }
+
+ public FastSparseSet<E> getCopy() {
+
+ int arrlength = data.length;
+ int[] cpdata = new int[arrlength];
+ int[] cpnext = new int[arrlength];
+
+ System.arraycopy(data, 0, cpdata, 0, arrlength);
+ System.arraycopy(next, 0, cpnext, 0, arrlength);
+
+ return new FastSparseSet<E>(factory, cpdata, cpnext);
+ }
+
+ private int[] ensureCapacity(int index) {
+
+ int newlength = data.length;
+ if (newlength == 0) {
+ newlength = 1;
+ }
+
+ while (newlength <= index) {
+ newlength *= 2;
+ }
+
+ int[] newdata = new int[newlength];
+ System.arraycopy(data, 0, newdata, 0, data.length);
+ data = newdata;
+
+ int[] newnext = new int[newlength];
+ System.arraycopy(next, 0, newnext, 0, next.length);
+ next = newnext;
+
+ return newdata;
+ }
+
+ public void add(E element) {
+ int[] index = colValuesInternal.getWithKey(element);
+
+ if (index == null) {
+ index = factory.addElement(element);
+ }
+
+ int block = index[0];
+ if (block >= data.length) {
+ ensureCapacity(block);
+ }
+
+ data[block] |= index[1];
+
+ changeNext(next, block, next[block], block);
+ }
+
+ public void setAllElements() {
+
+ int lastblock = factory.getLastBlock();
+ int lastmask = factory.getLastMask();
+
+ if (lastblock >= data.length) {
+ ensureCapacity(lastblock);
+ }
+
+ for (int i = lastblock - 1; i >= 0; i--) {
+ data[i] = 0xFFFFFFFF;
+ next[i] = i + 1;
+ }
+
+ data[lastblock] = lastmask | (lastmask - 1);
+ next[lastblock] = 0;
+ }
+
+ public void addAll(Set<E> set) {
+ for (E element : set) {
+ add(element);
+ }
+ }
+
+ public void remove(E element) {
+ int[] index = colValuesInternal.getWithKey(element);
+
+ if (index == null) {
+ index = factory.addElement(element);
+ }
+
+ int block = index[0];
+ if (block < data.length) {
+ data[block] &= ~index[1];
+
+ if (data[block] == 0) {
+ changeNext(next, block, block, next[block]);
+ }
+ }
+ }
+
+ public void removeAll(Set<E> set) {
+ for (E element : set) {
+ remove(element);
+ }
+ }
+
+ public boolean contains(E element) {
+ int[] index = colValuesInternal.getWithKey(element);
+
+ if (index == null) {
+ index = factory.addElement(element);
+ }
+
+ return index[0] >= data.length ? false : ((data[index[0]] & index[1]) != 0);
+ }
+
+ public boolean contains(FastSparseSet<E> set) {
+ int[] extdata = set.getData();
+ int[] intdata = data;
+
+ int minlength = Math.min(extdata.length, intdata.length);
+
+ for (int i = minlength - 1; i >= 0; i--) {
+ if ((extdata[i] & ~intdata[i]) != 0) {
+ return false;
+ }
+ }
+
+ for (int i = extdata.length - 1; i >= minlength; i--) {
+ if (extdata[i] != 0) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private void setNext() {
+
+ int link = 0;
+ for (int i = data.length - 1; i >= 0; i--) {
+ next[i] = link;
+ if (data[i] != 0) {
+ link = i;
+ }
+ }
+ }
+
+ private static void changeNext(int[] arrnext, int key, int oldnext, int newnext) {
+ for (int i = key - 1; i >= 0; i--) {
+ if (arrnext[i] == oldnext) {
+ arrnext[i] = newnext;
+ }
+ else {
+ break;
+ }
+ }
+ }
+
+ public void union(FastSparseSet<E> set) {
+
+ int[] extdata = set.getData();
+ int[] extnext = set.getNext();
+ int[] intdata = data;
+ int intlength = intdata.length;
+
+ int pointer = 0;
+ do {
+ if (pointer >= intlength) {
+ intdata = ensureCapacity(extdata.length - 1);
+ }
+
+ boolean nextrec = (intdata[pointer] == 0);
+ intdata[pointer] |= extdata[pointer];
+
+ if (nextrec) {
+ changeNext(next, pointer, next[pointer], pointer);
+ }
+
+ pointer = extnext[pointer];
+ }
+ while (pointer != 0);
+ }
+
+ public void intersection(FastSparseSet<E> set) {
+ int[] extdata = set.getData();
+ int[] intdata = data;
+
+ int minlength = Math.min(extdata.length, intdata.length);
+
+ for (int i = minlength - 1; i >= 0; i--) {
+ intdata[i] &= extdata[i];
+ }
+
+ for (int i = intdata.length - 1; i >= minlength; i--) {
+ intdata[i] = 0;
+ }
+
+ setNext();
+ }
+
+ public void symdiff(FastSparseSet<E> set) {
+ int[] extdata = set.getData();
+ int[] intdata = data;
+
+ int minlength = Math.min(extdata.length, intdata.length);
+
+ for (int i = minlength - 1; i >= 0; i--) {
+ intdata[i] ^= extdata[i];
+ }
+
+ boolean expanded = false;
+ for (int i = extdata.length - 1; i >= minlength; i--) {
+ if (extdata[i] != 0) {
+ if (!expanded) {
+ intdata = ensureCapacity(extdata.length - 1);
+ }
+ intdata[i] = extdata[i];
+ }
+ }
+
+ setNext();
+ }
+
+ public void complement(FastSparseSet<E> set) {
+
+ int[] extdata = set.getData();
+ int[] intdata = data;
+ int extlength = extdata.length;
+
+ int pointer = 0;
+ do {
+ if (pointer >= extlength) {
+ break;
+ }
+
+ intdata[pointer] &= ~extdata[pointer];
+ if (intdata[pointer] == 0) {
+ changeNext(next, pointer, pointer, next[pointer]);
+ }
+
+ pointer = next[pointer];
+ }
+ while (pointer != 0);
+ }
+
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null || !(o instanceof FastSparseSet)) return false;
+
+ int[] longdata = ((FastSparseSet)o).getData();
+ int[] shortdata = data;
+
+ if (data.length > longdata.length) {
+ shortdata = longdata;
+ longdata = data;
+ }
+
+ for (int i = shortdata.length - 1; i >= 0; i--) {
+ if (shortdata[i] != longdata[i]) {
+ return false;
+ }
+ }
+
+ for (int i = longdata.length - 1; i >= shortdata.length; i--) {
+ if (longdata[i] != 0) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public int getCardinality() {
+
+ boolean found = false;
+ int[] intdata = data;
+
+ for (int i = intdata.length - 1; i >= 0; i--) {
+ int block = intdata[i];
+ if (block != 0) {
+ if (found) {
+ return 2;
+ }
+ else {
+ if ((block & (block - 1)) == 0) {
+ found = true;
+ }
+ else {
+ return 2;
+ }
+ }
+ }
+ }
+
+ return found ? 1 : 0;
+ }
+
+ public boolean isEmpty() {
+ return data.length == 0 || (next[0] == 0 && data[0] == 0);
+ }
+
+ public Iterator<E> iterator() {
+ return new FastSparseSetIterator<E>(this);
+ }
+
+ public Set<E> toPlainSet() {
+ HashSet<E> set = new HashSet<E>();
+
+ int[] intdata = data;
+
+ int size = data.length * 32;
+ if (size > colValuesInternal.size()) {
+ size = colValuesInternal.size();
+ }
+
+ for (int i = size - 1; i >= 0; i--) {
+ int[] index = colValuesInternal.get(i);
+
+ if ((intdata[index[0]] & index[1]) != 0) {
+ set.add(colValuesInternal.getKey(i));
+ }
+ }
+
+ return set;
+ }
+
+ public String toString() {
+ return toPlainSet().toString();
+ }
+
+ public String toBinary() {
+
+ StringBuilder buffer = new StringBuilder();
+ int[] intdata = data;
+
+ for (int i = 0; i < intdata.length; i++) {
+ buffer.append(" ").append(Integer.toBinaryString(intdata[i]));
+ }
+
+ return buffer.toString();
+ }
+
+ private int[] getData() {
+ return data;
+ }
+
+ private int[] getNext() {
+ return next;
+ }
+
+ public int[] getLoad() {
+ int[] intdata = data;
+ int notempty = 0;
+
+ for (int i = 0; i < intdata.length; i++) {
+ if (intdata[i] != 0) {
+ notempty++;
+ }
+ }
+
+ return new int[]{intdata.length, notempty};
+ }
+
+ public FastSparseSetFactory<E> getFactory() {
+ return factory;
+ }
+ }
+
+ public static class FastSparseSetIterator<E> implements Iterator<E> {
+
+ private VBStyleCollection<int[], E> colValuesInternal;
+ private int[] data;
+ private int[] next;
+ private int size;
+
+ private int pointer = -1;
+ private int next_pointer = -1;
+
+ private FastSparseSetIterator(FastSparseSet<E> set) {
+ colValuesInternal = set.getFactory().getInternalValuesCollection();
+ data = set.getData();
+ next = set.getNext();
+ size = colValuesInternal.size();
+ }
+
+ private int getNextIndex(int index) {
+
+ index++;
+ int bindex = index >>> 5;
+ int dindex = index & 0x1F;
+
+ while (bindex < data.length) {
+ int block = data[bindex];
+
+ if (block != 0) {
+ block >>>= dindex;
+ while (dindex < 32) {
+ if ((block & 1) != 0) {
+ return (bindex << 5) + dindex;
+ }
+ block >>>= 1;
+ dindex++;
+ }
+ }
+
+ dindex = 0;
+ bindex = next[bindex];
+
+ if (bindex == 0) {
+ break;
+ }
+ }
+
+ return -1;
+ }
+
+ public boolean hasNext() {
+ next_pointer = getNextIndex(pointer);
+ return (next_pointer >= 0);
+ }
+
+ public E next() {
+ if (next_pointer >= 0) {
+ pointer = next_pointer;
+ }
+ else {
+ pointer = getNextIndex(pointer);
+ if (pointer == -1) {
+ pointer = size;
+ }
+ }
+
+ next_pointer = -1;
+ return pointer < size ? colValuesInternal.getKey(pointer) : null;
+ }
+
+ public void remove() {
+ int[] index = colValuesInternal.get(pointer);
+ data[index[0]] &= ~index[1];
+ }
+ }
+}
+
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/InterpreterUtil.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/InterpreterUtil.java
new file mode 100644
index 000000000000..0047bb792c87
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/InterpreterUtil.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.util;
+
+import org.jetbrains.java.decompiler.main.DecompilerContext;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
+
+import java.io.*;
+import java.nio.channels.FileChannel;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+public class InterpreterUtil {
+ public static final boolean IS_WINDOWS = System.getProperty("os.name", "").startsWith("Windows");
+
+ private static final int CHANNEL_WINDOW_SIZE = IS_WINDOWS ? 64 * 1024 * 1024 - (32 * 1024) : 64 * 1024 * 1024; // magic number for Windows
+ private static final int BUFFER_SIZE = 16* 1024;
+
+ public static void copyFile(File in, File out) throws IOException {
+ FileInputStream inStream = new FileInputStream(in);
+ try {
+ FileOutputStream outStream = new FileOutputStream(out);
+ try {
+ FileChannel inChannel = inStream.getChannel();
+ FileChannel outChannel = outStream.getChannel();
+ long size = inChannel.size(), position = 0;
+ while (position < size) {
+ position += inChannel.transferTo(position, CHANNEL_WINDOW_SIZE, outChannel);
+ }
+ }
+ finally {
+ outStream.close();
+ }
+ }
+ finally {
+ inStream.close();
+ }
+ }
+
+ public static void copyStream(InputStream in, OutputStream out) throws IOException {
+ byte[] buffer = new byte[BUFFER_SIZE];
+ int len;
+ while ((len = in.read(buffer)) >= 0) {
+ out.write(buffer, 0, len);
+ }
+ }
+
+ public static byte[] getBytes(ZipFile archive, ZipEntry entry) throws IOException {
+ return readAndClose(archive.getInputStream(entry), entry.getSize());
+ }
+
+ public static byte[] getBytes(File file) throws IOException {
+ return readAndClose(new FileInputStream(file), file.length());
+ }
+
+ private static byte[] readAndClose(InputStream stream, long length) throws IOException {
+ try {
+ byte[] bytes = new byte[(int)length];
+ if (stream.read(bytes) != length) {
+ throw new IOException("premature end of stream");
+ }
+ return bytes;
+ }
+ finally {
+ stream.close();
+ }
+ }
+
+ public static String getIndentString(int length) {
+ if (length == 0) return "";
+ StringBuilder buf = new StringBuilder();
+ appendIndent(buf, length);
+ return buf.toString();
+ }
+
+ public static void appendIndent(StringBuilder buffer, int length) {
+ if (length == 0) return;
+ String indent = (String)DecompilerContext.getProperty(IFernflowerPreferences.INDENT_STRING);
+ while (length-- > 0) {
+ buffer.append(indent);
+ }
+ }
+
+ public static boolean equalSets(Collection<?> c1, Collection<?> c2) {
+ if (c1 == null) {
+ return c2 == null;
+ }
+ else if (c2 == null) {
+ return false;
+ }
+
+ if (c1.size() != c2.size()) {
+ return false;
+ }
+
+ HashSet<Object> set = new HashSet<Object>(c1);
+ set.removeAll(c2);
+ return (set.size() == 0);
+ }
+
+ public static boolean equalObjects(Object first, Object second) {
+ return first == null ? second == null : first.equals(second);
+ }
+
+ public static boolean equalObjectArrays(Object[] first, Object[] second) {
+ if (first == null || second == null) {
+ return equalObjects(first, second);
+ }
+ else {
+ if (first.length != second.length) {
+ return false;
+ }
+
+ for (int i = 0; i < first.length; i++) {
+ if (!equalObjects(first[i], second[i])) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public static boolean equalLists(List<?> first, List<?> second) {
+ if (first == null) {
+ return second == null;
+ }
+ else if (second == null) {
+ return false;
+ }
+
+ if (first.size() == second.size()) {
+ for (int i = 0; i < first.size(); i++) {
+ if (!equalObjects(first.get(i), second.get(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+ public static boolean isPrintableUnicode(char c) {
+ int t = Character.getType(c);
+ return t != Character.UNASSIGNED && t != Character.LINE_SEPARATOR && t != Character.PARAGRAPH_SEPARATOR &&
+ t != Character.CONTROL && t != Character.FORMAT && t != Character.PRIVATE_USE && t != Character.SURROGATE;
+ }
+
+ public static String charToUnicodeLiteral(int value) {
+ String sTemp = Integer.toHexString(value);
+ sTemp = ("0000" + sTemp).substring(sTemp.length());
+ return "\\u" + sTemp;
+ }
+
+ public static String makeUniqueKey(String name, String descriptor) {
+ return name + " " + descriptor;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/ListStack.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/ListStack.java
new file mode 100644
index 000000000000..19c2416c44de
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/ListStack.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.util;
+
+import java.util.ArrayList;
+
+public class ListStack<T> extends ArrayList<T> {
+
+ protected int pointer = 0;
+
+ public ListStack() {
+ super();
+ }
+
+ public ListStack(ArrayList<T> list) {
+ super(list);
+ }
+
+ public ListStack<T> clone() {
+ ListStack<T> newstack = new ListStack<T>(this);
+ newstack.pointer = this.pointer;
+ return newstack;
+ }
+
+ public T push(T item) {
+ this.add(item);
+ pointer++;
+ return item;
+ }
+
+ public T pop() {
+ pointer--;
+ T o = this.get(pointer);
+ this.remove(pointer);
+ return o;
+ }
+
+ public T pop(int count) {
+ T o = null;
+ for (int i = count; i > 0; i--) {
+ o = this.pop();
+ }
+ return o;
+ }
+
+ public void remove() {
+ pointer--;
+ this.remove(pointer);
+ }
+
+ public void removeMultiple(int count) {
+ while (count > 0) {
+ pointer--;
+ this.remove(pointer);
+ count--;
+ }
+ }
+
+ public boolean empty() {
+ return (pointer == 0);
+ }
+
+ public int getPointer() {
+ return pointer;
+ }
+
+ public T getByOffset(int offset) {
+ return this.get(pointer + offset);
+ }
+
+ public void insertByOffset(int offset, T item) {
+ this.add(pointer + offset, item);
+ pointer++;
+ }
+
+ public void clear() {
+ super.clear();
+ pointer = 0;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/SFormsFastMapDirect.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/SFormsFastMapDirect.java
new file mode 100644
index 000000000000..996607a2bdbc
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/SFormsFastMapDirect.java
@@ -0,0 +1,414 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.util;
+
+import org.jetbrains.java.decompiler.modules.decompiler.exps.VarExprent;
+import org.jetbrains.java.decompiler.util.FastSparseSetFactory.FastSparseSet;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+
+public class SFormsFastMapDirect {
+
+ private int size;
+
+ @SuppressWarnings("unchecked") private FastSparseSet<Integer>[][] elements = new FastSparseSet[3][];
+
+ private int[][] next = new int[3][];
+
+ public SFormsFastMapDirect() {
+ this(true);
+ }
+
+ private SFormsFastMapDirect(boolean initialize) {
+ if (initialize) {
+ for (int i = 2; i >= 0; i--) {
+ @SuppressWarnings("unchecked") FastSparseSet<Integer>[] empty = new FastSparseSet[0];
+ elements[i] = empty;
+ next[i] = new int[0];
+ }
+ }
+ }
+
+ public SFormsFastMapDirect(SFormsFastMapDirect map) {
+ for (int i = 2; i >= 0; i--) {
+ FastSparseSet<Integer>[] arr = map.elements[i];
+ int[] arrnext = map.next[i];
+
+ int length = arr.length;
+ @SuppressWarnings("unchecked") FastSparseSet<Integer>[] arrnew = new FastSparseSet[length];
+ int[] arrnextnew = new int[length];
+
+ System.arraycopy(arr, 0, arrnew, 0, length);
+ System.arraycopy(arrnext, 0, arrnextnew, 0, length);
+
+ elements[i] = arrnew;
+ next[i] = arrnextnew;
+
+ size = map.size;
+ }
+ }
+
+ public SFormsFastMapDirect getCopy() {
+
+ SFormsFastMapDirect map = new SFormsFastMapDirect(false);
+ map.size = size;
+
+ FastSparseSet[][] mapelements = map.elements;
+ int[][] mapnext = map.next;
+
+ for (int i = 2; i >= 0; i--) {
+ FastSparseSet<Integer>[] arr = elements[i];
+ int length = arr.length;
+
+ if (length > 0) {
+ int[] arrnext = next[i];
+
+ @SuppressWarnings("unchecked") FastSparseSet<Integer>[] arrnew = new FastSparseSet[length];
+ int[] arrnextnew = new int[length];
+
+ System.arraycopy(arrnext, 0, arrnextnew, 0, length);
+
+ mapelements[i] = arrnew;
+ mapnext[i] = arrnextnew;
+
+ int pointer = 0;
+ do {
+ FastSparseSet<Integer> set = arr[pointer];
+ if (set != null) {
+ arrnew[pointer] = set.getCopy();
+ }
+
+ pointer = arrnext[pointer];
+ }
+ while (pointer != 0);
+ }
+ else {
+ mapelements[i] = new FastSparseSet[0];
+ mapnext[i] = new int[0];
+ }
+ }
+
+ return map;
+ }
+
+ public int size() {
+ return size;
+ }
+
+ public boolean isEmpty() {
+ return size == 0;
+ }
+
+ public void put(int key, FastSparseSet<Integer> value) {
+ putInternal(key, value, false);
+ }
+
+ public void remove(int key) {
+ putInternal(key, null, true);
+ }
+
+ public void removeAllFields() {
+ FastSparseSet<Integer>[] arr = elements[2];
+ int[] arrnext = next[2];
+
+ for (int i = arr.length - 1; i >= 0; i--) {
+ FastSparseSet<Integer> val = arr[i];
+ if (val != null) {
+ arr[i] = null;
+ size--;
+ }
+ arrnext[i] = 0;
+ }
+ }
+
+ public void putInternal(final int key, final FastSparseSet<Integer> value, boolean remove) {
+
+ int index = 0;
+ int ikey = key;
+ if (ikey < 0) {
+ index = 2;
+ ikey = -ikey;
+ }
+ else if (ikey >= VarExprent.STACK_BASE) {
+ index = 1;
+ ikey -= VarExprent.STACK_BASE;
+ }
+
+ FastSparseSet<Integer>[] arr = elements[index];
+ if (ikey >= arr.length) {
+ if (remove) {
+ return;
+ }
+ else {
+ arr = ensureCapacity(index, ikey + 1, false);
+ }
+ }
+
+ FastSparseSet<Integer> oldval = arr[ikey];
+ arr[ikey] = value;
+
+ int[] arrnext = next[index];
+
+ if (oldval == null && value != null) {
+ size++;
+ changeNext(arrnext, ikey, arrnext[ikey], ikey);
+ }
+ else if (oldval != null && value == null) {
+ size--;
+ changeNext(arrnext, ikey, ikey, arrnext[ikey]);
+ }
+ }
+
+ private static void changeNext(int[] arrnext, int key, int oldnext, int newnext) {
+ for (int i = key - 1; i >= 0; i--) {
+ if (arrnext[i] == oldnext) {
+ arrnext[i] = newnext;
+ }
+ else {
+ break;
+ }
+ }
+ }
+
+ public boolean containsKey(int key) {
+ return get(key) != null;
+ }
+
+ public FastSparseSet<Integer> get(int key) {
+
+ int index = 0;
+ if (key < 0) {
+ index = 2;
+ key = -key;
+ }
+ else if (key >= VarExprent.STACK_BASE) {
+ index = 1;
+ key -= VarExprent.STACK_BASE;
+ }
+
+ FastSparseSet<Integer>[] arr = elements[index];
+
+ if (key < arr.length) {
+ return arr[key];
+ }
+ return null;
+ }
+
+ public void complement(SFormsFastMapDirect map) {
+
+ for (int i = 2; i >= 0; i--) {
+ FastSparseSet<Integer>[] lstOwn = elements[i];
+
+ if (lstOwn.length == 0) {
+ continue;
+ }
+
+ FastSparseSet<Integer>[] lstExtern = map.elements[i];
+ int[] arrnext = next[i];
+
+ int pointer = 0;
+ do {
+ FastSparseSet<Integer> first = lstOwn[pointer];
+
+ if (first != null) {
+ if (pointer >= lstExtern.length) {
+ break;
+ }
+ FastSparseSet<Integer> second = lstExtern[pointer];
+
+ if (second != null) {
+ first.complement(second);
+ if (first.isEmpty()) {
+ lstOwn[pointer] = null;
+ size--;
+ changeNext(arrnext, pointer, pointer, arrnext[pointer]);
+ }
+ }
+ }
+
+ pointer = arrnext[pointer];
+ }
+ while (pointer != 0);
+ }
+ }
+
+ public void intersection(SFormsFastMapDirect map) {
+
+ for (int i = 2; i >= 0; i--) {
+ FastSparseSet<Integer>[] lstOwn = elements[i];
+
+ if (lstOwn.length == 0) {
+ continue;
+ }
+
+ FastSparseSet<Integer>[] lstExtern = map.elements[i];
+ int[] arrnext = next[i];
+
+ int pointer = 0;
+ do {
+ FastSparseSet<Integer> first = lstOwn[pointer];
+
+ if (first != null) {
+ FastSparseSet<Integer> second = null;
+ if (pointer < lstExtern.length) {
+ second = lstExtern[pointer];
+ }
+
+ if (second != null) {
+ first.intersection(second);
+ }
+
+ if (second == null || first.isEmpty()) {
+ lstOwn[pointer] = null;
+ size--;
+ changeNext(arrnext, pointer, pointer, arrnext[pointer]);
+ }
+ }
+
+ pointer = arrnext[pointer];
+ }
+ while (pointer != 0);
+ }
+ }
+
+ public void union(SFormsFastMapDirect map) {
+
+ for (int i = 2; i >= 0; i--) {
+ FastSparseSet<Integer>[] lstExtern = map.elements[i];
+
+ if (lstExtern.length == 0) {
+ continue;
+ }
+
+ FastSparseSet<Integer>[] lstOwn = elements[i];
+ int[] arrnext = next[i];
+ int[] arrnextExtern = map.next[i];
+
+ int pointer = 0;
+ do {
+ if (pointer >= lstOwn.length) {
+ lstOwn = ensureCapacity(i, lstExtern.length, true);
+ arrnext = next[i];
+ }
+
+ FastSparseSet<Integer> second = lstExtern[pointer];
+
+ if (second != null) {
+ FastSparseSet<Integer> first = lstOwn[pointer];
+
+ if (first == null) {
+ lstOwn[pointer] = second.getCopy();
+ size++;
+ changeNext(arrnext, pointer, arrnext[pointer], pointer);
+ }
+ else {
+ first.union(second);
+ }
+ }
+
+ pointer = arrnextExtern[pointer];
+ }
+ while (pointer != 0);
+ }
+ }
+
+ public String toString() {
+
+ StringBuilder buffer = new StringBuilder("{");
+
+ List<Entry<Integer, FastSparseSet<Integer>>> lst = entryList();
+ if (lst != null) {
+ boolean first = true;
+ for (Entry<Integer, FastSparseSet<Integer>> entry : lst) {
+ if (!first) {
+ buffer.append(", ");
+ }
+ else {
+ first = false;
+ }
+
+ Set<Integer> set = entry.getValue().toPlainSet();
+ buffer.append(entry.getKey()).append("={").append(set.toString()).append("}");
+ }
+ }
+
+ buffer.append("}");
+ return buffer.toString();
+ }
+
+ public List<Entry<Integer, FastSparseSet<Integer>>> entryList() {
+ List<Entry<Integer, FastSparseSet<Integer>>> list = new ArrayList<Entry<Integer, FastSparseSet<Integer>>>();
+
+ for (int i = 2; i >= 0; i--) {
+ int ikey = 0;
+ for (final FastSparseSet<Integer> ent : elements[i]) {
+ if (ent != null) {
+ final int key = i == 0 ? ikey : (i == 1 ? ikey + VarExprent.STACK_BASE : -ikey);
+
+ list.add(new Entry<Integer, FastSparseSet<Integer>>() {
+
+ private Integer var = key;
+ private FastSparseSet<Integer> val = ent;
+
+ public Integer getKey() {
+ return var;
+ }
+
+ public FastSparseSet<Integer> getValue() {
+ return val;
+ }
+
+ public FastSparseSet<Integer> setValue(FastSparseSet<Integer> newvalue) {
+ return null;
+ }
+ });
+ }
+
+ ikey++;
+ }
+ }
+
+ return list;
+ }
+
+ private FastSparseSet<Integer>[] ensureCapacity(int index, int size, boolean exact) {
+
+ FastSparseSet<Integer>[] arr = elements[index];
+ int[] arrnext = next[index];
+
+ int minsize = size;
+ if (!exact) {
+ minsize = 2 * arr.length / 3 + 1;
+ if (size > minsize) {
+ minsize = size;
+ }
+ }
+
+ @SuppressWarnings("unchecked") FastSparseSet<Integer>[] arrnew = new FastSparseSet[minsize];
+ System.arraycopy(arr, 0, arrnew, 0, arr.length);
+
+ int[] arrnextnew = new int[minsize];
+ System.arraycopy(arrnext, 0, arrnextnew, 0, arrnext.length);
+
+ elements[index] = arrnew;
+ next[index] = arrnextnew;
+
+ return arrnew;
+ }
+}
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/VBStyleCollection.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/VBStyleCollection.java
new file mode 100644
index 000000000000..cdc176263cd2
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/util/VBStyleCollection.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler.util;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+
+public class VBStyleCollection<E, K> extends ArrayList<E> {
+
+ private HashMap<K, Integer> map = new HashMap<K, Integer>();
+
+ private ArrayList<K> lstKeys = new ArrayList<K>();
+
+ public VBStyleCollection() {
+ super();
+ }
+
+ public VBStyleCollection(int initialCapacity) {
+ super(initialCapacity);
+ lstKeys = new ArrayList<K>(initialCapacity);
+ map = new HashMap<K, Integer>(initialCapacity);
+ }
+
+ public VBStyleCollection(Collection<E> c) {
+ super(c);
+ }
+
+ public boolean add(E element) {
+ lstKeys.add(null);
+ super.add(element);
+ return true;
+ }
+
+ public boolean remove(Object element) { // TODO: error on void remove(E element)
+ throw new RuntimeException("not implemented!");
+ }
+
+ public boolean addAll(Collection<? extends E> c) {
+ for (int i = c.size() - 1; i >= 0; i--) {
+ lstKeys.add(null);
+ }
+ return super.addAll(c);
+ }
+
+ public void addAllWithKey(VBStyleCollection<E, K> c) {
+ for (int i = 0; i < c.size(); i++) {
+ addWithKey(c.get(i), c.getKey(i));
+ }
+ }
+
+ public void addAllWithKey(Collection<E> elements, Collection<K> keys) {
+ int index = super.size();
+
+ for (K key : keys) {
+ map.put(key, index++);
+ }
+
+ super.addAll(elements);
+ lstKeys.addAll(keys);
+ }
+
+ public void addWithKey(E element, K key) {
+ map.put(key, super.size());
+ super.add(element);
+ lstKeys.add(key);
+ }
+
+ // TODO: speed up the method
+ public E putWithKey(E element, K key) {
+ Integer index = map.get(key);
+ if (index == null) {
+ addWithKey(element, key);
+ }
+ else {
+ return super.set(index, element);
+ }
+ return null;
+ }
+
+ public void add(int index, E element) {
+ addToListIndex(index, 1);
+ lstKeys.add(index, null);
+ super.add(index, element);
+ }
+
+ public void addWithKeyAndIndex(int index, E element, K key) {
+ addToListIndex(index, 1);
+ map.put(key, new Integer(index));
+ super.add(index, element);
+ lstKeys.add(index, key);
+ }
+
+ public void removeWithKey(K key) {
+ int index = map.get(key).intValue();
+ addToListIndex(index + 1, -1);
+ super.remove(index);
+ lstKeys.remove(index);
+ map.remove(key);
+ }
+
+ public E remove(int index) {
+ addToListIndex(index + 1, -1);
+ K obj = lstKeys.get(index);
+ if (obj != null) {
+ map.remove(obj);
+ }
+ lstKeys.remove(index);
+ return super.remove(index);
+ }
+
+ public E getWithKey(K key) {
+ Integer index = map.get(key);
+ if (index == null) {
+ return null;
+ }
+ return super.get(index.intValue());
+ }
+
+ public int getIndexByKey(K key) {
+ return map.get(key).intValue();
+ }
+
+ public E getLast() {
+ return super.get(super.size() - 1);
+ }
+
+ public boolean containsKey(K key) {
+ return map.containsKey(key);
+ }
+
+ public void clear() {
+ map.clear();
+ lstKeys.clear();
+ super.clear();
+ }
+
+ public VBStyleCollection<E, K> clone() {
+ VBStyleCollection<E, K> c = new VBStyleCollection<E, K>();
+ c.addAll(new ArrayList<E>(this));
+ c.setMap(new HashMap<K, Integer>(map));
+ c.setLstKeys(new ArrayList<K>(lstKeys));
+ return c;
+ }
+
+ public void swap(int index1, int index2) {
+
+ Collections.swap(this, index1, index2);
+ Collections.swap(lstKeys, index1, index2);
+
+ K key = lstKeys.get(index1);
+ if (key != null) {
+ map.put(key, new Integer(index1));
+ }
+
+ key = lstKeys.get(index2);
+ if (key != null) {
+ map.put(key, new Integer(index2));
+ }
+ }
+
+ public HashMap<K, Integer> getMap() {
+ return map;
+ }
+
+ public void setMap(HashMap<K, Integer> map) {
+ this.map = map;
+ }
+
+ public K getKey(int index) {
+ return lstKeys.get(index);
+ }
+
+ public ArrayList<K> getLstKeys() {
+ return lstKeys;
+ }
+
+ public void setLstKeys(ArrayList<K> lstKeys) {
+ this.lstKeys = lstKeys;
+ }
+
+ private void addToListIndex(int index, int diff) {
+ for (int i = lstKeys.size() - 1; i >= index; i--) {
+ K obj = lstKeys.get(i);
+ if (obj != null) {
+ map.put(obj, new Integer(i + diff));
+ }
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/test/org/jetbrains/java/decompiler/BulkDecompilationTest.java b/plugins/java-decompiler/engine/test/org/jetbrains/java/decompiler/BulkDecompilationTest.java
new file mode 100644
index 000000000000..1b5353b37a49
--- /dev/null
+++ b/plugins/java-decompiler/engine/test/org/jetbrains/java/decompiler/BulkDecompilationTest.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler;
+
+import org.hamcrest.Matchers;
+import org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler;
+import org.jetbrains.java.decompiler.util.InterpreterUtil;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.*;
+import java.util.Enumeration;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+public class BulkDecompilationTest {
+ private DecompilerTestFixture fixture;
+
+ @Before
+ public void setUp() throws IOException {
+ fixture = new DecompilerTestFixture();
+ fixture.setUp();
+ }
+
+ @After
+ public void tearDown() {
+ fixture.tearDown();
+ fixture = null;
+ }
+
+ @Test
+ public void testDirectory() {
+ File classes = new File(fixture.getTempDir(), "classes");
+ unpack(new File(fixture.getTestDataDir(), "bulk.jar"), classes);
+
+ ConsoleDecompiler decompiler = fixture.getDecompiler();
+ decompiler.addSpace(classes, true);
+ decompiler.decompileContext();
+
+ compareDirectories(new File(fixture.getTestDataDir(), "bulk"), fixture.getTargetDir());
+ }
+
+ @Test
+ public void testJar() {
+ ConsoleDecompiler decompiler = fixture.getDecompiler();
+ decompiler.addSpace(new File(fixture.getTestDataDir(), "bulk.jar"), true);
+ decompiler.decompileContext();
+
+ File unpacked = new File(fixture.getTempDir(), "unpacked");
+ unpack(new File(fixture.getTargetDir(), "bulk.jar"), unpacked);
+
+ compareDirectories(new File(fixture.getTestDataDir(), "bulk"), unpacked);
+ }
+
+ private static void unpack(File archive, File targetDir) {
+ try {
+ ZipFile zip = new ZipFile(archive);
+ try {
+ Enumeration<? extends ZipEntry> entries = zip.entries();
+ while (entries.hasMoreElements()) {
+ ZipEntry entry = entries.nextElement();
+ if (!entry.isDirectory()) {
+ File file = new File(targetDir, entry.getName());
+ assertTrue(file.getParentFile().mkdirs() || file.getParentFile().isDirectory());
+ InputStream in = zip.getInputStream(entry);
+ OutputStream out = new FileOutputStream(file);
+ InterpreterUtil.copyStream(in, out);
+ out.close();
+ in.close();
+ }
+ }
+ }
+ finally {
+ zip.close();
+ }
+ }
+ catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static void compareDirectories(File expected, File actual) {
+ String[] expectedList = expected.list();
+ String[] actualList = actual.list();
+ assertThat(actualList, Matchers.arrayContainingInAnyOrder(expectedList));
+ for (String name : expectedList) {
+ File child = new File(expected, name);
+ if (child.isDirectory()) {
+ compareDirectories(child, new File(actual, name));
+ }
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/test/org/jetbrains/java/decompiler/DecompilerTestFixture.java b/plugins/java-decompiler/engine/test/org/jetbrains/java/decompiler/DecompilerTestFixture.java
new file mode 100644
index 000000000000..b82b65e2155b
--- /dev/null
+++ b/plugins/java-decompiler/engine/test/org/jetbrains/java/decompiler/DecompilerTestFixture.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler;
+
+import org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
+
+import java.io.*;
+import java.util.HashMap;
+
+import static org.junit.Assert.assertTrue;
+
+public class DecompilerTestFixture {
+ private File testDataDir;
+ private File tempDir;
+ private File targetDir;
+ private ConsoleDecompiler decompiler;
+
+ public void setUp() throws IOException {
+ testDataDir = new File("testData");
+ if (!isTestDataDir(testDataDir)) testDataDir = new File("community/plugins/java-decompiler/engine/testData");
+ if (!isTestDataDir(testDataDir)) testDataDir = new File("plugins/java-decompiler/engine/testData");
+ assertTrue("current dir: " + new File("").getAbsolutePath(), isTestDataDir(testDataDir));
+
+ //noinspection SSBasedInspection
+ tempDir = File.createTempFile("decompiler_test_", "_dir");
+ assertTrue(tempDir.delete());
+
+ targetDir = new File(tempDir, "decompiled");
+ assertTrue(targetDir.mkdirs());
+ decompiler = new ConsoleDecompiler(this.targetDir, new HashMap<String, Object>() {{
+ put(IFernflowerPreferences.LOG_LEVEL, "warn");
+ put(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES, "1");
+ put(IFernflowerPreferences.REMOVE_SYNTHETIC, "1");
+ put(IFernflowerPreferences.REMOVE_BRIDGE, "1");
+ put(IFernflowerPreferences.LITERALS_AS_IS, "1");
+ }});
+ }
+
+ public void tearDown() {
+ if (tempDir != null) {
+ delete(tempDir);
+ }
+ }
+
+ public File getTestDataDir() {
+ return testDataDir;
+ }
+
+ public File getTempDir() {
+ return tempDir;
+ }
+
+ public File getTargetDir() {
+ return targetDir;
+ }
+
+ public ConsoleDecompiler getDecompiler() {
+ return decompiler;
+ }
+
+ private static boolean isTestDataDir(File dir) {
+ return dir.isDirectory() && new File(dir, "classes").isDirectory() && new File(dir, "results").isDirectory();
+ }
+
+ private static void delete(File file) {
+ if (file.isDirectory()) {
+ File[] files = file.listFiles();
+ if (files != null) {
+ for (File f : files) delete(f);
+ }
+ }
+ assertTrue(file.delete());
+ }
+}
diff --git a/plugins/java-decompiler/engine/test/org/jetbrains/java/decompiler/SingleClassesTest.java b/plugins/java-decompiler/engine/test/org/jetbrains/java/decompiler/SingleClassesTest.java
new file mode 100644
index 000000000000..70aa605e8630
--- /dev/null
+++ b/plugins/java-decompiler/engine/test/org/jetbrains/java/decompiler/SingleClassesTest.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.java.decompiler;
+
+import org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class SingleClassesTest {
+ private DecompilerTestFixture fixture;
+
+ @Before
+ public void setUp() throws IOException {
+ fixture = new DecompilerTestFixture();
+ fixture.setUp();
+ }
+
+ @After
+ public void tearDown() {
+ fixture.tearDown();
+ fixture = null;
+ }
+
+ @Test public void testClassFields() { doTest("pkg/TestClassFields"); }
+ @Test public void testClassLambda() { doTest("pkg/TestClassLambda"); }
+ @Test public void testClassLoop() { doTest("pkg/TestClassLoop"); }
+ @Test public void testClassSwitch() { doTest("pkg/TestClassSwitch"); }
+ @Test public void testClassTypes() { doTest("pkg/TestClassTypes"); }
+ @Test public void testClassVar() { doTest("pkg/TestClassVar"); }
+ @Test public void testClassNestedInitializer() { doTest("pkg/TestClassNestedInitializer"); }
+ @Test public void testClassCast() { doTest("pkg/TestClassCast"); }
+ @Test public void testDeprecations() { doTest("pkg/TestDeprecations"); }
+ @Test public void testExtendsList() { doTest("pkg/TestExtendsList"); }
+ @Test public void testMethodParameters() { doTest("pkg/TestMethodParameters"); }
+ @Test public void testCodeConstructs() { doTest("pkg/TestCodeConstructs"); }
+ @Test public void testConstants() { doTest("pkg/TestConstants"); }
+ @Test public void testEnum() { doTest("pkg/TestEnum"); }
+ @Test public void testDebugSymbols() { doTest("pkg/TestDebugSymbols"); }
+ @Test public void testInvalidMethodSignature() { doTest("InvalidMethodSignature"); }
+
+ private void doTest(String testFile) {
+ try {
+ File classFile = new File(fixture.getTestDataDir(), "/classes/" + testFile + ".class");
+ assertTrue(classFile.isFile());
+ String testName = classFile.getName().replace(".class", "");
+
+ ConsoleDecompiler decompiler = fixture.getDecompiler();
+ for (File file : collectClasses(classFile)) {
+ decompiler.addSpace(file, true);
+ }
+
+ decompiler.decompileContext();
+
+ File decompiledFile = new File(fixture.getTargetDir(), testName + ".java");
+ assertTrue(decompiledFile.isFile());
+
+ File referenceFile = new File(fixture.getTestDataDir(), "results/" + testName + ".dec");
+ assertTrue(referenceFile.isFile());
+
+ String decompiledContent = getContent(decompiledFile);
+ String referenceContent = getContent(referenceFile);
+ assertEquals(referenceContent, decompiledContent);
+ }
+ catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static List<File> collectClasses(File classFile) {
+ List<File> files = new ArrayList<File>();
+ files.add(classFile);
+
+ File parent = classFile.getParentFile();
+ if (parent != null) {
+ final String pattern = classFile.getName().replace(".class", "") + "\\$.+\\.class";
+ File[] inner = parent.listFiles(new FilenameFilter() {
+ @Override
+ public boolean accept(File dir, String name) {
+ return name.matches(pattern);
+ }
+ });
+ if (inner != null) Collections.addAll(files, inner);
+ }
+
+ return files;
+ }
+
+ private static String getContent(File file) throws IOException {
+ Reader reader = new InputStreamReader(new FileInputStream(file), "UTF-8");
+ try {
+ char[] buff = new char[16 * 1024];
+ StringBuilder content = new StringBuilder();
+ int n;
+ while ((n = reader.read(buff)) > 0) {
+ content.append(buff, 0, n);
+ }
+ return content.toString();
+ }
+ finally {
+ reader.close();
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/testData/bulk.jar b/plugins/java-decompiler/engine/testData/bulk.jar
new file mode 100644
index 000000000000..80e0dcfd5781
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/bulk.jar
Binary files differ
diff --git a/plugins/java-decompiler/engine/testData/bulk/META-INF/MANIFEST.MF b/plugins/java-decompiler/engine/testData/bulk/META-INF/MANIFEST.MF
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/bulk/META-INF/MANIFEST.MF
diff --git a/plugins/java-decompiler/engine/testData/bulk/pkg/Main.java b/plugins/java-decompiler/engine/testData/bulk/pkg/Main.java
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/bulk/pkg/Main.java
diff --git a/plugins/java-decompiler/engine/testData/bulk/pkg/res/Loader.java b/plugins/java-decompiler/engine/testData/bulk/pkg/res/Loader.java
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/bulk/pkg/res/Loader.java
diff --git a/plugins/java-decompiler/engine/testData/bulk/pkg/res/resource.txt b/plugins/java-decompiler/engine/testData/bulk/pkg/res/resource.txt
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/bulk/pkg/res/resource.txt
diff --git a/plugins/java-decompiler/engine/testData/classes/InvalidMethodSignature.class b/plugins/java-decompiler/engine/testData/classes/InvalidMethodSignature.class
new file mode 100644
index 000000000000..3b64eb80cda2
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/classes/InvalidMethodSignature.class
Binary files differ
diff --git a/plugins/java-decompiler/engine/testData/classes/pkg/TestClassCast.class b/plugins/java-decompiler/engine/testData/classes/pkg/TestClassCast.class
new file mode 100644
index 000000000000..5b71ce852454
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/classes/pkg/TestClassCast.class
Binary files differ
diff --git a/plugins/java-decompiler/engine/testData/classes/pkg/TestClassFields.class b/plugins/java-decompiler/engine/testData/classes/pkg/TestClassFields.class
new file mode 100644
index 000000000000..c1c0c6b9717c
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/classes/pkg/TestClassFields.class
Binary files differ
diff --git a/plugins/java-decompiler/engine/testData/classes/pkg/TestClassLambda.class b/plugins/java-decompiler/engine/testData/classes/pkg/TestClassLambda.class
new file mode 100644
index 000000000000..b506ea80c805
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/classes/pkg/TestClassLambda.class
Binary files differ
diff --git a/plugins/java-decompiler/engine/testData/classes/pkg/TestClassLoop.class b/plugins/java-decompiler/engine/testData/classes/pkg/TestClassLoop.class
new file mode 100644
index 000000000000..d363692ff02b
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/classes/pkg/TestClassLoop.class
Binary files differ
diff --git a/plugins/java-decompiler/engine/testData/classes/pkg/TestClassNestedInitializer$1.class b/plugins/java-decompiler/engine/testData/classes/pkg/TestClassNestedInitializer$1.class
new file mode 100644
index 000000000000..42b11df32210
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/classes/pkg/TestClassNestedInitializer$1.class
Binary files differ
diff --git a/plugins/java-decompiler/engine/testData/classes/pkg/TestClassNestedInitializer.class b/plugins/java-decompiler/engine/testData/classes/pkg/TestClassNestedInitializer.class
new file mode 100644
index 000000000000..1aa367010cbc
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/classes/pkg/TestClassNestedInitializer.class
Binary files differ
diff --git a/plugins/java-decompiler/engine/testData/classes/pkg/TestClassSwitch.class b/plugins/java-decompiler/engine/testData/classes/pkg/TestClassSwitch.class
new file mode 100644
index 000000000000..2fd6b5250df7
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/classes/pkg/TestClassSwitch.class
Binary files differ
diff --git a/plugins/java-decompiler/engine/testData/classes/pkg/TestClassTypes.class b/plugins/java-decompiler/engine/testData/classes/pkg/TestClassTypes.class
new file mode 100644
index 000000000000..45288caf7cd1
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/classes/pkg/TestClassTypes.class
Binary files differ
diff --git a/plugins/java-decompiler/engine/testData/classes/pkg/TestClassVar.class b/plugins/java-decompiler/engine/testData/classes/pkg/TestClassVar.class
new file mode 100644
index 000000000000..d66170c04214
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/classes/pkg/TestClassVar.class
Binary files differ
diff --git a/plugins/java-decompiler/engine/testData/classes/pkg/TestCodeConstructs.class b/plugins/java-decompiler/engine/testData/classes/pkg/TestCodeConstructs.class
new file mode 100644
index 000000000000..5727e89464dc
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/classes/pkg/TestCodeConstructs.class
Binary files differ
diff --git a/plugins/java-decompiler/engine/testData/classes/pkg/TestConstants$A.class b/plugins/java-decompiler/engine/testData/classes/pkg/TestConstants$A.class
new file mode 100644
index 000000000000..1d81f91d6fde
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/classes/pkg/TestConstants$A.class
Binary files differ
diff --git a/plugins/java-decompiler/engine/testData/classes/pkg/TestConstants.class b/plugins/java-decompiler/engine/testData/classes/pkg/TestConstants.class
new file mode 100644
index 000000000000..00c924aae6f8
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/classes/pkg/TestConstants.class
Binary files differ
diff --git a/plugins/java-decompiler/engine/testData/classes/pkg/TestDebugSymbols.class b/plugins/java-decompiler/engine/testData/classes/pkg/TestDebugSymbols.class
new file mode 100644
index 000000000000..102e09b778b1
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/classes/pkg/TestDebugSymbols.class
Binary files differ
diff --git a/plugins/java-decompiler/engine/testData/classes/pkg/TestDeprecations$ByAnno.class b/plugins/java-decompiler/engine/testData/classes/pkg/TestDeprecations$ByAnno.class
new file mode 100644
index 000000000000..72c86eadeb48
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/classes/pkg/TestDeprecations$ByAnno.class
Binary files differ
diff --git a/plugins/java-decompiler/engine/testData/classes/pkg/TestDeprecations$ByComment.class b/plugins/java-decompiler/engine/testData/classes/pkg/TestDeprecations$ByComment.class
new file mode 100644
index 000000000000..e5576181f2d4
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/classes/pkg/TestDeprecations$ByComment.class
Binary files differ
diff --git a/plugins/java-decompiler/engine/testData/classes/pkg/TestDeprecations.class b/plugins/java-decompiler/engine/testData/classes/pkg/TestDeprecations.class
new file mode 100644
index 000000000000..f1bb2e34ab4e
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/classes/pkg/TestDeprecations.class
Binary files differ
diff --git a/plugins/java-decompiler/engine/testData/classes/pkg/TestEnum$1.class b/plugins/java-decompiler/engine/testData/classes/pkg/TestEnum$1.class
new file mode 100644
index 000000000000..163965a6acf0
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/classes/pkg/TestEnum$1.class
Binary files differ
diff --git a/plugins/java-decompiler/engine/testData/classes/pkg/TestEnum$2.class b/plugins/java-decompiler/engine/testData/classes/pkg/TestEnum$2.class
new file mode 100644
index 000000000000..25c051bd8943
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/classes/pkg/TestEnum$2.class
Binary files differ
diff --git a/plugins/java-decompiler/engine/testData/classes/pkg/TestEnum.class b/plugins/java-decompiler/engine/testData/classes/pkg/TestEnum.class
new file mode 100644
index 000000000000..397ff04ee01e
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/classes/pkg/TestEnum.class
Binary files differ
diff --git a/plugins/java-decompiler/testData/ExtendsList.class b/plugins/java-decompiler/engine/testData/classes/pkg/TestExtendsList.class
index 7d4eb9c69265..98b5dbb3cfd4 100644
--- a/plugins/java-decompiler/testData/ExtendsList.class
+++ b/plugins/java-decompiler/engine/testData/classes/pkg/TestExtendsList.class
Binary files differ
diff --git a/plugins/java-decompiler/engine/testData/classes/pkg/TestMethodParameters$1Local.class b/plugins/java-decompiler/engine/testData/classes/pkg/TestMethodParameters$1Local.class
new file mode 100644
index 000000000000..6ba8aed255a3
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/classes/pkg/TestMethodParameters$1Local.class
Binary files differ
diff --git a/plugins/java-decompiler/engine/testData/classes/pkg/TestMethodParameters$C1.class b/plugins/java-decompiler/engine/testData/classes/pkg/TestMethodParameters$C1.class
new file mode 100644
index 000000000000..843ebc4b8f0a
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/classes/pkg/TestMethodParameters$C1.class
Binary files differ
diff --git a/plugins/java-decompiler/engine/testData/classes/pkg/TestMethodParameters$C2.class b/plugins/java-decompiler/engine/testData/classes/pkg/TestMethodParameters$C2.class
new file mode 100644
index 000000000000..fd52d14bd5fd
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/classes/pkg/TestMethodParameters$C2.class
Binary files differ
diff --git a/plugins/java-decompiler/engine/testData/classes/pkg/TestMethodParameters.class b/plugins/java-decompiler/engine/testData/classes/pkg/TestMethodParameters.class
new file mode 100644
index 000000000000..e439d0c13edf
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/classes/pkg/TestMethodParameters.class
Binary files differ
diff --git a/plugins/java-decompiler/engine/testData/results/InvalidMethodSignature.dec b/plugins/java-decompiler/engine/testData/results/InvalidMethodSignature.dec
new file mode 100644
index 000000000000..3b1bee4d20a9
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/results/InvalidMethodSignature.dec
@@ -0,0 +1,26 @@
+package a.a.a.a.e.f;
+
+import a.a.a.a.a.k;
+import a.a.a.a.c.c;
+import a.a.a.a.c.j;
+import a.a.a.a.e.bg;
+import a.a.a.a.e.f.b;
+import java.io.File;
+
+class i implements bg {
+ private final j a;
+ private final b b;
+
+ i(b var1, j var2) {
+ this.b = var1;
+ this.a = var2;
+ }
+
+ public void a(c var1, k var2, boolean var3) {
+ File var4 = this.a.b().a(var1);
+ b.a(this.b).add(var4);
+ }
+
+ public void a(a.a.a.a.c.b var1) {
+ }
+}
diff --git a/plugins/java-decompiler/engine/testData/results/TestClassCast.dec b/plugins/java-decompiler/engine/testData/results/TestClassCast.dec
new file mode 100644
index 000000000000..e09162ca0f5f
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/results/TestClassCast.dec
@@ -0,0 +1,15 @@
+package pkg;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class TestClassCast {
+ public void test(List var1) {
+ Object var2 = var1;
+ if(var1 != null) {
+ ((List)(var2 = new ArrayList(var1))).add("23");
+ }
+
+ System.out.println(((List)var2).size());
+ }
+}
diff --git a/plugins/java-decompiler/engine/testData/results/TestClassFields.dec b/plugins/java-decompiler/engine/testData/results/TestClassFields.dec
new file mode 100644
index 000000000000..749d828c2a71
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/results/TestClassFields.dec
@@ -0,0 +1,10 @@
+package pkg;
+
+public class TestClassFields {
+ private static int[] sizes;
+ private static String[] names = new String[]{"name1", "name2"};
+
+ static {
+ sizes = new int[names.length];
+ }
+}
diff --git a/plugins/java-decompiler/engine/testData/results/TestClassLambda.dec b/plugins/java-decompiler/engine/testData/results/TestClassLambda.dec
new file mode 100644
index 000000000000..d0485d352461
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/results/TestClassLambda.dec
@@ -0,0 +1,73 @@
+package pkg;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.OptionalInt;
+import java.util.function.Consumer;
+import java.util.function.IntBinaryOperator;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+
+public class TestClassLambda {
+ public int field = 0;
+
+ public void testLambda() {
+ List var1 = Arrays.asList(new Integer[]{Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3), Integer.valueOf(4), Integer.valueOf(5), Integer.valueOf(6), Integer.valueOf(7)});
+ int var2 = (int)Math.random();
+ var1.forEach((var2x) -> {
+ int var3 = 2 * var2x.intValue();
+ System.out.println(var3 + var2 + this.field);
+ });
+ }
+
+ public void testLambda1() {
+ int var1 = (int)Math.random();
+ Runnable var2 = () -> {
+ System.out.println("hello1" + var1);
+ };
+ Runnable var3 = () -> {
+ System.out.println("hello2" + var1);
+ };
+ }
+
+ public void testLambda2() {
+ reduce((var0, var1) -> {
+ return Math.max(var0, var1);
+ });
+ }
+
+ public void testLambda3() {
+ reduce(Math::max);
+ }
+
+ public void testLambda4() {
+ reduce(TestClassLambda::localMax);
+ }
+
+ public void testLambda5() {
+ String var1 = "abcd";
+ function(var1::toString);
+ }
+
+ public void testLambda6() {
+ ArrayList var1 = new ArrayList();
+ int var2 = var1.size() * 2;
+ int var3 = var1.size() * 5;
+ var1.removeIf((var2x) -> {
+ return var2 >= var2x.length() && var2x.length() <= var3;
+ });
+ }
+
+ public static OptionalInt reduce(IntBinaryOperator var0) {
+ return null;
+ }
+
+ public static String function(Supplier<String> var0) {
+ return (String)var0.get();
+ }
+
+ public static int localMax(int var0, int var1) {
+ return 0;
+ }
+}
diff --git a/plugins/java-decompiler/engine/testData/results/TestClassLoop.dec b/plugins/java-decompiler/engine/testData/results/TestClassLoop.dec
new file mode 100644
index 000000000000..74b8bac5d5e7
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/results/TestClassLoop.dec
@@ -0,0 +1,43 @@
+package pkg;
+
+public class TestClassLoop {
+ public static void testSimpleInfinite() {
+ while(true) {
+ System.out.println();
+ }
+ }
+
+ public static void testFinally() {
+ boolean var0 = Math.random() > 0.0D;
+
+ while(true) {
+ try {
+ if(!var0) {
+ return;
+ }
+ } finally {
+ System.out.println("1");
+ }
+ }
+ }
+
+ public static void testFinallyContinue() {
+ boolean var0 = Math.random() > 0.0D;
+
+ while(true) {
+ while(true) {
+ try {
+ System.out.println("1");
+ break;
+ } finally {
+ if(var0) {
+ System.out.println("3");
+ continue;
+ }
+ }
+ }
+
+ System.out.println("4");
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/testData/results/TestClassNestedInitializer.dec b/plugins/java-decompiler/engine/testData/results/TestClassNestedInitializer.dec
new file mode 100644
index 000000000000..585b01a0261c
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/results/TestClassNestedInitializer.dec
@@ -0,0 +1,14 @@
+package pkg;
+
+public class TestClassNestedInitializer {
+ public String secret;
+
+ public void test() {
+ TestClassNestedInitializer var1 = new TestClassNestedInitializer() {
+ {
+ this.secret = "one";
+ }
+ };
+ System.out.println(var1.secret);
+ }
+}
diff --git a/plugins/java-decompiler/engine/testData/results/TestClassSwitch.dec b/plugins/java-decompiler/engine/testData/results/TestClassSwitch.dec
new file mode 100644
index 000000000000..50efbe9b16f9
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/results/TestClassSwitch.dec
@@ -0,0 +1,14 @@
+package pkg;
+
+public class TestClassSwitch {
+ public void testCaseOrder(int var1) {
+ switch(var1) {
+ case 5:
+ System.out.println(5);
+ default:
+ return;
+ case 13:
+ System.out.println(13);
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/testData/results/TestClassTypes.dec b/plugins/java-decompiler/engine/testData/results/TestClassTypes.dec
new file mode 100644
index 000000000000..7a50473fc3e7
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/results/TestClassTypes.dec
@@ -0,0 +1,49 @@
+package pkg;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class TestClassTypes {
+ public void testBoolean() {
+ byte var1 = 0;
+ long var2 = System.currentTimeMillis();
+ if(var2 % 2L > 0L) {
+ var1 = 1;
+ } else if(var2 % 3L > 0L) {
+ var1 = 2;
+ }
+
+ if(var1 == 1) {
+ System.out.println();
+ }
+
+ }
+
+ public boolean testBit(int var1) {
+ return (var1 & 1) == 1;
+ }
+
+ public void testSwitchConsts(int var1) {
+ switch(var1) {
+ case 88:
+ System.out.println("1");
+ break;
+ case 656:
+ System.out.println("2");
+ break;
+ case 65201:
+ case 65489:
+ System.out.println("3");
+ }
+
+ }
+
+ public void testAssignmentType(List var1) {
+ Object var2 = var1;
+ if(var1 != null) {
+ ((List)(var2 = new ArrayList(var1))).add("23");
+ }
+
+ System.out.println(((List)var2).size());
+ }
+}
diff --git a/plugins/java-decompiler/engine/testData/results/TestClassVar.dec b/plugins/java-decompiler/engine/testData/results/TestClassVar.dec
new file mode 100644
index 000000000000..4cfd27f7854d
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/results/TestClassVar.dec
@@ -0,0 +1,40 @@
+package pkg;
+
+public class TestClassVar {
+ private boolean field_boolean = Math.random() > 0.0D;
+ public int field_int = 0;
+
+ public void testFieldSSAU() {
+ for(int var1 = 0; var1 < 10; ++var1) {
+ try {
+ System.out.println();
+ } finally {
+ if(this.field_boolean) {
+ System.out.println();
+ }
+
+ }
+ }
+
+ }
+
+ public Long testFieldSSAU1() {
+ return new Long((long)(this.field_int++));
+ }
+
+ public void testComplexPropagation() {
+ int var1 = 0;
+
+ while(var1 < 10) {
+ int var2;
+ for(var2 = var1; var1 < 10 && var1 == 0; ++var1) {
+ ;
+ }
+
+ if(var2 != var1) {
+ System.out.println();
+ }
+ }
+
+ }
+}
diff --git a/plugins/java-decompiler/engine/testData/results/TestCodeConstructs.dec b/plugins/java-decompiler/engine/testData/results/TestCodeConstructs.dec
new file mode 100644
index 000000000000..eb9de8daa07a
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/results/TestCodeConstructs.dec
@@ -0,0 +1,13 @@
+package pkg;
+
+class TestCodeConstructs {
+ private int count = 0;
+
+ void expressions() {
+ (new String()).hashCode();
+ }
+
+ Integer fieldIncrement() {
+ return new Integer(this.count++);
+ }
+}
diff --git a/plugins/java-decompiler/engine/testData/results/TestConstants.dec b/plugins/java-decompiler/engine/testData/results/TestConstants.dec
new file mode 100644
index 000000000000..216da8e98468
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/results/TestConstants.dec
@@ -0,0 +1,73 @@
+package pkg;
+
+import java.util.Date;
+
+public class TestConstants {
+ static final boolean T = true;
+ static final boolean F = false;
+ static final char C0 = '\n';
+ static final char C1 = 'a';
+ static final char C2 = 'È€';
+ static final byte BMin = -128;
+ static final byte BMax = 127;
+ static final short SMin = -32768;
+ static final short SMax = 32767;
+ static final int IMin = -2147483648;
+ static final int IMax = 2147483647;
+ static final long LMin = -9223372036854775808L;
+ static final long LMax = 9223372036854775807L;
+ static final float FNan = 0.0F / 0.0;
+ static final float FNeg = -1.0F / 0.0;
+ static final float FPos = 1.0F / 0.0;
+ static final float FMin = 1.4E-45F;
+ static final float FMax = 3.4028235E38F;
+ static final double DNan = 0.0D / 0.0;
+ static final double DNeg = -1.0D / 0.0;
+ static final double DPos = 1.0D / 0.0;
+ static final double DMin = 4.9E-324D;
+ static final double DMax = 1.7976931348623157E308D;
+
+ @TestConstants.A(byte.class)
+ void m1() {
+ }
+
+ @TestConstants.A(char.class)
+ void m2() {
+ }
+
+ @TestConstants.A(double.class)
+ void m3() {
+ }
+
+ @TestConstants.A(float.class)
+ void m4() {
+ }
+
+ @TestConstants.A(int.class)
+ void m5() {
+ }
+
+ @TestConstants.A(long.class)
+ void m6() {
+ }
+
+ @TestConstants.A(short.class)
+ void m7() {
+ }
+
+ @TestConstants.A(boolean.class)
+ void m8() {
+ }
+
+ @TestConstants.A(void.class)
+ void m9() {
+ }
+
+ @TestConstants.A(Date.class)
+ void m10() {
+ }
+
+ @interface A {
+ Class<?> value();
+ }
+}
diff --git a/plugins/java-decompiler/engine/testData/results/TestDebugSymbols.dec b/plugins/java-decompiler/engine/testData/results/TestDebugSymbols.dec
new file mode 100644
index 000000000000..42ae7a8c5513
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/results/TestDebugSymbols.dec
@@ -0,0 +1,11 @@
+package pkg;
+
+class TestDebugSymbols {
+ private int m() {
+ String text = "text";
+ long prolonged = 42L;
+ float decimated = (float)prolonged / 10.0F;
+ double doubled = (double)(2.0F * decimated);
+ return (text + ":" + prolonged + ":" + decimated + ":" + doubled).length();
+ }
+}
diff --git a/plugins/java-decompiler/engine/testData/results/TestDeprecations.dec b/plugins/java-decompiler/engine/testData/results/TestDeprecations.dec
new file mode 100644
index 000000000000..237ac9c72348
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/results/TestDeprecations.dec
@@ -0,0 +1,27 @@
+package pkg;
+
+public class TestDeprecations {
+ /** @deprecated */
+ public int byComment;
+ /** @deprecated */
+ @Deprecated
+ public int byAnno;
+
+ /** @deprecated */
+ public void byComment() {
+ }
+
+ /** @deprecated */
+ @Deprecated
+ public void byAnno() {
+ }
+
+ /** @deprecated */
+ @Deprecated
+ public static class ByAnno {
+ }
+
+ /** @deprecated */
+ public static class ByComment {
+ }
+}
diff --git a/plugins/java-decompiler/engine/testData/results/TestEnum.dec b/plugins/java-decompiler/engine/testData/results/TestEnum.dec
new file mode 100644
index 000000000000..b32a3d9a4f66
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/results/TestEnum.dec
@@ -0,0 +1,27 @@
+package pkg;
+
+public enum TestEnum {
+ E1,
+ E2 {
+ public void m() {
+ }
+ },
+ E3("-"),
+ E4("+") {
+ public void m() {
+ }
+ };
+
+ private String s;
+
+ public void m() {
+ }
+
+ private TestEnum() {
+ this((String)"?");
+ }
+
+ private TestEnum(@Deprecated String var3) {
+ this.s = var3;
+ }
+}
diff --git a/plugins/java-decompiler/engine/testData/results/TestExtendsList.dec b/plugins/java-decompiler/engine/testData/results/TestExtendsList.dec
new file mode 100644
index 000000000000..b4aacf6e126a
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/results/TestExtendsList.dec
@@ -0,0 +1,11 @@
+package pkg;
+
+public class TestExtendsList {
+ static <T extends Comparable<? super T>> T m1(T var0) {
+ return null;
+ }
+
+ static <T extends Object & Comparable<? super T>> T m2(T var0) {
+ return null;
+ }
+}
diff --git a/plugins/java-decompiler/engine/testData/results/TestMethodParameters.dec b/plugins/java-decompiler/engine/testData/results/TestMethodParameters.dec
new file mode 100644
index 000000000000..e4c4724d7a7c
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/results/TestMethodParameters.dec
@@ -0,0 +1,42 @@
+package pkg;
+
+public class TestMethodParameters {
+ TestMethodParameters(@Deprecated int var1) {
+ }
+
+ void m1(@Deprecated int var1) {
+ }
+
+ static void m2(@Deprecated int var0) {
+ }
+
+ void local() {
+ class Local {
+ Local(@Deprecated int var2) {
+ }
+
+ void m(@Deprecated int var1) {
+ }
+ }
+
+ }
+
+ static class C2 {
+ C2(@Deprecated int var1) {
+ }
+
+ void m1(@Deprecated int var1) {
+ }
+
+ static void m2(@Deprecated int var0) {
+ }
+ }
+
+ class C1 {
+ C1(@Deprecated int var2) {
+ }
+
+ void m(@Deprecated int var1) {
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/testData/src/pkg/TestClassCast.java b/plugins/java-decompiler/engine/testData/src/pkg/TestClassCast.java
new file mode 100644
index 000000000000..a831e54c98c1
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/src/pkg/TestClassCast.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pkg;
+
+import java.util.*;
+
+public class TestClassCast {
+ public void test(List list) {
+ List a = list;
+ if (a != null) {
+ (a = new ArrayList(a)).add("23");
+ }
+ System.out.println(a.size());
+ }
+} \ No newline at end of file
diff --git a/plugins/java-decompiler/engine/testData/src/pkg/TestClassFields.java b/plugins/java-decompiler/engine/testData/src/pkg/TestClassFields.java
new file mode 100644
index 000000000000..a1f2facaf41c
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/src/pkg/TestClassFields.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pkg;
+
+public class TestClassFields {
+
+ private static int[] sizes;
+ private static String[] names;
+
+ static {
+
+ names = new String[]{"name1", "name2"};
+ sizes = new int[names.length];
+ }
+}
diff --git a/plugins/java-decompiler/engine/testData/src/pkg/TestClassLambda.java b/plugins/java-decompiler/engine/testData/src/pkg/TestClassLambda.java
new file mode 100644
index 000000000000..589766e36506
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/src/pkg/TestClassLambda.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pkg;
+
+import java.util.*;
+import java.util.function.IntBinaryOperator;
+import java.util.function.Supplier;
+
+public class TestClassLambda {
+
+ public int field = 0;
+
+ public void testLambda() {
+ List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
+ int b = (int)Math.random();
+
+ list.forEach(n -> {
+ int a = 2 * n;
+ System.out.println(a + b + field);
+ });
+ }
+
+ public void testLambda1() {
+ int a = (int)Math.random();
+ Runnable r1 = () -> { System.out.println("hello1" + a); };
+ Runnable r2 = () -> { System.out.println("hello2" + a); };
+ }
+
+ public void testLambda2() {
+ reduce((left, right) -> Math.max(left, right));
+ }
+
+ public void testLambda3() { // IDEA-127301
+ reduce(Math::max);
+ }
+
+ public void testLambda4() {
+ reduce(TestClassLambda::localMax);
+ }
+
+ public void testLambda5() {
+ String x = "abcd";
+ function(x::toString);
+ }
+
+ public void testLambda6() {
+ List<String> list = new ArrayList<String>();
+ int bottom = list.size() * 2;
+ int top = list.size() * 5;
+ list.removeIf(s -> (bottom >= s.length() && s.length() <= top));
+ }
+
+ public static OptionalInt reduce(IntBinaryOperator op) {
+ return null;
+ }
+
+ public static String function(Supplier<String> supplier) {
+ return supplier.get();
+ }
+
+ public static int localMax(int first, int second) {
+ return 0;
+ }
+}
diff --git a/plugins/java-decompiler/engine/testData/src/pkg/TestClassLoop.java b/plugins/java-decompiler/engine/testData/src/pkg/TestClassLoop.java
new file mode 100644
index 000000000000..0ecab7de08c3
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/src/pkg/TestClassLoop.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pkg;
+
+public class TestClassLoop {
+
+ public static void testSimpleInfinite() {
+
+ while (true) {
+ System.out.println();
+ }
+ }
+
+ public static void testFinally() {
+
+ boolean a = (Math.random() > 0);
+
+ while (true) {
+ try {
+ if (!a) {
+ return;
+ }
+ }
+ finally {
+ System.out.println("1");
+ }
+ }
+ }
+
+ public static void testFinallyContinue() {
+
+ boolean a = (Math.random() > 0);
+
+ for (; ; ) {
+ try {
+ System.out.println("1");
+ }
+ finally {
+ if (a) {
+ System.out.println("3");
+ continue;
+ }
+ }
+
+ System.out.println("4");
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/testData/src/pkg/TestClassNestedInitializer.java b/plugins/java-decompiler/engine/testData/src/pkg/TestClassNestedInitializer.java
new file mode 100644
index 000000000000..ee8927aee89d
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/src/pkg/TestClassNestedInitializer.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pkg;
+
+public class TestClassNestedInitializer {
+ public String secret;
+
+ public void test() {
+ TestClassNestedInitializer obj = new TestClassNestedInitializer() { {secret = "one";} };
+ System.out.println(obj.secret);
+ }
+} \ No newline at end of file
diff --git a/plugins/java-decompiler/engine/testData/src/pkg/TestClassSwitch.java b/plugins/java-decompiler/engine/testData/src/pkg/TestClassSwitch.java
new file mode 100644
index 000000000000..0c95d2530e3b
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/src/pkg/TestClassSwitch.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pkg;
+
+public class TestClassSwitch {
+
+ public void testCaseOrder(int a) {
+
+ switch (a) {
+ case 13:
+ System.out.println(13);
+ return;
+ case 5:
+ System.out.println(5);
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/testData/src/pkg/TestClassTypes.java b/plugins/java-decompiler/engine/testData/src/pkg/TestClassTypes.java
new file mode 100644
index 000000000000..a745aebef600
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/src/pkg/TestClassTypes.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pkg;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class TestClassTypes {
+
+ public void testBoolean() {
+
+ byte var7 = 0;
+ long time = System.currentTimeMillis();
+
+ if (time % 2 > 0) {
+ var7 = 1;
+ }
+ else if (time % 3 > 0) {
+ var7 = 2;
+ }
+
+ if (var7 == 1) {
+ System.out.println();
+ }
+ }
+
+ public boolean testBit(int var0) {
+ return (var0 & 1) == 1;
+ }
+
+ public void testSwitchConsts(int a) {
+
+ switch (a) {
+ case 88:
+ System.out.println("1");
+ break;
+ case 656:
+ System.out.println("2");
+ break;
+ case 65201:
+ case 65489:
+ System.out.println("3");
+ }
+ }
+
+ public void testAssignmentType(List list) {
+
+ List a = list;
+
+ if (a != null) {
+ (a = new ArrayList(a)).add("23");
+ }
+
+ System.out.println(a.size());
+ }
+}
diff --git a/plugins/java-decompiler/engine/testData/src/pkg/TestClassVar.java b/plugins/java-decompiler/engine/testData/src/pkg/TestClassVar.java
new file mode 100644
index 000000000000..09dcded92d66
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/src/pkg/TestClassVar.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pkg;
+
+
+public class TestClassVar {
+
+ private boolean field_boolean = (Math.random() > 0);
+ public int field_int = 0;
+
+ public void testFieldSSAU() {
+
+ for (int i = 0; i < 10; i++) {
+
+ try {
+ System.out.println();
+ }
+ finally {
+ if (field_boolean) {
+ System.out.println();
+ }
+ }
+ }
+ }
+
+ public Long testFieldSSAU1() { // IDEA-127466
+ return new Long(field_int++);
+ }
+
+ public void testComplexPropagation() {
+
+ int a = 0;
+
+ while (a < 10) {
+
+ int b = a;
+
+ for (; a < 10 && a == 0; a++) {
+ }
+
+ if (b != a) {
+ System.out.println();
+ }
+ }
+ }
+}
diff --git a/plugins/java-decompiler/engine/testData/src/pkg/TestCodeConstructs.java b/plugins/java-decompiler/engine/testData/src/pkg/TestCodeConstructs.java
new file mode 100644
index 000000000000..fd903e4add33
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/src/pkg/TestCodeConstructs.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pkg;
+
+class TestCodeConstructs {
+ void expressions() {
+ new String().hashCode();
+ }
+
+ private int count = 0;
+ Integer fieldIncrement() {
+ return new Integer(count++);
+ }
+} \ No newline at end of file
diff --git a/plugins/java-decompiler/testData/Constants.java b/plugins/java-decompiler/engine/testData/src/pkg/TestConstants.java
index b2b59a5728c6..09b5419fc3e4 100644
--- a/plugins/java-decompiler/testData/Constants.java
+++ b/plugins/java-decompiler/engine/testData/src/pkg/TestConstants.java
@@ -1,4 +1,21 @@
-public class Constants {
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pkg;
+
+public class TestConstants {
static final boolean T = true;
static final boolean F = false;
diff --git a/plugins/java-decompiler/engine/testData/src/pkg/TestDebugSymbols.java b/plugins/java-decompiler/engine/testData/src/pkg/TestDebugSymbols.java
new file mode 100644
index 000000000000..167351031dc8
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/src/pkg/TestDebugSymbols.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pkg;
+
+// need to be compiled with debug info
+class TestDebugSymbols {
+ private int m() {
+ String text = "text";
+ long prolonged = 42L;
+ float decimated = prolonged / 10.0f;
+ double doubled = 2 * decimated;
+ return (text + ":" + prolonged + ":" + decimated + ":" + doubled).length();
+ }
+}
diff --git a/plugins/java-decompiler/engine/testData/src/pkg/TestDeprecations.java b/plugins/java-decompiler/engine/testData/src/pkg/TestDeprecations.java
new file mode 100644
index 000000000000..18ba0b5f10a6
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/src/pkg/TestDeprecations.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pkg;
+
+public class TestDeprecations {
+ /** @deprecated */
+ public int byComment;
+
+ @Deprecated
+ public int byAnno;
+
+ /** @deprecated */
+ public void byComment() { }
+
+ @Deprecated
+ public void byAnno() { }
+
+ /** @deprecated */
+ public static class ByComment { }
+
+ @Deprecated
+ public static class ByAnno { }
+} \ No newline at end of file
diff --git a/plugins/java-decompiler/engine/testData/src/pkg/TestEnum.java b/plugins/java-decompiler/engine/testData/src/pkg/TestEnum.java
new file mode 100644
index 000000000000..43fab48355f2
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/src/pkg/TestEnum.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pkg;
+
+public enum TestEnum {
+ E1,
+ E2() {
+ @Override
+ public void m() { }
+ },
+ E3("-"),
+ E4("+") {
+ @Override
+ public void m() { }
+ };
+
+ public void m() { }
+
+ private String s;
+
+ private TestEnum() { this("?"); }
+ private TestEnum(@Deprecated String s) { this.s = s; }
+}
diff --git a/plugins/java-decompiler/engine/testData/src/pkg/TestExtendsList.java b/plugins/java-decompiler/engine/testData/src/pkg/TestExtendsList.java
new file mode 100644
index 000000000000..812f83689ba6
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/src/pkg/TestExtendsList.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pkg;
+
+public class TestExtendsList {
+ static <T extends Comparable<? super T>> T m1(T t) {
+ return null;
+ }
+
+ static <T extends Object & Comparable<? super T>> T m2(T t) {
+ return null;
+ }
+} \ No newline at end of file
diff --git a/plugins/java-decompiler/engine/testData/src/pkg/TestMethodParameters.java b/plugins/java-decompiler/engine/testData/src/pkg/TestMethodParameters.java
new file mode 100644
index 000000000000..b9739e9cfda4
--- /dev/null
+++ b/plugins/java-decompiler/engine/testData/src/pkg/TestMethodParameters.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pkg;
+
+public class TestMethodParameters {
+ TestMethodParameters(@Deprecated int p01) { }
+ void m1(@Deprecated int p02) { }
+ static void m2(@Deprecated int p03) { }
+
+ class C1 {
+ C1(@Deprecated int p11) { }
+ void m(@Deprecated int p12) { }
+ }
+
+ static class C2 {
+ C2(@Deprecated int p21) { }
+ void m1(@Deprecated int p22) { }
+ static void m2(@Deprecated int p23) { }
+ }
+
+ void local() {
+ class Local {
+ Local(@Deprecated int p31) { }
+ void m(@Deprecated int p32) { }
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/java-decompiler/java-decompiler.iml b/plugins/java-decompiler/java-decompiler.iml
index cf37a2991f2f..b25775f3666b 100644
--- a/plugins/java-decompiler/java-decompiler.iml
+++ b/plugins/java-decompiler/java-decompiler.iml
@@ -5,6 +5,9 @@
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
+ <sourceFolder url="file://$MODULE_DIR$/engine/src" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/engine/test" isTestSource="true" />
+ <excludeFolder url="file://$MODULE_DIR$/engine/out" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
@@ -13,15 +16,6 @@
<orderEntry type="module" module-name="java-psi-impl" />
<orderEntry type="module" module-name="util" />
<orderEntry type="module" module-name="testFramework-java" scope="TEST" />
- <orderEntry type="module-library">
- <library>
- <CLASSES>
- <root url="jar://$MODULE_DIR$/lib/fernflower.jar!/" />
- </CLASSES>
- <JAVADOC />
- <SOURCES />
- </library>
- </orderEntry>
<orderEntry type="library" name="asm5" level="project" />
</component>
</module>
diff --git a/plugins/java-decompiler/lib/fernflower.jar b/plugins/java-decompiler/lib/fernflower.jar
deleted file mode 100644
index d8589afbb097..000000000000
--- a/plugins/java-decompiler/lib/fernflower.jar
+++ /dev/null
Binary files differ
diff --git a/plugins/java-decompiler/src/META-INF/plugin.xml b/plugins/java-decompiler/src/META-INF/plugin.xml
index 2eacf248c370..3b8c53a78cae 100644
--- a/plugins/java-decompiler/src/META-INF/plugin.xml
+++ b/plugins/java-decompiler/src/META-INF/plugin.xml
@@ -14,6 +14,8 @@
<module value="com.intellij.modules.java"/>
<extensions defaultExtensionNs="com.intellij">
+ <errorHandler implementation="com.intellij.diagnostic.ITNReporter"/>
+
<psi.classFileDecompiler implementation="org.jetbrains.java.decompiler.IdeaDecompiler" order="last"/>
</extensions>
diff --git a/plugins/java-decompiler/src/org/jetbrains/java/decompiler/IdeaDecompiler.java b/plugins/java-decompiler/src/org/jetbrains/java/decompiler/IdeaDecompiler.java
index f57ea6a4087b..616403b9c93f 100644
--- a/plugins/java-decompiler/src/org/jetbrains/java/decompiler/IdeaDecompiler.java
+++ b/plugins/java-decompiler/src/org/jetbrains/java/decompiler/IdeaDecompiler.java
@@ -30,19 +30,18 @@ import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.psi.compiled.ClassFileDecompilers;
import com.intellij.psi.impl.compiled.ClsFileImpl;
import com.intellij.util.containers.ContainerUtil;
-import de.fernflower.main.decompiler.IdeDecompiler;
-import de.fernflower.main.extern.IBytecodeProvider;
-import de.fernflower.main.extern.IDecompilatSaver;
-import de.fernflower.main.extern.IFernflowerLogger;
-import de.fernflower.main.extern.IFernflowerPreferences;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.java.decompiler.main.decompiler.BaseDecompiler;
+import org.jetbrains.java.decompiler.main.extern.IBytecodeProvider;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
+import org.jetbrains.java.decompiler.main.extern.IResultSaver;
import org.jetbrains.org.objectweb.asm.ClassReader;
import org.jetbrains.org.objectweb.asm.ClassVisitor;
import org.jetbrains.org.objectweb.asm.Opcodes;
import java.io.File;
import java.io.IOException;
-import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.jar.Manifest;
@@ -51,10 +50,10 @@ public class IdeaDecompiler extends ClassFileDecompilers.Light {
private static final Logger LOG = Logger.getInstance(IdeaDecompiler.class);
private static final String BANNER =
- "//\n" +
- "// Source code recreated from a .class file by IntelliJ IDEA\n" +
- "// (powered by Fernflower decompiler)\n" +
- "//\n\n";
+ "//\n" +
+ "// Source code recreated from a .class file by IntelliJ IDEA\n" +
+ "// (powered by Fernflower decompiler)\n" +
+ "//\n\n";
private final IFernflowerLogger myLogger = new IdeaLogger();
private final HashMap<String, Object> myOptions = new HashMap<String, Object>();
@@ -94,10 +93,10 @@ public class IdeaDecompiler extends ClassFileDecompilers.Light {
files.put(child.getPath(), child);
}
}
- MyByteCodeProvider provider = new MyByteCodeProvider(files);
+ MyBytecodeProvider provider = new MyBytecodeProvider(files);
MyResultSaver saver = new MyResultSaver();
- IdeDecompiler decompiler = new IdeDecompiler(provider, saver, myLogger, myOptions);
+ BaseDecompiler decompiler = new BaseDecompiler(provider, saver, myOptions, myLogger);
for (String path : files.keySet()) {
decompiler.addSpace(new File(path), true);
}
@@ -149,20 +148,20 @@ public class IdeaDecompiler extends ClassFileDecompilers.Light {
return true;
}
- private static class MyByteCodeProvider implements IBytecodeProvider {
+ private static class MyBytecodeProvider implements IBytecodeProvider {
private final Map<String, VirtualFile> myFiles;
- private MyByteCodeProvider(@NotNull Map<String, VirtualFile> files) {
+ private MyBytecodeProvider(@NotNull Map<String, VirtualFile> files) {
myFiles = files;
}
@Override
- public InputStream getBytecodeStream(String externalPath, String internalPath) {
+ public byte[] getBytecode(String externalPath, String internalPath) {
try {
String path = FileUtil.toSystemIndependentName(externalPath);
VirtualFile file = myFiles.get(path);
assert file != null : path;
- return file.getInputStream();
+ return file.contentsToByteArray();
}
catch (IOException e) {
throw new RuntimeException(e);
@@ -170,7 +169,7 @@ public class IdeaDecompiler extends ClassFileDecompilers.Light {
}
}
- private static class MyResultSaver implements IDecompilatSaver {
+ private static class MyResultSaver implements IResultSaver {
private String myResult = "";
@Override
@@ -181,25 +180,22 @@ public class IdeaDecompiler extends ClassFileDecompilers.Light {
}
@Override
- public void copyFile(String source, String destPath, String destFileName) { }
-
- @Override
public void saveFolder(String path) { }
@Override
- public void saveFile(String path, String filename, String content) { }
+ public void copyFile(String source, String path, String entryName) { }
@Override
public void createArchive(String path, String archiveName, Manifest manifest) { }
@Override
- public void saveClassEntry(String path, String archiveName, String qualifiedName, String entryName, String content) { }
+ public void saveDirEntry(String path, String archiveName, String entryName) { }
@Override
- public void saveEntry(String path, String archiveName, String entryName, String content) { }
+ public void copyEntry(String source, String path, String archiveName, String entry) { }
@Override
- public void copyEntry(String source, String destPath, String archiveName, String entry) { }
+ public void saveClassEntry(String path, String archiveName, String qualifiedName, String entryName, String content) { }
@Override
public void closeArchive(String path, String archiveName) { }
diff --git a/plugins/java-decompiler/src/org/jetbrains/java/decompiler/IdeaLogger.java b/plugins/java-decompiler/src/org/jetbrains/java/decompiler/IdeaLogger.java
index 904af9bf31b3..46a280cd315e 100644
--- a/plugins/java-decompiler/src/org/jetbrains/java/decompiler/IdeaLogger.java
+++ b/plugins/java-decompiler/src/org/jetbrains/java/decompiler/IdeaLogger.java
@@ -16,9 +16,9 @@
package org.jetbrains.java.decompiler;
import com.intellij.openapi.diagnostic.Logger;
-import de.fernflower.main.extern.IFernflowerLogger;
+import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
-public class IdeaLogger implements IFernflowerLogger {
+public class IdeaLogger extends IFernflowerLogger {
private final static Logger LOG = Logger.getInstance(IdeaDecompiler.class);
public static class InternalException extends RuntimeException {
@@ -28,10 +28,10 @@ public class IdeaLogger implements IFernflowerLogger {
}
@Override
- public void writeMessage(String message, int severity) {
- if (severity >= ERROR) LOG.error(message);
- else if (severity == WARNING) LOG.warn(message);
- else if (severity == INFO) LOG.info(message);
+ public void writeMessage(String message, Severity severity) {
+ if (severity == Severity.ERROR) LOG.error(message);
+ else if (severity == Severity.WARN) LOG.warn(message);
+ else if (severity == Severity.INFO) LOG.info(message);
else LOG.debug(message);
}
@@ -62,20 +62,12 @@ public class IdeaLogger implements IFernflowerLogger {
}
@Override
- public void startMethod(String method) {
- LOG.debug("processing method " + method);
+ public void startMethod(String methodName) {
+ LOG.debug("processing method " + methodName);
}
@Override
public void endMethod() {
LOG.debug("... method processed");
}
-
- @Override
- public int getSeverity() {
- return WARNING;
- }
-
- @Override
- public void setSeverity(int ignore) { }
}
diff --git a/plugins/java-decompiler/test/org/jetbrains/java/decompiler/IdeaDecompilerTest.java b/plugins/java-decompiler/test/org/jetbrains/java/decompiler/IdeaDecompilerTest.java
index 060b269789e3..941f677d618b 100644
--- a/plugins/java-decompiler/test/org/jetbrains/java/decompiler/IdeaDecompilerTest.java
+++ b/plugins/java-decompiler/test/org/jetbrains/java/decompiler/IdeaDecompilerTest.java
@@ -15,32 +15,32 @@
*/
package org.jetbrains.java.decompiler;
-import com.intellij.openapi.application.PathManager;
-import com.intellij.openapi.application.PluginPathManager;
import com.intellij.openapi.fileTypes.StdFileTypes;
-import com.intellij.openapi.util.io.FileUtil;
-import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.StandardFileSystems;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileVisitor;
-import com.intellij.psi.*;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
import com.intellij.psi.impl.compiled.ClsFileImpl;
import com.intellij.testFramework.PlatformTestUtil;
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.io.File;
-import java.io.IOException;
public class IdeaDecompilerTest extends LightCodeInsightFixtureTestCase {
+ private static final String BANNER =
+ "//\n" +
+ "// Source code recreated from a .class file by IntelliJ IDEA\n" +
+ "// (powered by Fernflower decompiler)\n" +
+ "//\n\n";
+
public void testSimple() {
String path = PlatformTestUtil.getRtJarPath() + "!/java/lang/String.class";
VirtualFile file = StandardFileSystems.jar().findFileByPath(path);
assertNotNull(path, file);
String decompiled = new IdeaDecompiler().getText(file).toString();
+ assertTrue(decompiled.startsWith(BANNER + "package java.lang;\n"));
assertTrue(decompiled, decompiled.contains("public final class String"));
assertTrue(decompiled, decompiled.contains("@deprecated"));
assertTrue(decompiled, decompiled.contains("private static class CaseInsensitiveComparator"));
@@ -48,110 +48,29 @@ public class IdeaDecompilerTest extends LightCodeInsightFixtureTestCase {
assertFalse(decompiled, decompiled.contains("synthetic"));
}
- public void testEnum() { doTestDecompiler(); }
- public void testDeprecations() { doTestDecompiler(); }
- public void testExtendsList() { doTestDecompiler(); }
- public void testParameters() { doTestDecompiler(); }
- public void testConstants() { doTestDecompiler(); }
- public void testAnonymous() { doTestDecompiler(); }
- public void testCodeConstructs() { doTestDecompiler(); }
-
- private void doTestDecompiler() {
- String name = PluginPathManager.getPluginHomePath("java-decompiler") + "/testData/" + getName().substring(4);
- String path = name + ".class";
- VirtualFile file = StandardFileSystems.local().findFileByPath(path);
- assertNotNull(path, file);
- file.getParent().getChildren();
- file.getParent().refresh(false, true);
-
- try {
- CharSequence text = new IdeaDecompiler().getText(file);
- assertNotNull(text);
- String expected = FileUtil.loadFile(new File(name + ".txt"), "UTF-8");
- assertEquals(StringUtil.convertLineSeparators(expected), text.toString());
- }
- catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- public void testStubCompatibilityRt() {
- String path = PlatformTestUtil.getRtJarPath() + "!/";
+ public void testStubCompatibility() {
+ String path = PlatformTestUtil.getRtJarPath() + "!/java";
VirtualFile dir = StandardFileSystems.jar().findFileByPath(path);
assertNotNull(path, dir);
doTestStubCompatibility(dir);
}
- public void testStubCompatibilityIdea() {
- String path = PathManager.getHomePath() + "/out/production";
- if (!new File(path).exists()) path = PathManager.getHomePath() + "/out/classes/production";
- VirtualFile dir = StandardFileSystems.local().refreshAndFindFileByPath(path);
- assertNotNull(path, dir);
- doTestStubCompatibility(dir);
- }
-
private void doTestStubCompatibility(VirtualFile root) {
- doTestStubCompatibility(root, null);
- }
-
- private void doTestStubCompatibility(VirtualFile root, @Nullable final String textPath) {
- final int pathStart = root.getPath().length();
- final boolean compare = textPath != null && new File(textPath).exists();
-
VfsUtilCore.visitChildrenRecursively(root, new VirtualFileVisitor() {
@Override
public boolean visitFile(@NotNull VirtualFile file) {
- if (!file.isDirectory() && file.getFileType() == StdFileTypes.CLASS && !file.getName().contains("$")) {
+ if (file.isDirectory()) {
+ System.out.println(file.getPath());
+ }
+ else if (file.getFileType() == StdFileTypes.CLASS && !file.getName().contains("$")) {
PsiFile clsFile = getPsiManager().findFile(file);
assertNotNull(file.getPath(), clsFile);
-
- PsiElement mirror = ((ClsFileImpl)clsFile).getMirror().copy();
- if (textPath != null) {
- collapseCodeBlocks(mirror);
- }
+ PsiElement mirror = ((ClsFileImpl)clsFile).getMirror();
String decompiled = mirror.getText();
assertTrue(file.getPath(), decompiled.contains(file.getNameWithoutExtension()));
-
- if (textPath != null) {
- try {
- File txtFile = new File(textPath, file.getPath().substring(pathStart));
- if (!compare) {
- FileUtil.writeToFile(txtFile, decompiled.getBytes("UTF-8"));
- }
- else {
- String expected = FileUtil.loadFile(txtFile, "UTF-8");
- assertEquals(file.getPath(), expected, decompiled);
- }
- }
- catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
}
return true;
}
});
}
-
- private static void collapseCodeBlocks(PsiElement original) {
- final PsiElementFactory factory = PsiElementFactory.SERVICE.getInstance(original.getProject());
- original.accept(new JavaRecursiveElementWalkingVisitor() {
- @Override
- public void visitMethod(PsiMethod method) {
- PsiCodeBlock body = method.getBody();
- if (body != null) {
- body.replace(factory.createCodeBlockFromText("{ /* collapsed */}", null));
- }
- }
-
- @Override
- public void visitClass(PsiClass aClass) {
- for (PsiClassInitializer initializer : aClass.getInitializers()) {
- PsiCodeBlock body = initializer.getBody();
- body.replace(factory.createCodeBlockFromText("{ /* collapsed */}", null));
- }
- super.visitClass(aClass);
- }
- });
- }
}
diff --git a/plugins/java-decompiler/testData/Anonymous$1.class b/plugins/java-decompiler/testData/Anonymous$1.class
deleted file mode 100644
index 338c04840be2..000000000000
--- a/plugins/java-decompiler/testData/Anonymous$1.class
+++ /dev/null
Binary files differ
diff --git a/plugins/java-decompiler/testData/Anonymous.class b/plugins/java-decompiler/testData/Anonymous.class
deleted file mode 100644
index df67a5858753..000000000000
--- a/plugins/java-decompiler/testData/Anonymous.class
+++ /dev/null
Binary files differ
diff --git a/plugins/java-decompiler/testData/Anonymous.java b/plugins/java-decompiler/testData/Anonymous.java
deleted file mode 100644
index 6f4a89389a27..000000000000
--- a/plugins/java-decompiler/testData/Anonymous.java
+++ /dev/null
@@ -1,13 +0,0 @@
-public class Anonymous {
- private int count = 0;
-
- public Object produce() {
- final int id = count++;
- return new Object() {
- @Override
- public String toString() {
- return "anonymous_" + id;
- }
- };
- }
-} \ No newline at end of file
diff --git a/plugins/java-decompiler/testData/Anonymous.txt b/plugins/java-decompiler/testData/Anonymous.txt
deleted file mode 100644
index a7cea92713b7..000000000000
--- a/plugins/java-decompiler/testData/Anonymous.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-//
-// Source code recreated from a .class file by IntelliJ IDEA
-// (powered by Fernflower decompiler)
-//
-
-
-public class Anonymous {
-
- private int count = 0;
-
-
- public Anonymous() {
- }
-
- public Object produce() {
- ++this.count;
- final int var1 = this.count;
- return new Object() {
- public String toString() {
- return "anonymous_" + var1;
- }
- };
- }
-}
diff --git a/plugins/java-decompiler/testData/CodeConstructs.class b/plugins/java-decompiler/testData/CodeConstructs.class
deleted file mode 100644
index bcac6685eb01..000000000000
--- a/plugins/java-decompiler/testData/CodeConstructs.class
+++ /dev/null
Binary files differ
diff --git a/plugins/java-decompiler/testData/CodeConstructs.java b/plugins/java-decompiler/testData/CodeConstructs.java
deleted file mode 100644
index d0c2e35311c8..000000000000
--- a/plugins/java-decompiler/testData/CodeConstructs.java
+++ /dev/null
@@ -1,5 +0,0 @@
-class CodeConstructs {
- void expressions() {
- new String().hashCode();
- }
-} \ No newline at end of file
diff --git a/plugins/java-decompiler/testData/CodeConstructs.txt b/plugins/java-decompiler/testData/CodeConstructs.txt
deleted file mode 100644
index 59bc71849dd6..000000000000
--- a/plugins/java-decompiler/testData/CodeConstructs.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-//
-// Source code recreated from a .class file by IntelliJ IDEA
-// (powered by Fernflower decompiler)
-//
-
-
-class CodeConstructs {
-
- CodeConstructs() {
- }
-
- void expressions() {
- (new String()).hashCode();
- }
-}
diff --git a/plugins/java-decompiler/testData/Constants$A.class b/plugins/java-decompiler/testData/Constants$A.class
deleted file mode 100644
index d4d8df39443a..000000000000
--- a/plugins/java-decompiler/testData/Constants$A.class
+++ /dev/null
Binary files differ
diff --git a/plugins/java-decompiler/testData/Constants.class b/plugins/java-decompiler/testData/Constants.class
deleted file mode 100644
index a8ad40e7b158..000000000000
--- a/plugins/java-decompiler/testData/Constants.class
+++ /dev/null
Binary files differ
diff --git a/plugins/java-decompiler/testData/Constants.txt b/plugins/java-decompiler/testData/Constants.txt
deleted file mode 100644
index 9665582396c0..000000000000
--- a/plugins/java-decompiler/testData/Constants.txt
+++ /dev/null
@@ -1,82 +0,0 @@
-//
-// Source code recreated from a .class file by IntelliJ IDEA
-// (powered by Fernflower decompiler)
-//
-
-import java.util.Date;
-
-public class Constants {
-
- static final boolean T = true;
- static final boolean F = false;
- static final char C0 = '\n';
- static final char C1 = 'a';
- static final char C2 = 'È€';
- static final byte BMin = -128;
- static final byte BMax = 127;
- static final short SMin = -32768;
- static final short SMax = 32767;
- static final int IMin = -2147483648;
- static final int IMax = 2147483647;
- static final long LMin = -9223372036854775808L;
- static final long LMax = 9223372036854775807L;
- static final float FNan = 0.0F / 0.0;
- static final float FNeg = -1.0F / 0.0;
- static final float FPos = 1.0F / 0.0;
- static final float FMin = 1.4E-45F;
- static final float FMax = 3.4028235E38F;
- static final double DNan = 0.0D / 0.0;
- static final double DNeg = -1.0D / 0.0;
- static final double DPos = 1.0D / 0.0;
- static final double DMin = 4.9E-324D;
- static final double DMax = 1.7976931348623157E308D;
-
-
- public Constants() {
- }
-
- @Constants(byte.class)
- void m1() {
- }
-
- @Constants(char.class)
- void m2() {
- }
-
- @Constants(double.class)
- void m3() {
- }
-
- @Constants(float.class)
- void m4() {
- }
-
- @Constants(int.class)
- void m5() {
- }
-
- @Constants(long.class)
- void m6() {
- }
-
- @Constants(short.class)
- void m7() {
- }
-
- @Constants(boolean.class)
- void m8() {
- }
-
- @Constants(void.class)
- void m9() {
- }
-
- @Constants(Date.class)
- void m10() {
- }
-
- @interface A {
-
- Class<?> value();
- }
-}
diff --git a/plugins/java-decompiler/testData/Deprecations$ByAnno.class b/plugins/java-decompiler/testData/Deprecations$ByAnno.class
deleted file mode 100644
index 4fcd96c2259e..000000000000
--- a/plugins/java-decompiler/testData/Deprecations$ByAnno.class
+++ /dev/null
Binary files differ
diff --git a/plugins/java-decompiler/testData/Deprecations$ByComment.class b/plugins/java-decompiler/testData/Deprecations$ByComment.class
deleted file mode 100644
index e04dcf79a0f2..000000000000
--- a/plugins/java-decompiler/testData/Deprecations$ByComment.class
+++ /dev/null
Binary files differ
diff --git a/plugins/java-decompiler/testData/Deprecations.class b/plugins/java-decompiler/testData/Deprecations.class
deleted file mode 100644
index aa6de359a4aa..000000000000
--- a/plugins/java-decompiler/testData/Deprecations.class
+++ /dev/null
Binary files differ
diff --git a/plugins/java-decompiler/testData/Deprecations.java b/plugins/java-decompiler/testData/Deprecations.java
deleted file mode 100644
index 838ff68131de..000000000000
--- a/plugins/java-decompiler/testData/Deprecations.java
+++ /dev/null
@@ -1,19 +0,0 @@
-public class Deprecations {
- /** @deprecated */
- public int byComment;
-
- @Deprecated
- public int byAnno;
-
- /** @deprecated */
- public void byComment() { }
-
- @Deprecated
- public void byAnno() { }
-
- /** @deprecated */
- public static class ByComment { }
-
- @Deprecated
- public static class ByAnno { }
-} \ No newline at end of file
diff --git a/plugins/java-decompiler/testData/Deprecations.txt b/plugins/java-decompiler/testData/Deprecations.txt
deleted file mode 100644
index bb1340e83799..000000000000
--- a/plugins/java-decompiler/testData/Deprecations.txt
+++ /dev/null
@@ -1,42 +0,0 @@
-//
-// Source code recreated from a .class file by IntelliJ IDEA
-// (powered by Fernflower decompiler)
-//
-
-
-public class Deprecations {
-
- /** @deprecated */
- public int byComment;
- /** @deprecated */
- @Deprecated
- public int byAnno;
-
-
- public Deprecations() {
- }
-
- /** @deprecated */
- public void byComment() {
- }
-
- /** @deprecated */
- @Deprecated
- public void byAnno() {
- }
-
- /** @deprecated */
- @Deprecated
- public static class ByAnno {
-
- public ByAnno() {
- }
- }
-
- /** @deprecated */
- public static class ByComment {
-
- public ByComment() {
- }
- }
-}
diff --git a/plugins/java-decompiler/testData/Enum$1.class b/plugins/java-decompiler/testData/Enum$1.class
deleted file mode 100644
index e52b1899a716..000000000000
--- a/plugins/java-decompiler/testData/Enum$1.class
+++ /dev/null
Binary files differ
diff --git a/plugins/java-decompiler/testData/Enum$2.class b/plugins/java-decompiler/testData/Enum$2.class
deleted file mode 100644
index c86cdd2a95d1..000000000000
--- a/plugins/java-decompiler/testData/Enum$2.class
+++ /dev/null
Binary files differ
diff --git a/plugins/java-decompiler/testData/Enum.class b/plugins/java-decompiler/testData/Enum.class
deleted file mode 100644
index 45123e255eab..000000000000
--- a/plugins/java-decompiler/testData/Enum.class
+++ /dev/null
Binary files differ
diff --git a/plugins/java-decompiler/testData/Enum.java b/plugins/java-decompiler/testData/Enum.java
deleted file mode 100644
index b61c069e0e19..000000000000
--- a/plugins/java-decompiler/testData/Enum.java
+++ /dev/null
@@ -1,19 +0,0 @@
-public enum Enum {
- E1,
- E2() {
- @Override
- public void m() { }
- },
- E3("-"),
- E4("+") {
- @Override
- public void m() { }
- };
-
- public void m() { }
-
- private String s;
-
- private Enum() { this("?"); }
- private Enum(@Deprecated String s) { this.s = s; }
-}
diff --git a/plugins/java-decompiler/testData/Enum.txt b/plugins/java-decompiler/testData/Enum.txt
deleted file mode 100644
index 1156c8214d78..000000000000
--- a/plugins/java-decompiler/testData/Enum.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-//
-// Source code recreated from a .class file by IntelliJ IDEA
-// (powered by Fernflower decompiler)
-//
-
-
-public enum Enum {
-
- E1,
- E2 {
- public void m() {
- }
- },
- E3("-"),
- E4("+") {
- public void m() {
- }
- };
- private String s;
-
-
- public void m() {
- }
-
- private Enum() {
- this((String)"?");
- }
-
- private Enum(@Deprecated String var3) {
- this.s = var3;
- }
-
-}
diff --git a/plugins/java-decompiler/testData/ExtendsList.java b/plugins/java-decompiler/testData/ExtendsList.java
deleted file mode 100644
index 19fbe6d66705..000000000000
--- a/plugins/java-decompiler/testData/ExtendsList.java
+++ /dev/null
@@ -1,9 +0,0 @@
-public class ExtendsList {
- static <T extends Comparable<? super T>> T m1(T t) {
- return null;
- }
-
- static <T extends Object & Comparable<? super T>> T m2(T t) {
- return null;
- }
-} \ No newline at end of file
diff --git a/plugins/java-decompiler/testData/ExtendsList.txt b/plugins/java-decompiler/testData/ExtendsList.txt
deleted file mode 100644
index 6996123b6a3d..000000000000
--- a/plugins/java-decompiler/testData/ExtendsList.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-//
-// Source code recreated from a .class file by IntelliJ IDEA
-// (powered by Fernflower decompiler)
-//
-
-
-public class ExtendsList {
-
- public ExtendsList() {
- }
-
- static <T extends Comparable<? super T>> T m1(T var0) {
- return null;
- }
-
- static <T extends Object & Comparable<? super T>> T m2(T var0) {
- return null;
- }
-}
diff --git a/plugins/java-decompiler/testData/Parameters$1Local.class b/plugins/java-decompiler/testData/Parameters$1Local.class
deleted file mode 100644
index a9c187cc05d7..000000000000
--- a/plugins/java-decompiler/testData/Parameters$1Local.class
+++ /dev/null
Binary files differ
diff --git a/plugins/java-decompiler/testData/Parameters$C1.class b/plugins/java-decompiler/testData/Parameters$C1.class
deleted file mode 100644
index 882226ceb63c..000000000000
--- a/plugins/java-decompiler/testData/Parameters$C1.class
+++ /dev/null
Binary files differ
diff --git a/plugins/java-decompiler/testData/Parameters$C2.class b/plugins/java-decompiler/testData/Parameters$C2.class
deleted file mode 100644
index 85a98c6f72dd..000000000000
--- a/plugins/java-decompiler/testData/Parameters$C2.class
+++ /dev/null
Binary files differ
diff --git a/plugins/java-decompiler/testData/Parameters.class b/plugins/java-decompiler/testData/Parameters.class
deleted file mode 100644
index f29432cf1fd0..000000000000
--- a/plugins/java-decompiler/testData/Parameters.class
+++ /dev/null
Binary files differ
diff --git a/plugins/java-decompiler/testData/Parameters.java b/plugins/java-decompiler/testData/Parameters.java
deleted file mode 100644
index be18b4e6e06f..000000000000
--- a/plugins/java-decompiler/testData/Parameters.java
+++ /dev/null
@@ -1,23 +0,0 @@
-public class Parameters {
- Parameters(@Deprecated int p01) { }
- void m1(@Deprecated int p02) { }
- static void m2(@Deprecated int p03) { }
-
- class C1 {
- C1(@Deprecated int p11) { }
- void m(@Deprecated int p12) { }
- }
-
- static class C2 {
- C2(@Deprecated int p21) { }
- void m1(@Deprecated int p22) { }
- static void m2(@Deprecated int p23) { }
- }
-
- void local() {
- class Local {
- Local(@Deprecated int p31) { }
- void m(@Deprecated int p32) { }
- }
- }
-} \ No newline at end of file
diff --git a/plugins/java-decompiler/testData/Parameters.txt b/plugins/java-decompiler/testData/Parameters.txt
deleted file mode 100644
index 45a856abdd89..000000000000
--- a/plugins/java-decompiler/testData/Parameters.txt
+++ /dev/null
@@ -1,50 +0,0 @@
-//
-// Source code recreated from a .class file by IntelliJ IDEA
-// (powered by Fernflower decompiler)
-//
-
-
-public class Parameters {
-
- Parameters(@Deprecated int var1) {
- }
-
- void m1(@Deprecated int var1) {
- }
-
- static void m2(@Deprecated int var0) {
- }
-
- void local() {
- class Local {
-
- Local(@Deprecated int var2) {
- }
-
- void m(@Deprecated int var1) {
- }
- }
-
- }
-
- static class C2 {
-
- C2(@Deprecated int var1) {
- }
-
- void m1(@Deprecated int var1) {
- }
-
- static void m2(@Deprecated int var0) {
- }
- }
-
- class C1 {
-
- C1(@Deprecated int var2) {
- }
-
- void m(@Deprecated int var1) {
- }
- }
-}
diff --git a/plugins/java-i18n/java-i18n.iml b/plugins/java-i18n/java-i18n.iml
index b2f011fe2f7c..08852084e604 100644
--- a/plugins/java-i18n/java-i18n.iml
+++ b/plugins/java-i18n/java-i18n.iml
@@ -21,7 +21,6 @@
<orderEntry type="module" module-name="testFramework-java" scope="TEST" />
<orderEntry type="module" module-name="properties-psi-api" />
<orderEntry type="module" module-name="properties-psi-impl" />
- <orderEntry type="module" module-name="ui-designer" scope="TEST" />
</component>
</module>
diff --git a/plugins/junit/src/com/intellij/execution/ConfigurationUtil.java b/plugins/junit/src/com/intellij/execution/ConfigurationUtil.java
index 274c2797540d..3d8da3aac313 100644
--- a/plugins/junit/src/com/intellij/execution/ConfigurationUtil.java
+++ b/plugins/junit/src/com/intellij/execution/ConfigurationUtil.java
@@ -95,7 +95,13 @@ public class ConfigurationUtil {
//allScope is used to find all abstract test cases which probably have inheritors in the current 'scope'
AnnotatedMembersSearch.search(testAnnotation, GlobalSearchScope.allScope(manager.getProject())).forEach(new Processor<PsiMember>() {
public boolean process(final PsiMember annotated) {
- final PsiClass containingClass = annotated instanceof PsiClass ? (PsiClass)annotated : annotated.getContainingClass();
+ final PsiClass containingClass = annotated instanceof PsiClass ? (PsiClass)annotated : ApplicationManager.getApplication()
+ .runReadAction(new Computable<PsiClass>() {
+ @Override
+ public PsiClass compute() {
+ return annotated.getContainingClass();
+ }
+ });
if (containingClass != null && annotated instanceof PsiMethod == isMethod) {
if (ApplicationManager.getApplication().runReadAction(
new Computable<Boolean>() {
diff --git a/plugins/junit/src/com/intellij/execution/junit/JUnitConfiguration.java b/plugins/junit/src/com/intellij/execution/junit/JUnitConfiguration.java
index 28cd670446e9..0b7ab14a151d 100644
--- a/plugins/junit/src/com/intellij/execution/junit/JUnitConfiguration.java
+++ b/plugins/junit/src/com/intellij/execution/junit/JUnitConfiguration.java
@@ -20,19 +20,23 @@ import com.intellij.diagnostic.logging.LogConfigurationPanel;
import com.intellij.execution.*;
import com.intellij.execution.configuration.EnvironmentVariablesComponent;
import com.intellij.execution.configurations.*;
+import com.intellij.execution.executors.DefaultRunExecutor;
import com.intellij.execution.junit2.configuration.JUnitConfigurable;
import com.intellij.execution.junit2.info.MethodLocation;
import com.intellij.execution.runners.ExecutionEnvironment;
+import com.intellij.execution.runners.ExecutionEnvironmentBuilder;
import com.intellij.execution.testframework.TestSearchScope;
import com.intellij.execution.util.JavaParametersUtil;
import com.intellij.openapi.components.PathMacroManager;
-import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.options.SettingsEditor;
import com.intellij.openapi.options.SettingsEditorGroup;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.*;
+import com.intellij.openapi.util.Comparing;
+import com.intellij.openapi.util.DefaultJDOMExternalizer;
+import com.intellij.openapi.util.InvalidDataException;
+import com.intellij.openapi.util.WriteExternalException;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
@@ -45,7 +49,6 @@ import java.util.*;
public class JUnitConfiguration extends ModuleBasedConfiguration<JavaRunConfigurationModule>
implements CommonJavaRunConfigurationParameters, RefactoringListenerProvider {
- private static final Logger LOG = Logger.getInstance("#com.intellij.execution.junit.JUnitConfiguration");
public static final String DEFAULT_PACKAGE_NAME = ExecutionBundle.message("default.package.presentable.name");
@NonNls public static final String TEST_CLASS = "class";
@@ -75,11 +78,12 @@ public class JUnitConfiguration extends ModuleBasedConfiguration<JavaRunConfigur
myData = data;
}
+ @Override
public RunProfileState getState(@NotNull final Executor executor, @NotNull final ExecutionEnvironment env) throws ExecutionException {
- return TestObject.fromString(myData.TEST_OBJECT, getProject(), this, env);
+ return TestObject.fromString(myData.TEST_OBJECT, this, env);
}
-
+ @Override
@NotNull
public SettingsEditor<? extends RunConfiguration> getConfigurationEditor() {
SettingsEditorGroup<JUnitConfiguration> group = new SettingsEditorGroup<JUnitConfiguration>();
@@ -93,22 +97,25 @@ public class JUnitConfiguration extends ModuleBasedConfiguration<JavaRunConfigur
return myData;
}
+ @Override
public RefactoringElementListener getRefactoringElementListener(final PsiElement element) {
- final RefactoringElementListener listener = myData.getTestObject(getProject(), this).getListener(element, this);
+ final RefactoringElementListener listener = myData.getTestObject(this).getListener(element, this);
return RunConfigurationExtension.wrapRefactoringElementListener(element, this, listener);
}
+ @Override
public void checkConfiguration() throws RuntimeConfigurationException {
- myData.getTestObject(getProject(), this).checkConfiguration();
+ myData.getTestObject(this).checkConfiguration();
JavaRunConfigurationExtensionManager.checkConfigurationIsValid(this);
}
+ @Override
public Collection<Module> getValidModules() {
if (TEST_PACKAGE.equals(myData.TEST_OBJECT) || TEST_PATTERN.equals(myData.TEST_OBJECT)) {
return Arrays.asList(ModuleManager.getInstance(getProject()).getModules());
}
try {
- myData.getTestObject(getProject(), this).checkConfiguration();
+ myData.getTestObject(this).checkConfiguration();
}
catch (RuntimeConfigurationError e) {
return Arrays.asList(ModuleManager.getInstance(getProject()).getModules());
@@ -120,10 +127,12 @@ public class JUnitConfiguration extends ModuleBasedConfiguration<JavaRunConfigur
return JavaRunConfigurationModule.getModulesForClass(getProject(), myData.getMainClassName());
}
+ @Override
protected ModuleBasedConfiguration createInstance() {
return new JUnitConfiguration(getName(), getProject(), myData.clone(), JUnitConfigurationType.getInstance().getConfigurationFactories()[0]);// throw new RuntimeException("Should not call");
}
+ @Override
public String suggestedName() {
return myData.getGeneratedName(getConfigurationModule());
}
@@ -133,68 +142,84 @@ public class JUnitConfiguration extends ModuleBasedConfiguration<JavaRunConfigur
return getTestObject().suggestActionName();
}
+ @Override
public void setVMParameters(String value) {
myData.setVMParameters(value);
}
+ @Override
public String getVMParameters() {
return myData.getVMParameters();
}
+ @Override
public void setProgramParameters(String value) {
myData.setProgramParameters(value);
}
+ @Override
public String getProgramParameters() {
return myData.getProgramParameters();
}
+ @Override
public void setWorkingDirectory(String value) {
myData.setWorkingDirectory(value);
}
+ @Override
public String getWorkingDirectory() {
return myData.getWorkingDirectory();
}
+ @Override
public void setEnvs(@NotNull Map<String, String> envs) {
myData.setEnvs(envs);
}
+ @Override
@NotNull
public Map<String, String> getEnvs() {
return myData.getEnvs();
}
+ @Override
public void setPassParentEnvs(boolean passParentEnvs) {
myData.PASS_PARENT_ENVS = passParentEnvs;
}
+ @Override
public boolean isPassParentEnvs() {
return myData.PASS_PARENT_ENVS;
}
+ @Override
public boolean isAlternativeJrePathEnabled() {
return ALTERNATIVE_JRE_PATH_ENABLED;
}
+ @Override
public void setAlternativeJrePathEnabled(boolean enabled) {
- this.ALTERNATIVE_JRE_PATH_ENABLED = enabled;
+ ALTERNATIVE_JRE_PATH_ENABLED = enabled;
}
+ @Override
public String getAlternativeJrePath() {
return ALTERNATIVE_JRE_PATH;
}
+ @Override
public void setAlternativeJrePath(String path) {
- this.ALTERNATIVE_JRE_PATH = path;
+ ALTERNATIVE_JRE_PATH = path;
}
+ @Override
public String getRunClass() {
final Data data = getPersistentData();
return data.TEST_OBJECT != TEST_CLASS && data.TEST_OBJECT != TEST_METHOD ? null : data.getMainClassName();
}
+ @Override
public String getPackage() {
final Data data = getPersistentData();
return !Comparing.strEqual(data.TEST_OBJECT, TEST_PACKAGE) ? null : data.getPackageName();
@@ -218,6 +243,7 @@ public class JUnitConfiguration extends ModuleBasedConfiguration<JavaRunConfigur
setGeneratedName();
}
+ @Override
@NotNull
public Module[] getModules() {
if (TEST_PACKAGE.equals(myData.TEST_OBJECT) &&
@@ -228,34 +254,40 @@ public class JUnitConfiguration extends ModuleBasedConfiguration<JavaRunConfigur
}
final RefactoringListeners.Accessor<PsiPackage> myPackage = new RefactoringListeners.Accessor<PsiPackage>() {
+ @Override
public void setName(final String qualifiedName) {
final boolean generatedName = isGeneratedName();
myData.PACKAGE_NAME = qualifiedName;
if (generatedName) setGeneratedName();
}
+ @Override
public PsiPackage getPsiElement() {
final String qualifiedName = myData.getPackageName();
return qualifiedName != null ? JavaPsiFacade.getInstance(getProject()).findPackage(qualifiedName)
: null;
}
+ @Override
public void setPsiElement(final PsiPackage psiPackage) {
setName(psiPackage.getQualifiedName());
}
};
final RefactoringListeners.Accessor<PsiClass> myClass = new RefactoringListeners.Accessor<PsiClass>() {
+ @Override
public void setName(@NotNull final String qualifiedName) {
final boolean generatedName = isGeneratedName();
myData.MAIN_CLASS_NAME = qualifiedName;
if (generatedName) setGeneratedName();
}
+ @Override
public PsiClass getPsiElement() {
return getConfigurationModule().findClass(myData.getMainClassName());
}
+ @Override
public void setPsiElement(final PsiClass psiClass) {
final Module originalModule = getConfigurationModule().getModule();
setMainClass(psiClass);
@@ -264,9 +296,10 @@ public class JUnitConfiguration extends ModuleBasedConfiguration<JavaRunConfigur
};
public TestObject getTestObject() {
- return myData.getTestObject(getProject(), this);
+ return myData.getTestObject(this);
}
+ @Override
public void readExternal(final Element element) throws InvalidDataException {
PathMacroManager.getInstance(getProject()).expandPaths(element);
super.readExternal(element);
@@ -304,6 +337,7 @@ public class JUnitConfiguration extends ModuleBasedConfiguration<JavaRunConfigur
}
}
+ @Override
public void writeExternal(final Element element) throws WriteExternalException {
super.writeExternal(element);
JavaRunConfigurationExtensionManager.getInstance().writeExternal(this, element);
@@ -445,6 +479,7 @@ public class JUnitConfiguration extends ModuleBasedConfiguration<JavaRunConfigur
return TEST_SEARCH_SCOPE.getScope();
}
+ @Override
public Data clone() {
try {
Data data = (Data)super.clone();
@@ -550,9 +585,9 @@ public class JUnitConfiguration extends ModuleBasedConfiguration<JavaRunConfigur
myPattern = pattern;
}
- public TestObject getTestObject(final Project project, final JUnitConfiguration configuration) {
+ public TestObject getTestObject(@NotNull JUnitConfiguration configuration) {
//TODO[dyoma]!
- return TestObject.fromString(TEST_OBJECT, project, configuration, null);
+ return TestObject.fromString(TEST_OBJECT, configuration, ExecutionEnvironmentBuilder.create(DefaultRunExecutor.getRunExecutorInstance(), configuration).build());
}
public Module setMainClass(final PsiClass testClass) {
diff --git a/plugins/junit/src/com/intellij/execution/junit/TestCategory.java b/plugins/junit/src/com/intellij/execution/junit/TestCategory.java
index 457e3d342336..01cced5a24a4 100644
--- a/plugins/junit/src/com/intellij/execution/junit/TestCategory.java
+++ b/plugins/junit/src/com/intellij/execution/junit/TestCategory.java
@@ -22,7 +22,6 @@ import com.intellij.execution.configurations.RuntimeConfigurationException;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.util.JavaParametersUtil;
import com.intellij.execution.util.ProgramParametersUtil;
-import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
/**
@@ -30,13 +29,8 @@ import com.intellij.psi.*;
* Date: 4/21/11
*/
class TestCategory extends TestPackage {
- private final Project myProject;
-
- public TestCategory(Project project,
- JUnitConfiguration configuration,
- ExecutionEnvironment environment) {
- super(project, configuration, environment);
- myProject = project;
+ public TestCategory(JUnitConfiguration configuration, ExecutionEnvironment environment) {
+ super(configuration, environment);
}
@Override
@@ -56,14 +50,14 @@ class TestCategory extends TestPackage {
@Override
protected PsiPackage getPackage(JUnitConfiguration.Data data) throws CantRunException {
- return JavaPsiFacade.getInstance(myProject).findPackage("");
+ return JavaPsiFacade.getInstance(myEnvironment.getProject()).findPackage("");
}
@Override
public boolean isConfiguredByElement(JUnitConfiguration configuration,
PsiClass testClass,
PsiMethod testMethod,
- PsiPackage testPackage,
+ PsiPackage testPackage,
PsiDirectory testDir) {
return false;
}
diff --git a/plugins/junit/src/com/intellij/execution/junit/TestClass.java b/plugins/junit/src/com/intellij/execution/junit/TestClass.java
index d1b687d05af9..e3ab54aa6adc 100644
--- a/plugins/junit/src/com/intellij/execution/junit/TestClass.java
+++ b/plugins/junit/src/com/intellij/execution/junit/TestClass.java
@@ -24,18 +24,16 @@ import com.intellij.execution.configurations.RunConfigurationModule;
import com.intellij.execution.configurations.RuntimeConfigurationException;
import com.intellij.execution.configurations.RuntimeConfigurationWarning;
import com.intellij.execution.runners.ExecutionEnvironment;
-import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.psi.*;
import com.intellij.refactoring.listeners.RefactoringElementListener;
class TestClass extends TestObject {
- public TestClass(final Project project,
- final JUnitConfiguration configuration,
- ExecutionEnvironment environment) {
- super(project, configuration, environment);
+ public TestClass(JUnitConfiguration configuration, ExecutionEnvironment environment) {
+ super(configuration, environment);
}
+ @Override
protected void initialize() throws ExecutionException {
super.initialize();
final JUnitConfiguration.Data data = myConfiguration.getPersistentData();
@@ -44,6 +42,7 @@ class TestClass extends TestObject {
myJavaParameters.getProgramParametersList().add(data.getMainClassName());
}
+ @Override
public String suggestActionName() {
String name = myConfiguration.getPersistentData().MAIN_CLASS_NAME;
if (name != null && name.endsWith(".")) {
@@ -52,10 +51,12 @@ class TestClass extends TestObject {
return JavaExecutionUtil.getShortClassName(name);
}
+ @Override
public RefactoringElementListener getListener(final PsiElement element, final JUnitConfiguration configuration) {
return RefactoringListeners.getClassOrPackageListener(element, configuration.myClass);
}
+ @Override
public boolean isConfiguredByElement(final JUnitConfiguration configuration,
PsiClass testClass,
PsiMethod testMethod,
@@ -72,6 +73,7 @@ class TestClass extends TestObject {
return Comparing.equal(JavaExecutionUtil.getRuntimeQualifiedName(testClass), configuration.getPersistentData().getMainClassName());
}
+ @Override
public void checkConfiguration() throws RuntimeConfigurationException {
super.checkConfiguration();
final String testClassName = myConfiguration.getPersistentData().getMainClassName();
diff --git a/plugins/junit/src/com/intellij/execution/junit/TestDirectory.java b/plugins/junit/src/com/intellij/execution/junit/TestDirectory.java
index 843e81e457a6..d0a9e2f0881e 100644
--- a/plugins/junit/src/com/intellij/execution/junit/TestDirectory.java
+++ b/plugins/junit/src/com/intellij/execution/junit/TestDirectory.java
@@ -40,20 +40,15 @@ import java.util.Collection;
* Date: 4/21/11
*/
class TestDirectory extends TestPackage {
- private final Project myProject;
-
- public TestDirectory(Project project,
- JUnitConfiguration configuration,
- ExecutionEnvironment environment) {
- super(project, configuration, environment);
- myProject = project;
+ public TestDirectory(JUnitConfiguration configuration, ExecutionEnvironment environment) {
+ super(configuration, environment);
}
@Override
public SourceScope getSourceScope() {
final String dirName = myConfiguration.getPersistentData().getDirName();
final VirtualFile file = LocalFileSystem.getInstance().findFileByPath(FileUtil.toSystemIndependentName(dirName));
- final GlobalSearchScope globalSearchScope = file == null ? GlobalSearchScope.EMPTY_SCOPE : GlobalSearchScopesCore.directoryScope(myProject, file, true);
+ final GlobalSearchScope globalSearchScope = file == null ? GlobalSearchScope.EMPTY_SCOPE : GlobalSearchScopesCore.directoryScope(myEnvironment.getProject(), file, true);
return new SourceScope() {
@Override
public GlobalSearchScope getGlobalSearchScope() {
@@ -62,13 +57,13 @@ class TestDirectory extends TestPackage {
@Override
public Project getProject() {
- return myProject;
+ return myEnvironment.getProject();
}
@Override
public GlobalSearchScope getLibrariesScope() {
final Module module = myConfiguration.getConfigurationModule().getModule();
- return module != null ? GlobalSearchScope.moduleWithLibrariesScope(module) : GlobalSearchScope.allScope(myProject);
+ return module != null ? GlobalSearchScope.moduleWithLibrariesScope(module) : GlobalSearchScope.allScope(myEnvironment.getProject());
}
@Override
@@ -104,7 +99,7 @@ class TestDirectory extends TestPackage {
if (file == null) {
throw new CantRunException("Directory \'" + dirName + "\' is not found");
}
- final PsiDirectory directory = PsiManager.getInstance(myProject).findDirectory(file);
+ final PsiDirectory directory = PsiManager.getInstance(myEnvironment.getProject()).findDirectory(file);
if (directory == null) {
throw new CantRunException("Directory \'" + dirName + "\' is not found");
}
@@ -119,10 +114,10 @@ class TestDirectory extends TestPackage {
public boolean isConfiguredByElement(JUnitConfiguration configuration,
PsiClass testClass,
PsiMethod testMethod,
- PsiPackage testPackage,
+ PsiPackage testPackage,
PsiDirectory testDir) {
if (JUnitConfiguration.TEST_DIRECTORY.equals(configuration.getPersistentData().TEST_OBJECT) && testDir != null) {
- if (Comparing.strEqual(FileUtil.toSystemIndependentName(configuration.getPersistentData().getDirName()),
+ if (Comparing.strEqual(FileUtil.toSystemIndependentName(configuration.getPersistentData().getDirName()),
testDir.getVirtualFile().getPath())) {
return true;
}
diff --git a/plugins/junit/src/com/intellij/execution/junit/TestMethod.java b/plugins/junit/src/com/intellij/execution/junit/TestMethod.java
index 23d798314197..21817210e4d8 100644
--- a/plugins/junit/src/com/intellij/execution/junit/TestMethod.java
+++ b/plugins/junit/src/com/intellij/execution/junit/TestMethod.java
@@ -31,12 +31,11 @@ import com.intellij.rt.execution.junit.JUnitStarter;
import org.jetbrains.annotations.NotNull;
class TestMethod extends TestObject {
- public TestMethod(final Project project,
- final JUnitConfiguration configuration,
- ExecutionEnvironment environment) {
- super(project, configuration, environment);
+ public TestMethod(JUnitConfiguration configuration, ExecutionEnvironment environment) {
+ super(configuration, environment);
}
+ @Override
protected void initialize() throws ExecutionException {
defaultInitialize();
final JUnitConfiguration.Data data = myConfiguration.getPersistentData();
@@ -66,16 +65,20 @@ class TestMethod extends TestObject {
myJavaParameters.getProgramParametersList().add(JUnitStarter.JUNIT3_PARAMETER);
}
+ @Override
public String suggestActionName() {
return ProgramRunnerUtil.shortenName(myConfiguration.getPersistentData().METHOD_NAME, 2) + "()";
}
+ @Override
public RefactoringElementListener getListener(final PsiElement element, final JUnitConfiguration configuration) {
if (element instanceof PsiMethod) {
final PsiMethod method = (PsiMethod)element;
if (!method.getName().equals(configuration.getPersistentData().getMethodName())) return null;
+ //noinspection ConstantConditions
if (!method.getContainingClass().equals(configuration.myClass.getPsiElement())) return null;
class Listener extends RefactoringElementAdapter implements UndoRefactoringElementListener {
+ @Override
public void elementRenamedOrMoved(@NotNull final PsiElement newElement) {
final boolean generatedName = configuration.isGeneratedName();
configuration.getPersistentData().setTestMethod(PsiLocation.fromPsiElement((PsiMethod)newElement));
@@ -99,6 +102,7 @@ class TestMethod extends TestObject {
}
+ @Override
public boolean isConfiguredByElement(final JUnitConfiguration configuration,
PsiClass testClass,
PsiMethod testMethod,
@@ -118,6 +122,7 @@ class TestMethod extends TestObject {
Comparing.equal(testMethod.getName(), data.getMethodName());
}
+ @Override
public void checkConfiguration() throws RuntimeConfigurationException {
super.checkConfiguration();
final JavaRunConfigurationModule configurationModule = myConfiguration.getConfigurationModule();
diff --git a/plugins/junit/src/com/intellij/execution/junit/TestMethods.java b/plugins/junit/src/com/intellij/execution/junit/TestMethods.java
index a526abb6a7ea..9f6a114e9cfe 100644
--- a/plugins/junit/src/com/intellij/execution/junit/TestMethods.java
+++ b/plugins/junit/src/com/intellij/execution/junit/TestMethods.java
@@ -35,23 +35,25 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.Function;
+import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.LinkedHashSet;
public class TestMethods extends TestMethod {
- private static final Logger LOG = Logger.getInstance("#com.intellij.execution.junit.TestMethods");
+ private static final Logger LOG = Logger.getInstance(TestMethods.class);
private final Collection<AbstractTestProxy> myFailedTests;
- public TestMethods(final Project project,
- final JUnitConfiguration configuration,
- ExecutionEnvironment environment,
- Collection<AbstractTestProxy> failedTests) {
- super(project, configuration, environment);
+ public TestMethods(@NotNull JUnitConfiguration configuration,
+ @NotNull ExecutionEnvironment environment,
+ @NotNull Collection<AbstractTestProxy> failedTests) {
+ super(configuration, environment);
+
myFailedTests = failedTests;
}
+ @Override
protected void initialize() throws ExecutionException {
defaultInitialize();
final JUnitConfiguration.Data data = myConfiguration.getPersistentData();
@@ -59,6 +61,7 @@ public class TestMethods extends TestMethod {
final Project project = module.getProject();
final ExecutionException[] exception = new ExecutionException[1];
ApplicationManager.getApplication().runReadAction(new Runnable() {
+ @Override
public void run() {
try {
myConfiguration.configureClasspath(myJavaParameters);
@@ -76,17 +79,17 @@ public class TestMethods extends TestMethod {
if (location instanceof PsiMemberParameterizedLocation) {
final PsiElement element = location.getPsiElement();
if (element instanceof PsiMethod) {
- location = MethodLocation.elementInClass(((PsiMethod)element),
+ location = MethodLocation.elementInClass(((PsiMethod)element),
((PsiMemberParameterizedLocation)location).getContainingClass());
}
}
if (!(location instanceof MethodLocation)) continue;
PsiElement psiElement = location.getPsiElement();
LOG.assertTrue(psiElement instanceof PsiMethod);
- PsiMethod method = (PsiMethod)psiElement;
methods.add(((TestProxy)failedTest).getInfo());
}
addClassesListToJavaParameters(methods, new Function<TestInfo, String>() {
+ @Override
public String fun(TestInfo testInfo) {
if (testInfo != null) {
final MethodLocation location = (MethodLocation)testInfo.getLocation(project, searchScope);
@@ -99,6 +102,7 @@ public class TestMethods extends TestMethod {
}
+ @Override
public String suggestActionName() {
return ActionsBundle.message("action.RerunFailedTests.text");
}
diff --git a/plugins/junit/src/com/intellij/execution/junit/TestObject.java b/plugins/junit/src/com/intellij/execution/junit/TestObject.java
index cc7c0ee66b74..e1b74d5452ef 100644
--- a/plugins/junit/src/com/intellij/execution/junit/TestObject.java
+++ b/plugins/junit/src/com/intellij/execution/junit/TestObject.java
@@ -39,7 +39,6 @@ import com.intellij.execution.testframework.*;
import com.intellij.execution.testframework.sm.SMTestRunnerConnectionUtil;
import com.intellij.execution.testframework.sm.runner.SMTRunnerConsoleProperties;
import com.intellij.execution.testframework.sm.runner.ui.SMTRunnerConsoleView;
-import com.intellij.execution.testframework.ui.BaseTestsOutputConsoleView;
import com.intellij.execution.ui.ConsoleView;
import com.intellij.execution.ui.ConsoleViewContentType;
import com.intellij.execution.util.JavaParametersUtil;
@@ -49,7 +48,6 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
-import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.JavaSdkType;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.ex.JavaSdkUtil;
@@ -81,13 +79,12 @@ import java.io.PrintWriter;
import java.util.*;
public abstract class TestObject implements JavaCommandLine {
- protected static final Logger LOG = Logger.getInstance("#com.intellij.execution.junit.TestObject");
+ protected static final Logger LOG = Logger.getInstance(TestObject.class);
private static final String MESSAGE = ExecutionBundle.message("configuration.not.speficied.message");
@NonNls private static final String JUNIT_TEST_FRAMEWORK_NAME = "JUnit";
protected JavaParameters myJavaParameters;
- private final Project myProject;
protected final JUnitConfiguration myConfiguration;
protected final ExecutionEnvironment myEnvironment;
protected File myTempFile = null;
@@ -95,26 +92,25 @@ public abstract class TestObject implements JavaCommandLine {
public File myListenersFile;
public static TestObject fromString(final String id,
- final Project project,
final JUnitConfiguration configuration,
- ExecutionEnvironment environment) {
+ @NotNull ExecutionEnvironment environment) {
if (JUnitConfiguration.TEST_METHOD.equals(id)) {
- return new TestMethod(project, configuration, environment);
+ return new TestMethod(configuration, environment);
}
if (JUnitConfiguration.TEST_CLASS.equals(id)) {
- return new TestClass(project, configuration, environment);
+ return new TestClass(configuration, environment);
}
if (JUnitConfiguration.TEST_PACKAGE.equals(id)){
- return new TestPackage(project, configuration, environment);
+ return new TestPackage(configuration, environment);
}
if (JUnitConfiguration.TEST_DIRECTORY.equals(id)) {
- return new TestDirectory(project, configuration, environment);
+ return new TestDirectory(configuration, environment);
}
if (JUnitConfiguration.TEST_CATEGORY.equals(id)) {
- return new TestCategory(project, configuration, environment);
+ return new TestCategory(configuration, environment);
}
if (JUnitConfiguration.TEST_PATTERN.equals(id)) {
- return new TestsPattern(project, configuration, environment);
+ return new TestsPattern(configuration, environment);
}
return NOT_CONFIGURED;
}
@@ -124,10 +120,7 @@ public abstract class TestObject implements JavaCommandLine {
return sourceScope != null ? sourceScope.getModulesToCompile() : Module.EMPTY_ARRAY;
}
- protected TestObject(final Project project,
- final JUnitConfiguration configuration,
- ExecutionEnvironment environment) {
- myProject = project;
+ protected TestObject(JUnitConfiguration configuration, ExecutionEnvironment environment) {
myConfiguration = configuration;
myEnvironment = environment;
}
@@ -143,7 +136,7 @@ public abstract class TestObject implements JavaCommandLine {
public abstract boolean isConfiguredByElement(JUnitConfiguration configuration,
PsiClass testClass,
PsiMethod testMethod,
- PsiPackage testPackage,
+ PsiPackage testPackage,
PsiDirectory testDir);
protected void configureModule(final JavaParameters parameters, final RunConfigurationModule configurationModule, final String mainClassName)
@@ -153,7 +146,7 @@ public abstract class TestObject implements JavaCommandLine {
myConfiguration.isAlternativeJrePathEnabled() ? myConfiguration.getAlternativeJrePath() : null);
}
- private static final TestObject NOT_CONFIGURED = new TestObject(null, null, null) {
+ private static final TestObject NOT_CONFIGURED = new TestObject(null, null) {
@Override
public RefactoringElementListener getListener(final PsiElement element, final JUnitConfiguration configuration) {
return null;
@@ -212,14 +205,10 @@ public abstract class TestObject implements JavaCommandLine {
if (myJavaParameters.getJdk() == null){
myJavaParameters.setJdk(module != null
? ModuleRootManager.getInstance(module).getSdk()
- : ProjectRootManager.getInstance(myProject).getProjectSdk());
+ : ProjectRootManager.getInstance(myEnvironment.getProject()).getProjectSdk());
}
- myJavaParameters.getClassPath().add(JavaSdkUtil.getIdeaRtJarPath());
- myJavaParameters.getClassPath().add(PathUtil.getJarPathForClass(JUnitStarter.class));
- if (Registry.is("junit_sm_runner")) {
- myJavaParameters.getClassPath().add(PathUtil.getJarPathForClass(ServiceMessageTypes.class));
- }
+ configureAdditionalClasspath(myJavaParameters);
myJavaParameters.getProgramParametersList().add(JUnitStarter.IDE_VERSION + JUnitStarter.VERSION);
if (!StringUtil.isEmptyOrSpaces(parameters)) {
myJavaParameters.getProgramParametersList().add("@name" + parameters);
@@ -257,6 +246,14 @@ public abstract class TestObject implements JavaCommandLine {
}
}
+ private void configureAdditionalClasspath(JavaParameters javaParameters) {
+ javaParameters.getClassPath().add(JavaSdkUtil.getIdeaRtJarPath());
+ javaParameters.getClassPath().add(PathUtil.getJarPathForClass(JUnitStarter.class));
+ if (Registry.is("junit_sm_runner")) {
+ javaParameters.getClassPath().add(PathUtil.getJarPathForClass(ServiceMessageTypes.class));
+ }
+ }
+
@Override
public JavaParameters getJavaParameters() throws ExecutionException {
if (myJavaParameters == null) {
@@ -368,8 +365,7 @@ public abstract class TestObject implements JavaCommandLine {
}
});
- final RerunFailedTestsAction rerunFailedTestsAction = new RerunFailedTestsAction(consoleView);
- rerunFailedTestsAction.init(consoleProperties, myEnvironment);
+ final RerunFailedTestsAction rerunFailedTestsAction = new RerunFailedTestsAction(consoleView, consoleProperties);
rerunFailedTestsAction.setModelProvider(new Getter<TestFrameworkRunningModel>() {
@Override
public TestFrameworkRunningModel get() {
@@ -384,22 +380,15 @@ public abstract class TestObject implements JavaCommandLine {
private ExecutionResult useSmRunner(Executor executor, JUnitProcessHandler handler) {
TestConsoleProperties testConsoleProperties = new SMTRunnerConsoleProperties(myConfiguration, JUNIT_TEST_FRAMEWORK_NAME, executor);
-
testConsoleProperties.setIfUndefined(TestConsoleProperties.HIDE_PASSED_TESTS, false);
- BaseTestsOutputConsoleView smtConsoleView = SMTestRunnerConnectionUtil.createConsoleWithCustomLocator(
+ final ConsoleView consoleView = SMTestRunnerConnectionUtil.createConsoleWithCustomLocator(
JUNIT_TEST_FRAMEWORK_NAME,
testConsoleProperties,
myEnvironment, null);
-
-
- Disposer.register(myProject, smtConsoleView);
-
- final ConsoleView consoleView = smtConsoleView;
consoleView.attachToProcess(handler);
- final RerunFailedTestsAction rerunFailedTestsAction = new RerunFailedTestsAction(consoleView);
- rerunFailedTestsAction.init(testConsoleProperties, myEnvironment);
+ RerunFailedTestsAction rerunFailedTestsAction = new RerunFailedTestsAction(consoleView, testConsoleProperties);
rerunFailedTestsAction.setModelProvider(new Getter<TestFrameworkRunningModel>() {
@Override
public TestFrameworkRunningModel get() {
@@ -421,12 +410,12 @@ public abstract class TestObject implements JavaCommandLine {
else {
comment = null;
}
- TestsUIUtil.notifyByBalloon(myProject, started, model != null ? model.getRoot() : null, consoleProperties, comment);
+ TestsUIUtil.notifyByBalloon(myEnvironment.getProject(), started, model != null ? model.getRoot() : null, consoleProperties, comment);
}
protected JUnitProcessHandler createHandler(Executor executor) throws ExecutionException {
appendForkInfo(executor);
- return JUnitProcessHandler.runCommandLine(CommandLineBuilder.createFromJavaParameters(myJavaParameters, myProject, true));
+ return JUnitProcessHandler.runCommandLine(CommandLineBuilder.createFromJavaParameters(myJavaParameters, myEnvironment.getProject(), true));
}
private boolean forkPerModule() {
@@ -439,17 +428,18 @@ public abstract class TestObject implements JavaCommandLine {
private void appendForkInfo(Executor executor) throws ExecutionException {
final String forkMode = myConfiguration.getForkMode();
if (Comparing.strEqual(forkMode, "none")) {
- if (forkPerModule() && getRunnerSettings() != null) {
- final String actionName = UIUtil.removeMnemonic(executor.getStartActionText());
- throw new CantRunException("'" + actionName + "' is disabled when per-module working directory is configured.<br/>" +
- "Please specify single working directory, or change test scope to single module.");
+ if (forkPerModule()) {
+ if (getRunnerSettings() != null) {
+ final String actionName = UIUtil.removeMnemonic(executor.getStartActionText());
+ throw new CantRunException("'" + actionName + "' is disabled when per-module working directory is configured.<br/>" +
+ "Please specify single working directory, or change test scope to single module.");
+ }
+ } else {
+ return;
}
- return;
- }
-
- if (getRunnerSettings() != null) {
+ } else if (getRunnerSettings() != null) {
final String actionName = executor.getActionName();
- throw new CantRunException(actionName + " is disabled in fork mode.<br/>Please change fork mode to &lt;none&gt; to " + actionName.toLowerCase() + ".");
+ throw new CantRunException(actionName + " is disabled in fork mode.<br/>Please change fork mode to &lt;none&gt; to " + actionName.toLowerCase(Locale.ENGLISH) + ".");
}
final JavaParameters javaParameters = getJavaParameters();
@@ -482,65 +472,71 @@ public abstract class TestObject implements JavaCommandLine {
protected <T> void addClassesListToJavaParameters(Collection<? extends T> elements, Function<T, String> nameFunction, String packageName,
boolean createTempFile,
- boolean junit4) {
+ boolean junit4) throws CantRunException {
try {
if (createTempFile) {
createTempFiles();
}
- final Map<String, List<String>> perModule = forkPerModule() ? new TreeMap<String, List<String>>() : null;
- final PrintWriter writer = new PrintWriter(myTempFile, CharsetToolkit.UTF8);
- try {
- writer.println(packageName);
- final JUnitConfiguration.Data data = myConfiguration.getPersistentData();
- final String category = data.TEST_OBJECT == JUnitConfiguration.TEST_CATEGORY ? data.getCategory() : "";
- writer.println(category);
- final List<String> testNames = new ArrayList<String>();
- for (final T element : elements) {
- final String name = nameFunction.fun(element);
- if (name == null) {
- LOG.error("invalid element " + element);
- return;
- }
+ final Map<Module, List<String>> perModule = forkPerModule() ? new TreeMap<Module, List<String>>(new Comparator<Module>() {
+ @Override
+ public int compare(Module o1, Module o2) {
+ return StringUtil.compare(o1.getName(), o2.getName(), true);
+ }
+ }) : null;
+
+ final List<String> testNames = new ArrayList<String>();
+
+ for (final T element : elements) {
+ final String name = nameFunction.fun(element);
+ if (name == null) {
+ LOG.error("invalid element " + element);
+ return;
+ }
- if (perModule != null && element instanceof PsiElement) {
- final Module module = ModuleUtilCore.findModuleForPsiElement((PsiElement)element);
- if (module != null) {
- final String moduleDir = PathMacroUtil.getModuleDir(module.getModuleFilePath());
- List<String> list = perModule.get(moduleDir);
- if (list == null) {
- list = new ArrayList<String>();
- perModule.put(moduleDir, list);
- }
- list.add(name);
+ if (perModule != null && element instanceof PsiElement) {
+ final Module module = ModuleUtilCore.findModuleForPsiElement((PsiElement)element);
+ if (module != null) {
+ List<String> list = perModule.get(module);
+ if (list == null) {
+ list = new ArrayList<String>();
+ perModule.put(module, list);
}
- } else {
- testNames.add(name);
+ list.add(name);
}
}
- if (perModule != null) {
- for (List<String> perModuleClasses : perModule.values()) {
- Collections.sort(perModuleClasses);
- testNames.addAll(perModuleClasses);
- }
- } else {
- Collections.sort(testNames); //sort tests in FQN order
+ else {
+ testNames.add(name);
}
- for (String testName : testNames) {
- writer.println(testName);
+ }
+ if (perModule != null) {
+ for (List<String> perModuleClasses : perModule.values()) {
+ Collections.sort(perModuleClasses);
+ testNames.addAll(perModuleClasses);
}
}
- finally {
- writer.close();
+ else {
+ Collections.sort(testNames); //sort tests in FQN order
}
+ final JUnitConfiguration.Data data = myConfiguration.getPersistentData();
+ final String category = data.TEST_OBJECT == JUnitConfiguration.TEST_CATEGORY ? data.getCategory() : "";
+ JUnitStarter.printClassesList(testNames, packageName, category, myTempFile);
+
if (perModule != null && perModule.size() > 1) {
final PrintWriter wWriter = new PrintWriter(myWorkingDirsFile, CharsetToolkit.UTF8);
try {
wWriter.println(packageName);
- for (String workingDir : perModule.keySet()) {
- wWriter.println(workingDir);
- final List<String> classNames = perModule.get(workingDir);
+ for (Module module : perModule.keySet()) {
+ final String moduleDir = PathMacroUtil.getModuleDir(module.getModuleFilePath());
+ wWriter.println(moduleDir);
+
+ final JavaParameters parameters = new JavaParameters();
+ JavaParametersUtil.configureModule(module, parameters, JavaParameters.JDK_AND_CLASSES_AND_TESTS,
+ myConfiguration.isAlternativeJrePathEnabled() ? myConfiguration.getAlternativeJrePath() : null);
+ configureAdditionalClasspath(parameters);
+ wWriter.println(parameters.getClassPath().getPathsString());
+ final List<String> classNames = perModule.get(module);
wWriter.println(classNames.size());
for (String className : classNames) {
wWriter.println(className);
diff --git a/plugins/junit/src/com/intellij/execution/junit/TestPackage.java b/plugins/junit/src/com/intellij/execution/junit/TestPackage.java
index 3d3c2da89143..6bde0b4419dd 100644
--- a/plugins/junit/src/com/intellij/execution/junit/TestPackage.java
+++ b/plugins/junit/src/com/intellij/execution/junit/TestPackage.java
@@ -27,7 +27,6 @@ import com.intellij.execution.process.ProcessAdapter;
import com.intellij.execution.process.ProcessEvent;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.runners.ExecutionEnvironmentBuilder;
-import com.intellij.execution.runners.ExecutionUtil;
import com.intellij.execution.testframework.SourceScope;
import com.intellij.execution.testframework.TestSearchScope;
import com.intellij.openapi.application.ApplicationManager;
@@ -71,13 +70,10 @@ public class TestPackage extends TestObject {
protected ServerSocket myServerSocket;
private boolean myFoundTests = true;
- public TestPackage(final Project project,
- final JUnitConfiguration configuration,
- ExecutionEnvironment environment) {
- super(project, configuration, environment);
+ public TestPackage(JUnitConfiguration configuration, ExecutionEnvironment environment) {
+ super(configuration, environment);
}
-
@Override
public SourceScope getSourceScope() {
final JUnitConfiguration.Data data = myConfiguration.getPersistentData();
diff --git a/plugins/junit/src/com/intellij/execution/junit/TestsPattern.java b/plugins/junit/src/com/intellij/execution/junit/TestsPattern.java
index 7277c5e5369d..a017cb1b8e9d 100644
--- a/plugins/junit/src/com/intellij/execution/junit/TestsPattern.java
+++ b/plugins/junit/src/com/intellij/execution/junit/TestsPattern.java
@@ -48,10 +48,8 @@ import java.util.LinkedHashSet;
import java.util.Set;
public class TestsPattern extends TestPackage {
- public TestsPattern(final Project project,
- final JUnitConfiguration configuration,
- ExecutionEnvironment environment) {
- super(project, configuration, environment);
+ public TestsPattern(JUnitConfiguration configuration, ExecutionEnvironment environment) {
+ super(configuration, environment);
}
@Override
@@ -119,7 +117,7 @@ public class TestsPattern extends TestPackage {
? className.substring(0, className.indexOf(','))
: className).trim(), GlobalSearchScope.allScope(project));
}
-
+
protected void configureClasspath() throws CantRunException {
final String jreHome = myConfiguration.isAlternativeJrePathEnabled() ? myConfiguration.getAlternativeJrePath() : null;
diff --git a/plugins/junit/src/com/intellij/execution/junit2/configuration/JUnitConfigurable.java b/plugins/junit/src/com/intellij/execution/junit2/configuration/JUnitConfigurable.java
index 07e578bae6c8..0a2119fb73d2 100644
--- a/plugins/junit/src/com/intellij/execution/junit2/configuration/JUnitConfigurable.java
+++ b/plugins/junit/src/com/intellij/execution/junit2/configuration/JUnitConfigurable.java
@@ -118,6 +118,7 @@ public class JUnitConfigurable extends SettingsEditor<JUnitConfiguration> implem
myModel = new JUnitConfigurationModel(project);
myModuleSelector = new ConfigurationModuleSelector(project, getModulesComponent());
myCommonJavaParameters.setModuleContext(myModuleSelector.getModule());
+ myCommonJavaParameters.setHasModuleMacro();
myModule.getComponent().addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
myCommonJavaParameters.setModuleContext(myModuleSelector.getModule());
diff --git a/plugins/junit/src/com/intellij/execution/junit2/states/ComparisonFailureState.java b/plugins/junit/src/com/intellij/execution/junit2/states/ComparisonFailureState.java
index d4ef1319d866..c772936f5d20 100644
--- a/plugins/junit/src/com/intellij/execution/junit2/states/ComparisonFailureState.java
+++ b/plugins/junit/src/com/intellij/execution/junit2/states/ComparisonFailureState.java
@@ -24,7 +24,7 @@ import com.intellij.execution.ui.ConsoleViewContentType;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NonNls;
-public class ComparisonFailureState extends FaultyState implements AbstractTestProxy.AssertEqualsDiffViewerProvider {
+public class ComparisonFailureState extends FaultyState implements AbstractTestProxy.AssertEqualsMultiDiffViewProvider {
private DiffHyperlink myHyperlink;
@NonNls
protected static final String EXPECTED_VALUE_MESSAGE_TEXT = "expected:<";
@@ -59,4 +59,19 @@ public class ComparisonFailureState extends FaultyState implements AbstractTestP
public void openDiff(final Project project) {
if (myHyperlink != null) myHyperlink.openDiff(project);
}
+
+ @Override
+ public void openMultiDiff(Project project, AbstractTestProxy.AssertEqualsDiffChain chain) {
+ if (myHyperlink != null) {
+ myHyperlink.openMultiDiff(project, chain);
+ }
+ }
+
+ @Override
+ public String getFilePath() {
+ if (myHyperlink != null) {
+ return myHyperlink.getFilePath();
+ }
+ return null;
+ }
}
diff --git a/plugins/junit/src/com/intellij/execution/junit2/ui/ConsolePanel.java b/plugins/junit/src/com/intellij/execution/junit2/ui/ConsolePanel.java
index 3fe67a6d5e1b..d4102d4df784 100644
--- a/plugins/junit/src/com/intellij/execution/junit2/ui/ConsolePanel.java
+++ b/plugins/junit/src/com/intellij/execution/junit2/ui/ConsolePanel.java
@@ -41,6 +41,7 @@ import com.intellij.ui.SimpleTextAttributes;
import com.intellij.ui.treeStructure.Tree;
import com.intellij.util.Alarm;
import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
@@ -69,25 +70,30 @@ public class ConsolePanel extends TestResultsPanel {
myPrinter = printer;
}
+ @Override
public void initUI() {
super.initUI();
myStartingProgress = new StartingProgress(myTreeView);
}
+ @Override
protected JComponent createStatisticsPanel() {
myStatisticsPanel = new StatisticsPanel();
return myStatisticsPanel;
}
+ @Override
protected ToolbarPanel createToolbarPanel() {
return new JUnitToolbarPanel(myProperties, myEnvironment, this);
}
+ @Override
protected TestStatusLine createStatusLine() {
myStatusLine = new JUnitStatusLine();
return myStatusLine;
}
+ @Override
protected JComponent createTestTreeView() {
myTreeView = new JUnitTestTreeView();
return myTreeView;
@@ -129,6 +135,7 @@ public class ConsolePanel extends TestResultsPanel {
return myPrinter;
}
+ @Override
public void dispose() {
stopStartingProgress();
myPrinter = null;
@@ -145,8 +152,10 @@ public class ConsolePanel extends TestResultsPanel {
private ProcessHandler myProcess;
private long myStartedAt = System.currentTimeMillis();
private final ProcessAdapter myProcessListener = new ProcessAdapter() {
+ @Override
public void processTerminated(ProcessEvent event) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
+ @Override
public void run() {
doStop();
}
@@ -162,7 +171,9 @@ public class ConsolePanel extends TestResultsPanel {
myTree.setPaintBusy(true);
//myStartingLabel.setBackground(UIManager.getColor("Tree.background"));
myTree.setCellRenderer(new TreeCellRenderer() {
- public Component getTreeCellRendererComponent(final JTree tree, final Object value,
+ @NotNull
+ @Override
+ public Component getTreeCellRendererComponent(@NotNull final JTree tree, final Object value,
final boolean selected, final boolean expanded,
final boolean leaf, final int row, final boolean hasFocus) {
myStartingLabel.clear();
@@ -173,7 +184,8 @@ public class ConsolePanel extends TestResultsPanel {
}
});
myTree.addPropertyChangeListener(JTree.TREE_MODEL_PROPERTY, new PropertyChangeListener() {
- public void propertyChange(final PropertyChangeEvent evt) {
+ @Override
+ public void propertyChange(@NotNull final PropertyChangeEvent evt) {
myTree.removePropertyChangeListener(JTree.TREE_MODEL_PROPERTY, this);
doStop();
}
@@ -189,6 +201,7 @@ public class ConsolePanel extends TestResultsPanel {
myProcess = null;
}
+ @Override
public void run() {
myModel.nodeChanged(myRootNode);
postRepaint();
diff --git a/plugins/junit/src/com/intellij/execution/junit2/ui/JUnitStatusLine.java b/plugins/junit/src/com/intellij/execution/junit2/ui/JUnitStatusLine.java
index 88a474cd31ab..c7aef3a9a378 100644
--- a/plugins/junit/src/com/intellij/execution/junit2/ui/JUnitStatusLine.java
+++ b/plugins/junit/src/com/intellij/execution/junit2/ui/JUnitStatusLine.java
@@ -17,7 +17,7 @@
package com.intellij.execution.junit2.ui;
import com.intellij.execution.ExecutionBundle;
-import com.intellij.execution.junit2.*;
+import com.intellij.execution.junit2.TestProxy;
import com.intellij.execution.junit2.events.NewChildEvent;
import com.intellij.execution.junit2.events.StateChangedEvent;
import com.intellij.execution.junit2.events.TestEvent;
@@ -47,15 +47,17 @@ class JUnitStatusLine extends TestStatusLine {
public void onProcessStarted(final ProcessHandler process) {
if (myTestsBuilt) return;
process.addProcessListener(new ProcessAdapter() {
+ @Override
public void processTerminated(ProcessEvent event) {
process.removeProcessListener(this);
ApplicationManager.getApplication().invokeLater(new Runnable() {
+ @Override
public void run() {
myStateInfo.setTerminated(myState);
if (!myTestsBuilt && myProgressBar.getFraction() == 0.0) {
myProgressBar.setColor(ColorProgressBar.RED);
myProgressBar.setFraction(1.0);
- myState.setText(ExecutionBundle.message("junit.runing.info.failed.to.start.error.message"));
+ myState.setText(ExecutionBundle.message("junit.running.info.failed.to.start.error.message"));
}
}
});
@@ -83,21 +85,21 @@ class JUnitStatusLine extends TestStatusLine {
myCurrentTestName = currentTest == null ? "" : Formatters.printTest(currentTest);
}
- public double getComplitedPercents() {
+ public double getCompletedPercents() {
return (double)myCompleted/(double)myTotal;
}
public void updateLabel(final JLabel label) {
- final StringBuffer buffer = new StringBuffer();
+ final StringBuilder buffer = new StringBuilder();
if (myDoneEvent != null && myTerminated) {
String termMessage = generateTermMessage(getTestCount(0));
buffer.append(termMessage);
final String comment = myDoneEvent.getComment();
if (comment.length() > 0) {
- buffer.append(" (" + comment + ")");
+ buffer.append(" (").append(comment).append(")");
}
} else {
- buffer.append(ExecutionBundle.message("junit.runing.info.status.running.number.with.name", getTestCount(myDoneEvent != null ? 0 : 1), myCurrentTestName));
+ buffer.append(ExecutionBundle.message("junit.running.info.status.running.number.with.name", getTestCount(myDoneEvent != null ? 0 : 1), myCurrentTestName));
}
label.setText(buffer.toString());
}
@@ -105,16 +107,16 @@ class JUnitStatusLine extends TestStatusLine {
private String getTestCount(int offset) {
String testCount;
if (myDefects > 0)
- testCount = ExecutionBundle.message("junit.runing.info.status.completed.from.total.failed", myCompleted + offset, myTotal, myDefects); // += " Failed: " + myDefects + " ";
+ testCount = ExecutionBundle.message("junit.running.info.status.completed.from.total.failed", myCompleted + offset, myTotal, myDefects); // += " Failed: " + myDefects + " ";
else
- testCount = ExecutionBundle.message("junit.runing.info.status.completed.from.total", myCompleted + offset, myTotal); // myCompleted + " of " + myTotal
+ testCount = ExecutionBundle.message("junit.running.info.status.completed.from.total", myCompleted + offset, myTotal); // myCompleted + " of " + myTotal
return testCount;
}
private String generateTermMessage(final String testCount) {
switch(myDoneEvent.getType()) {
- case DONE: return ExecutionBundle.message("junit.runing.info.status.done.count", testCount);
- default: return ExecutionBundle.message("junit.runing.info.status.terminated.count", testCount);
+ case DONE: return ExecutionBundle.message("junit.running.info.status.done.count", testCount);
+ default: return ExecutionBundle.message("junit.running.info.status.terminated.count", testCount);
}
}
@@ -131,6 +133,7 @@ class JUnitStatusLine extends TestStatusLine {
myProgress = progress;
}
+ @Override
public void onRunnerStateChanged(final StateEvent event) {
if (!event.isRunning()) {
final CompletionEvent completionEvent = (CompletionEvent) event;
@@ -143,18 +146,20 @@ class JUnitStatusLine extends TestStatusLine {
}
}
+ @Override
public void onTestChanged(final TestEvent event) {
if (event instanceof StateChangedEvent || event instanceof NewChildEvent)
updateCounters();
}
+ @Override
public void doDispose() {
myProgress = null;
}
private void updateCounters() {
myStateInfo.updateCounters(myProgress);
- myProgressBar.setFraction(myStateInfo.getComplitedPercents());
+ myProgressBar.setFraction(myStateInfo.getCompletedPercents());
if (myProgress.hasDefects()) {
myProgressBar.setColor(ColorProgressBar.RED);
}
diff --git a/plugins/junit/src/com/intellij/execution/junit2/ui/JUnitTreeConsoleView.java b/plugins/junit/src/com/intellij/execution/junit2/ui/JUnitTreeConsoleView.java
index b311002027b1..4b879594d262 100644
--- a/plugins/junit/src/com/intellij/execution/junit2/ui/JUnitTreeConsoleView.java
+++ b/plugins/junit/src/com/intellij/execution/junit2/ui/JUnitTreeConsoleView.java
@@ -41,17 +41,20 @@ public class JUnitTreeConsoleView extends BaseTestsOutputConsoleView {
myEnvironment = environment;
}
+ @Override
protected TestResultsPanel createTestResultsPanel() {
myConsolePanel = new ConsolePanel(getConsole().getComponent(), getPrinter(), myProperties, myEnvironment,
getConsole().createConsoleActions());
return myConsolePanel;
}
+ @Override
public void attachToProcess(final ProcessHandler processHandler) {
super.attachToProcess(processHandler);
myConsolePanel.onProcessStarted(processHandler);
}
+ @Override
public void dispose() {
super.dispose();
myConsolePanel = null;
diff --git a/plugins/junit/src/com/intellij/execution/junit2/ui/actions/RerunFailedTestsAction.java b/plugins/junit/src/com/intellij/execution/junit2/ui/actions/RerunFailedTestsAction.java
index 04c13aa9e6fa..332566b1b3f2 100644
--- a/plugins/junit/src/com/intellij/execution/junit2/ui/actions/RerunFailedTestsAction.java
+++ b/plugins/junit/src/com/intellij/execution/junit2/ui/actions/RerunFailedTestsAction.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,40 +13,38 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package com.intellij.execution.junit2.ui.actions;
-import com.intellij.execution.ExecutionException;
import com.intellij.execution.Executor;
import com.intellij.execution.actions.JavaRerunFailedTestsAction;
import com.intellij.execution.configurations.RunProfileState;
import com.intellij.execution.junit.JUnitConfiguration;
import com.intellij.execution.junit.TestMethods;
import com.intellij.execution.runners.ExecutionEnvironment;
+import com.intellij.execution.testframework.TestConsoleProperties;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.ui.ComponentContainer;
import org.jetbrains.annotations.NotNull;
-/**
- * @author Alexey
- */
public class RerunFailedTestsAction extends JavaRerunFailedTestsAction {
-
- public RerunFailedTestsAction(@NotNull ComponentContainer componentContainer) {
- super(componentContainer);
+ public RerunFailedTestsAction(@NotNull ComponentContainer componentContainer, @NotNull TestConsoleProperties consoleProperties) {
+ super(componentContainer, consoleProperties);
}
@Override
- public MyRunProfile getRunProfile() {
+ protected MyRunProfile getRunProfile(@NotNull ExecutionEnvironment environment) {
+ //noinspection ConstantConditions
final JUnitConfiguration configuration = (JUnitConfiguration)getModel().getProperties().getConfiguration();
- final TestMethods testMethods = new TestMethods(configuration.getProject(), configuration, myEnvironment, getFailedTests(configuration.getProject()));
+ final TestMethods testMethods = new TestMethods(configuration, environment, getFailedTests(configuration.getProject()));
return new MyRunProfile(configuration) {
+ @Override
@NotNull
public Module[] getModules() {
return testMethods.getModulesToCompile();
}
- public RunProfileState getState(@NotNull Executor executor, @NotNull ExecutionEnvironment env) throws ExecutionException {
+ @Override
+ public RunProfileState getState(@NotNull Executor executor, @NotNull ExecutionEnvironment env) {
testMethods.clear();
return testMethods;
}
diff --git a/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitForkedStarter.java b/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitForkedStarter.java
index dbb575ae6986..e79ab8e677b3 100644
--- a/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitForkedStarter.java
+++ b/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitForkedStarter.java
@@ -99,44 +99,37 @@ public class JUnitForkedStarter {
if (workingDirsPath == null || new File(workingDirsPath).length() == 0) {
final List children = testRunner.getChildTests(description);
final boolean forkTillMethod = forkMode.equalsIgnoreCase("method");
- result = processChildren(isJUnit4, listeners, out, err, parameters, testRunner, children, 0, forkTillMethod, null);
+ result = processChildren(isJUnit4, listeners, out, err, parameters, testRunner, children, 0, forkTillMethod, null, System.getProperty("java.class.path"));
} else {
final BufferedReader perDirReader = new BufferedReader(new FileReader(workingDirsPath));
try {
final String packageName = perDirReader.readLine();
String workingDir;
while ((workingDir = perDirReader.readLine()) != null) {
+ final String classpath = perDirReader.readLine();
try {
- File tempFile = File.createTempFile("idea_junit", ".tmp");
- tempFile.deleteOnExit();
-
- final FileOutputStream writer = new FileOutputStream(tempFile);
List classNames = new ArrayList();
- try {
- final int classNamesSize = Integer.parseInt(perDirReader.readLine());
- writer.write((packageName + ", working directory: \'" + workingDir + "\'\n").getBytes("UTF-8")); //instead of package name
- for (int i = 0; i < classNamesSize; i++) {
- String className = perDirReader.readLine();
- if (className == null) {
- System.err.println("Class name is expected. Working dir: " + workingDir);
- return -1;
- }
- classNames.add(className);
- writer.write((className + "\n").getBytes("UTF-8"));
+ final int classNamesSize = Integer.parseInt(perDirReader.readLine());
+ for (int i = 0; i < classNamesSize; i++) {
+ String className = perDirReader.readLine();
+ if (className == null) {
+ System.err.println("Class name is expected. Working dir: " + workingDir);
+ return -1;
}
- }
- finally {
- writer.close();
+ classNames.add(className);
}
final Object rootDescriptor = findByClassName(testRunner, (String)classNames.get(0), description);
final int childResult;
final File dir = new File(workingDir);
if (forkMode.equals("none")) {
+ File tempFile = File.createTempFile("idea_junit", ".tmp");
+ tempFile.deleteOnExit();
+ JUnitStarter.printClassesList(classNames, packageName + ", working directory: \'" + workingDir + "\'", "", tempFile);
childResult =
runChild(isJUnit4, listeners, out, err, parameters, "@" + tempFile.getAbsolutePath(), dir,
- String.valueOf(testRunner.getRegistry().getKnownObject(rootDescriptor) - 1));
+ String.valueOf(testRunner.getRegistry().getKnownObject(rootDescriptor) - 1), classpath);
} else {
final List children = new ArrayList(testRunner.getChildTests(description));
for (Iterator iterator = children.iterator(); iterator.hasNext(); ) {
@@ -145,7 +138,7 @@ public class JUnitForkedStarter {
}
}
final boolean forkTillMethod = forkMode.equalsIgnoreCase("method");
- childResult = processChildren(isJUnit4, listeners, out, err, parameters, testRunner, children, result, forkTillMethod, dir);
+ childResult = processChildren(isJUnit4, listeners, out, err, parameters, testRunner, children, result, forkTillMethod, dir, classpath);
}
result = Math.min(childResult, result);
}
@@ -187,7 +180,7 @@ public class JUnitForkedStarter {
IdeaTestRunner testRunner,
List children,
int result,
- boolean forkTillMethod, File workingDir) throws IOException, InterruptedException {
+ boolean forkTillMethod, File workingDir, String classpath) throws IOException, InterruptedException {
for (int i = 0, argsLength = children.size(); i < argsLength; i++) {
final Object child = children.get(i);
final List childTests = testRunner.getChildTests(child);
@@ -195,12 +188,11 @@ public class JUnitForkedStarter {
if (childTests.isEmpty() || !forkTillMethod) {
final int startIndex = testRunner.getRegistry().getKnownObject(child);
childResult =
- runChild(isJUnit4, listeners, out, err, parameters, testRunner.getStartDescription(child), workingDir,
- String.valueOf(startIndex));
+ runChild(isJUnit4, listeners, out, err, parameters, testRunner.getStartDescription(child), workingDir, String.valueOf(startIndex), classpath);
}
else {
childResult =
- processChildren(isJUnit4, listeners, out, err, parameters, testRunner, childTests, result, forkTillMethod, workingDir);
+ processChildren(isJUnit4, listeners, out, err, parameters, testRunner, childTests, result, forkTillMethod, workingDir, classpath);
}
result = Math.min(childResult, result);
}
@@ -213,14 +205,17 @@ public class JUnitForkedStarter {
SegmentedOutputStream err,
List parameters,
String description,
- File workingDir,
- String startIndex) throws IOException, InterruptedException {
+ File workingDir,
+ String startIndex,
+ String classpath) throws IOException, InterruptedException {
//noinspection SSBasedInspection
final File tempFile = File.createTempFile("fork", "test");
final String testOutputPath = tempFile.getAbsolutePath();
final ProcessBuilder builder = new ProcessBuilder();
builder.add(parameters);
+ builder.add("-classpath");
+ builder.add(classpath);
builder.add(JUnitForkedStarter.class.getName());
builder.add(testOutputPath);
builder.add(startIndex);
diff --git a/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitStarter.java b/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitStarter.java
index cb398d9a0262..5c0edbb9ded8 100644
--- a/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitStarter.java
+++ b/plugins/junit_rt/src/com/intellij/rt/execution/junit/JUnitStarter.java
@@ -226,4 +226,19 @@ public class JUnitStarter {
: Class.forName("com.intellij.junit3.JUnit3IdeaTestRunner");
}
+
+ public static void printClassesList(List classNames, String packageName, String category, File tempFile) throws IOException {
+ final PrintWriter writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(tempFile), "UTF-8"));
+
+ try {
+ writer.println(packageName); //package name
+ writer.println(category); //category
+ for (int i = 0; i < classNames.size(); i++) {
+ writer.println(classNames.get(i));
+ }
+ }
+ finally {
+ writer.close();
+ }
+ }
}
diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/references/MavenPathReferenceConverter.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/references/MavenPathReferenceConverter.java
index b136cf440f59..cc5619d8a50d 100644
--- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/references/MavenPathReferenceConverter.java
+++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/references/MavenPathReferenceConverter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
package org.jetbrains.idea.maven.dom.references;
import com.intellij.openapi.util.Condition;
+import com.intellij.openapi.util.Conditions;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.vfs.LocalFileSystem;
@@ -44,7 +45,7 @@ public class MavenPathReferenceConverter extends PathReferenceConverter {
private final Condition<PsiFileSystemItem> myCondition;
public MavenPathReferenceConverter() {
- this(Condition.TRUE);
+ this(Conditions.<PsiFileSystemItem>alwaysTrue());
}
public MavenPathReferenceConverter(@NotNull Condition<PsiFileSystemItem> condition) {
diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/plugins/api/common/MavenCommonParamReferenceProviders.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/plugins/api/common/MavenCommonParamReferenceProviders.java
index 48b86e5b8aa4..2e928726d839 100644
--- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/plugins/api/common/MavenCommonParamReferenceProviders.java
+++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/plugins/api/common/MavenCommonParamReferenceProviders.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,9 +17,10 @@ package org.jetbrains.idea.maven.plugins.api.common;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
-import com.intellij.openapi.util.Condition;
+import com.intellij.openapi.util.Conditions;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFileSystemItem;
import com.intellij.psi.PsiReference;
import com.intellij.psi.PsiReferenceBase;
import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReferenceSet;
@@ -48,7 +49,7 @@ public class MavenCommonParamReferenceProviders {
public PsiReference[] getReferencesByElement(@NotNull PsiElement element,
@NotNull MavenDomConfiguration domCfg,
@NotNull ProcessingContext context) {
- return MavenPathReferenceConverter.createReferences(domCfg, element, Condition.TRUE);
+ return MavenPathReferenceConverter.createReferences(domCfg, element, Conditions.<PsiFileSystemItem>alwaysTrue());
}
}
diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenArtifactDownloader.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenArtifactDownloader.java
index 9935bb301bcd..b46bb47d239b 100644
--- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenArtifactDownloader.java
+++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenArtifactDownloader.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -39,7 +39,7 @@ import java.util.concurrent.atomic.AtomicInteger;
public class MavenArtifactDownloader {
private static final ThreadPoolExecutor EXECUTOR =
- new ThreadPoolExecutor(5, Integer.MAX_VALUE, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new ThreadFactory() {
+ new ThreadPoolExecutor(5, Integer.MAX_VALUE, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new ThreadFactory() {
AtomicInteger num = new AtomicInteger();
@NotNull
diff --git a/plugins/maven/src/main/resources/META-INF/plugin.xml b/plugins/maven/src/main/resources/META-INF/plugin.xml
index c2d98d272044..41a8ad3c6040 100644
--- a/plugins/maven/src/main/resources/META-INF/plugin.xml
+++ b/plugins/maven/src/main/resources/META-INF/plugin.xml
@@ -46,7 +46,7 @@
<applicationService serviceImplementation="org.jetbrains.idea.maven.indices.MavenIndicesManager"/>
<applicationService serviceImplementation="org.jetbrains.idea.maven.services.MavenRepositoryServicesManager"/>
- <projectConfigurable groupId="build" instance="org.jetbrains.idea.maven.utils.MavenSettings" id="MavenSettings" displayName="Maven" order="last">
+ <projectConfigurable groupId="build.tools" groupWeight="120" instance="org.jetbrains.idea.maven.utils.MavenSettings" id="MavenSettings" displayName="Maven" order="last">
<configurable instance="org.jetbrains.idea.maven.project.MavenImportingConfigurable" id="reference.settings.project.maven.importing"
key="maven.tab.importing" bundle="ProjectBundle"/>
<configurable instance="org.jetbrains.idea.maven.project.MavenIgnoredFilesConfigurable"
diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/MavenImportingTestCase.java b/plugins/maven/src/test/java/org/jetbrains/idea/maven/MavenImportingTestCase.java
index 79639e96c8b8..810e27460e54 100644
--- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/MavenImportingTestCase.java
+++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/MavenImportingTestCase.java
@@ -521,7 +521,7 @@ public abstract class MavenImportingTestCase extends MavenTestCase {
}
protected Sdk setupJdkForModule(final String moduleName) {
- final Sdk sdk = true ? JavaAwareProjectJdkTableImpl.getInstanceEx().getInternalJdk() : createJdk("Java 1.5");
+ final Sdk sdk = JavaAwareProjectJdkTableImpl.getInstanceEx().getInternalJdk();
ModuleRootModificationUtil.setModuleSdk(getModule(moduleName), sdk);
return sdk;
}
diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/compiler/ManifestGenerationTest.java b/plugins/maven/src/test/java/org/jetbrains/idea/maven/compiler/ManifestGenerationTest.java
index 6bc55921b1b3..0ef6067d6b0f 100644
--- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/compiler/ManifestGenerationTest.java
+++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/compiler/ManifestGenerationTest.java
@@ -19,14 +19,36 @@ import com.intellij.openapi.application.ApplicationNamesInfo;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.ModuleRootManager;
+import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import org.jetbrains.idea.maven.project.MavenWorkspaceSettingsComponent;
+
+import java.io.File;
/**
* @author Vladislav.Soroka
* @since 5/23/2014
*/
public class ManifestGenerationTest extends MavenCompilingTestCase {
+ private File myGlobalSettingsFile;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ myGlobalSettingsFile = MavenWorkspaceSettingsComponent.getInstance(myProject).getSettings().generalSettings.getEffectiveGlobalSettingsIoFile();
+ if (myGlobalSettingsFile != null) {
+ VfsRootAccess.allowRootAccess(myGlobalSettingsFile.getAbsolutePath());
+ }
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ if (myGlobalSettingsFile != null) {
+ VfsRootAccess.disallowRootAccess(myGlobalSettingsFile.getAbsolutePath());
+ }
+ super.tearDown();
+ }
public void testBasic() throws Exception {
importProject("<groupId>test</groupId>" +
diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/compiler/MavenCompilingTestCase.java b/plugins/maven/src/test/java/org/jetbrains/idea/maven/compiler/MavenCompilingTestCase.java
index aa430ca15de7..43ec755de8f4 100644
--- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/compiler/MavenCompilingTestCase.java
+++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/compiler/MavenCompilingTestCase.java
@@ -16,36 +16,33 @@
package org.jetbrains.idea.maven.compiler;
import com.intellij.compiler.CompilerTestUtil;
-import com.intellij.compiler.CompilerWorkspaceConfiguration;
import com.intellij.compiler.artifacts.ArtifactsTestUtil;
import com.intellij.compiler.impl.ModuleCompileScope;
-import com.intellij.openapi.compiler.CompileContext;
import com.intellij.openapi.compiler.CompileScope;
-import com.intellij.openapi.compiler.CompileStatusNotification;
-import com.intellij.openapi.compiler.CompilerManager;
+import com.intellij.openapi.compiler.CompilerMessage;
+import com.intellij.openapi.compiler.CompilerMessageCategory;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.packaging.artifacts.Artifact;
import com.intellij.packaging.impl.compiler.ArtifactCompileScope;
-import com.intellij.util.concurrency.Semaphore;
+import com.intellij.testFramework.CompilerTester;
import com.intellij.util.io.TestFileSystemBuilder;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.idea.maven.MavenImportingTestCase;
import org.jetbrains.idea.maven.project.MavenProjectsManager;
import org.jetbrains.idea.maven.project.MavenResourceCompilerConfigurationGenerator;
-import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
* @author nik
*/
public abstract class MavenCompilingTestCase extends MavenImportingTestCase {
-
protected void tearDown() throws Exception {
try {
CompilerTestUtil.disableExternalCompiler(myProject);
@@ -64,42 +61,29 @@ public abstract class MavenCompilingTestCase extends MavenImportingTestCase {
}
private void compile(final CompileScope scope) {
- UIUtil.invokeAndWaitIfNeeded(new Runnable() {
- @Override
- public void run() {
- for (Module module : scope.getAffectedModules()) {
- setupJdkForModule(module.getName());
+ try {
+ CompilerTester tester = new CompilerTester(myProject, Arrays.asList(scope.getAffectedModules()));
+ UIUtil.invokeAndWaitIfNeeded(new Runnable() {
+ @Override
+ public void run() {
+ new MavenResourceCompilerConfigurationGenerator(myProject, MavenProjectsManager.getInstance(myProject).getProjectsTreeForTests())
+ .generateBuildConfiguration(false);
}
- new MavenResourceCompilerConfigurationGenerator(myProject, MavenProjectsManager.getInstance(myProject).getProjectsTreeForTests()).generateBuildConfiguration(false);
- }
- });
-
- CompilerWorkspaceConfiguration.getInstance(myProject).CLEAR_OUTPUT_DIRECTORY = true;
-
- final Semaphore semaphore = new Semaphore();
- semaphore.down();
- UIUtil.invokeAndWaitIfNeeded(new Runnable() {
- @Override
- public void run() {
- CompilerTestUtil.enableExternalCompiler();
- CompilerManager.getInstance(myProject).make(scope, new CompileStatusNotification() {
- @Override
- public void finished(boolean aborted, int errors, int warnings, CompileContext compileContext) {
- //assertFalse(aborted);
- //assertEquals(collectMessages(compileContext, CompilerMessageCategory.ERROR), 0, errors);
- //assertEquals(collectMessages(compileContext, CompilerMessageCategory.WARNING), 0, warnings);
- semaphore.up();
+ });
+ try {
+ List<CompilerMessage> messages = tester.make(scope);
+ for (CompilerMessage message : messages) {
+ if (message.getCategory() == CompilerMessageCategory.ERROR) {
+ fail("Compilation failed with error: " + message.getMessage());
}
- });
+ }
}
- });
- while (!semaphore.waitFor(100)) {
- if (SwingUtilities.isEventDispatchThread()) {
- UIUtil.dispatchAllInvocationEvents();
+ finally {
+ tester.tearDown();
}
}
- if (SwingUtilities.isEventDispatchThread()) {
- UIUtil.dispatchAllInvocationEvents();
+ catch (Exception e) {
+ throw new RuntimeException(e);
}
}
diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/PropertiesImplUtil.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/PropertiesImplUtil.java
index 15e73791f8ea..502d9b4dc499 100644
--- a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/PropertiesImplUtil.java
+++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/PropertiesImplUtil.java
@@ -15,7 +15,6 @@
*/
package com.intellij.lang.properties;
-import com.intellij.lang.HtmlScriptContentProvider;
import com.intellij.lang.properties.psi.PropertiesFile;
import com.intellij.lang.properties.psi.PropertyKeyIndex;
import com.intellij.lang.properties.xml.XmlPropertiesFileImpl;
@@ -79,7 +78,13 @@ public class PropertiesImplUtil extends PropertiesUtil {
private static ResourceBundle getResourceBundle(@NotNull final String baseName, @NotNull final PsiDirectory baseDirectory) {
PropertiesFile defaultPropertiesFile = null;
final ResourceBundleManager bundleBaseNameManager = ResourceBundleManager.getInstance(baseDirectory.getProject());
- for (final PsiFile psiFile : baseDirectory.getFiles()) {
+ final PsiFile[] psiFiles = ApplicationManager.getApplication().runReadAction(new Computable<PsiFile[]>() {
+ @Override
+ public PsiFile[] compute() {
+ return baseDirectory.getFiles();
+ }
+ });
+ for (final PsiFile psiFile : psiFiles) {
if (baseName.equals(bundleBaseNameManager.getBaseName(psiFile))) {
final PropertiesFile propertiesFile = getPropertiesFile(psiFile);
if (propertiesFile != null) {
@@ -147,4 +152,4 @@ public class PropertiesImplUtil extends PropertiesUtil {
}
return getResourceBundle(baseName, baseDirectory);
}
-}
+} \ No newline at end of file
diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfiguration.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfiguration.java
index 9d8df6591268..bbafc719f43b 100644
--- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfiguration.java
+++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnConfiguration.java
@@ -53,12 +53,7 @@ import java.util.TreeSet;
@State(
name = "SvnConfiguration",
- roamingType = RoamingType.DISABLED,
- storages = {
- @Storage(
- file = StoragePathMacros.WORKSPACE_FILE
- )
- }
+ storages = {@Storage(file = StoragePathMacros.WORKSPACE_FILE)}
)
public class SvnConfiguration implements PersistentStateComponent<SvnConfigurationState> {
diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryTreeModel.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryTreeModel.java
index c57391dc546e..38195f64053f 100644
--- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryTreeModel.java
+++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryTreeModel.java
@@ -122,10 +122,12 @@ public class RepositoryTreeModel extends DefaultTreeModel implements Disposable
return myCacheLoader;
}
+ @NotNull
public Expander getLazyLoadingExpander() {
return myDefaultExpanderFactory.fun(myBrowser);
}
+ @NotNull
public Expander getSelectionKeepingExpander() {
return new KeepingSelectionExpander(myBrowser);
}
diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryTreeNode.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryTreeNode.java
index f21ca1735ff4..90f617ecad72 100644
--- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryTreeNode.java
+++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryTreeNode.java
@@ -15,9 +15,12 @@
*/
package org.jetbrains.idea.svn.dialogs;
+import com.intellij.CommonBundle;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.util.NotNullFunction;
+import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.containers.FilteringIterator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.SvnVcs;
@@ -27,7 +30,6 @@ import org.jetbrains.idea.svn.dialogs.browserCache.NodeLoadState;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
-import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;
import java.util.ArrayList;
import java.util.Collections;
@@ -37,16 +39,16 @@ import java.util.List;
public class RepositoryTreeNode implements TreeNode, Disposable {
private TreeNode myParentNode;
- private List<TreeNode> myChildren;
+ @NotNull private final List<TreeNode> myChildren;
private final RepositoryTreeModel myModel;
private final SVNURL myURL;
private final Object myUserObject;
- private final NodeLoadState myLoadState;
+ @NotNull private final NodeLoadState myLoadState;
private NodeLoadState myChildrenLoadState;
public RepositoryTreeNode(RepositoryTreeModel model, TreeNode parentNode,
- @NotNull SVNURL url, Object userObject, final NodeLoadState state) {
+ @NotNull SVNURL url, Object userObject, @NotNull NodeLoadState state) {
myParentNode = parentNode;
myURL = url;
@@ -54,6 +56,7 @@ public class RepositoryTreeNode implements TreeNode, Disposable {
myUserObject = userObject;
myLoadState = state;
+ myChildren = ContainerUtil.newArrayList();
myChildrenLoadState = NodeLoadState.EMPTY;
}
@@ -113,10 +116,10 @@ public class RepositoryTreeNode implements TreeNode, Disposable {
return SVNPathUtil.tail(myURL.getPath());
}
- public void reload(final Expander expander, final boolean removeCurrentChildren) {
+ public void reload(@NotNull Expander expander, boolean removeCurrentChildren) {
ApplicationManager.getApplication().assertIsDispatchThread();
- if (removeCurrentChildren || (myChildren == null)) {
+ if (removeCurrentChildren || NodeLoadState.EMPTY.equals(myChildrenLoadState)) {
initChildren();
}
@@ -124,15 +127,15 @@ public class RepositoryTreeNode implements TreeNode, Disposable {
}
private void initChildren() {
- myChildren = new ArrayList<TreeNode>();
- myChildren.add(new DefaultMutableTreeNode("Loading"));
+ myChildren.clear();
+ myChildren.add(new SimpleTextNode(CommonBundle.getLoadingTreeNodeText()));
myChildrenLoadState = NodeLoadState.LOADING;
}
private List getChildren() {
ApplicationManager.getApplication().assertIsDispatchThread();
-
- if (myChildren == null) {
+
+ if (NodeLoadState.EMPTY.equals(myChildrenLoadState)) {
initChildren();
myModel.getCacheLoader().load(this, myModel.getLazyLoadingExpander());
}
@@ -145,10 +148,7 @@ public class RepositoryTreeNode implements TreeNode, Disposable {
@Nullable
public DirectoryEntry getSVNDirEntry() {
- if (myUserObject instanceof DirectoryEntry) {
- return (DirectoryEntry) myUserObject;
- }
- return null;
+ return myUserObject instanceof DirectoryEntry ? (DirectoryEntry)myUserObject : null;
}
public void dispose() {
@@ -164,35 +164,19 @@ public class RepositoryTreeNode implements TreeNode, Disposable {
@NotNull
public List<TreeNode> getAllAlreadyLoadedChildren() {
- if (myChildren != null) {
- final List<TreeNode> result = new ArrayList<TreeNode>(myChildren.size());
- for (TreeNode child : myChildren) {
- result.add(child);
- }
- return result;
- }
- return Collections.emptyList();
+ return ContainerUtil.newArrayList(myChildren);
}
@NotNull
public List<RepositoryTreeNode> getAlreadyLoadedChildren() {
- if (myChildren != null) {
- final List<RepositoryTreeNode> result = new ArrayList<RepositoryTreeNode>(myChildren.size());
- for (TreeNode child : myChildren) {
- if (child instanceof RepositoryTreeNode) {
- result.add((RepositoryTreeNode) child);
- }
- }
- return result;
- }
- return Collections.emptyList();
+ return ContainerUtil.collect(myChildren.iterator(), FilteringIterator.instanceOf(RepositoryTreeNode.class));
}
public boolean isDisposed() {
return myModel.isDisposed();
}
- public void setChildren(final List<DirectoryEntry> children, final NodeLoadState state) {
+ public void setChildren(@NotNull List<DirectoryEntry> children, @NotNull NodeLoadState state) {
final List<TreeNode> nodes = new ArrayList<TreeNode>();
for (final DirectoryEntry entry : children) {
if (!myModel.isShowFiles() && !entry.isDirectory()) {
@@ -213,19 +197,17 @@ public class RepositoryTreeNode implements TreeNode, Disposable {
}
public void setAlienChildren(final List<TreeNode> children, final NodeLoadState oldState) {
- if (myChildren == null) {
- myChildren = new ArrayList<TreeNode>();
- } else {
- myChildren.clear();
- }
+ myChildren.clear();
for (TreeNode child : children) {
if (child instanceof RepositoryTreeNode) {
((RepositoryTreeNode) child).setParentNode(this);
myChildren.add(child);
myChildrenLoadState = oldState;
- } else if (child instanceof DefaultMutableTreeNode) {
- myChildren.add(new DefaultMutableTreeNode(((DefaultMutableTreeNode) child).getUserObject()));
+ }
+ else if (child instanceof SimpleTextNode) {
+ SimpleTextNode node = (SimpleTextNode)child;
+ myChildren.add(new SimpleTextNode(node.getText(), node.isError()));
myChildrenLoadState = oldState;
}
}
@@ -233,13 +215,9 @@ public class RepositoryTreeNode implements TreeNode, Disposable {
myModel.reload(this);
}
- public void setErrorNode(final String text, final NodeLoadState state) {
- if (myChildren == null) {
- myChildren = new ArrayList<TreeNode>();
- }
+ public void setErrorNode(@NotNull String text) {
myChildren.clear();
- myChildren.add(new DefaultMutableTreeNode(text));
-
+ myChildren.add(new SimpleTextNode(text, true));
myChildrenLoadState = NodeLoadState.ERROR;
myModel.reload(this);
}
@@ -257,24 +235,20 @@ public class RepositoryTreeNode implements TreeNode, Disposable {
return myModel.findByUrl(this);
}
- public RepositoryTreeModel getModel() {
- return myModel;
- }
-
public NodeLoadState getChildrenLoadState() {
return myChildrenLoadState;
}
- public void doOnSubtree(final NotNullFunction<RepositoryTreeNode, Object> function) {
- final SubTreeWalker walker = new SubTreeWalker(this, function);
- walker.execute();
+ public void doOnSubtree(@NotNull NotNullFunction<RepositoryTreeNode, Object> function) {
+ new SubTreeWalker(this, function).execute();
}
private static class SubTreeWalker {
- private final RepositoryTreeNode myNode;
- private final NotNullFunction<RepositoryTreeNode, Object> myFunction;
- private SubTreeWalker(final RepositoryTreeNode node, final NotNullFunction<RepositoryTreeNode, Object> function) {
+ @NotNull private final RepositoryTreeNode myNode;
+ @NotNull private final NotNullFunction<RepositoryTreeNode, Object> myFunction;
+
+ private SubTreeWalker(@NotNull RepositoryTreeNode node, @NotNull NotNullFunction<RepositoryTreeNode, Object> function) {
myNode = node;
myFunction = function;
}
diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SimpleTextNode.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SimpleTextNode.java
new file mode 100644
index 000000000000..ce3f0d923252
--- /dev/null
+++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SimpleTextNode.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.idea.svn.dialogs;
+
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.tree.DefaultMutableTreeNode;
+
+/**
+ * @author Konstantin Kolosovsky.
+ */
+public class SimpleTextNode extends DefaultMutableTreeNode {
+
+ private final boolean myIsError;
+
+ public SimpleTextNode(@NotNull String text) {
+ this(text, false);
+ }
+
+ public SimpleTextNode(@NotNull String text, boolean isError) {
+ super(text);
+ myIsError = isError;
+ }
+
+ public boolean isError() {
+ return myIsError;
+ }
+
+ @NotNull
+ public String getText() {
+ return (String)getUserObject();
+ }
+}
diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SvnRepositoryTreeCellRenderer.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SvnRepositoryTreeCellRenderer.java
index 6ecd89f82fd7..75742303b050 100644
--- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SvnRepositoryTreeCellRenderer.java
+++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SvnRepositoryTreeCellRenderer.java
@@ -15,17 +15,14 @@
*/
package org.jetbrains.idea.svn.dialogs;
-import com.intellij.CommonBundle;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.ui.ColoredTreeCellRenderer;
import com.intellij.ui.SimpleTextAttributes;
import com.intellij.util.PlatformIcons;
import com.intellij.util.text.DateFormatUtil;
import org.jetbrains.idea.svn.browse.DirectoryEntry;
-import org.tmatesoft.svn.core.SVNErrorMessage;
import javax.swing.*;
-import javax.swing.tree.DefaultMutableTreeNode;
public class SvnRepositoryTreeCellRenderer extends ColoredTreeCellRenderer {
@@ -56,13 +53,11 @@ public class SvnRepositoryTreeCellRenderer extends ColoredTreeCellRenderer {
? FileTypeManager.getInstance().getFileTypeByFileName(name).getIcon()
: PlatformIcons.DIRECTORY_CLOSED_ICON);
}
- } else if (value instanceof DefaultMutableTreeNode) {
- DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
- if (node.getUserObject() instanceof String) {
- append(CommonBundle.getLoadingTreeNodeText(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
- } else if (node.getUserObject() instanceof SVNErrorMessage) {
- append(node.getUserObject().toString(), SimpleTextAttributes.ERROR_ATTRIBUTES);
- }
+ }
+ else if (value instanceof SimpleTextNode) {
+ SimpleTextNode node = (SimpleTextNode)value;
+
+ append(node.getText(), node.isError() ? SimpleTextAttributes.ERROR_ATTRIBUTES : SimpleTextAttributes.REGULAR_ATTRIBUTES);
}
}
diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/browserCache/CacheLoader.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/browserCache/CacheLoader.java
index d80efb97a123..f8553d5c66c3 100644
--- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/browserCache/CacheLoader.java
+++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/browserCache/CacheLoader.java
@@ -16,6 +16,7 @@
package org.jetbrains.idea.svn.dialogs.browserCache;
import com.intellij.openapi.components.ServiceManager;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.svn.browse.DirectoryEntry;
import org.jetbrains.idea.svn.dialogs.RepositoryTreeNode;
@@ -23,7 +24,8 @@ import javax.swing.*;
import java.util.List;
public class CacheLoader extends Loader {
- private final Loader myRepositoryLoader;
+
+ @NotNull private final Loader myRepositoryLoader;
public static Loader getInstance() {
return ServiceManager.getService(Loader.class);
@@ -34,7 +36,7 @@ public class CacheLoader extends Loader {
myRepositoryLoader = new RepositoryLoader(myCache);
}
- public void load(final RepositoryTreeNode node, final Expander expander) {
+ public void load(@NotNull final RepositoryTreeNode node, @NotNull final Expander expander) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
final String nodeUrl = node.getURL().toString();
@@ -53,15 +55,8 @@ public class CacheLoader extends Loader {
});
}
- public void forceRefresh(final String repositoryRootUrl) {
- myCache.clear(repositoryRootUrl);
- }
-
+ @NotNull
protected NodeLoadState getNodeLoadState() {
return NodeLoadState.CACHED;
}
-
- public Loader getRepositoryLoader() {
- return myRepositoryLoader;
- }
}
diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/browserCache/Loader.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/browserCache/Loader.java
index ab2b6ddb67f3..62d7ec10024a 100644
--- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/browserCache/Loader.java
+++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/browserCache/Loader.java
@@ -15,51 +15,52 @@
*/
package org.jetbrains.idea.svn.dialogs.browserCache;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.browse.DirectoryEntry;
import org.jetbrains.idea.svn.dialogs.RepositoryTreeNode;
import java.util.List;
public abstract class Loader {
- protected final SvnRepositoryCache myCache;
- protected Loader(final SvnRepositoryCache cache) {
+ @NotNull protected final SvnRepositoryCache myCache;
+
+ protected Loader(@NotNull SvnRepositoryCache cache) {
myCache = cache;
}
- public abstract void load(final RepositoryTreeNode node, final Expander afterRefreshExpander);
- public abstract void forceRefresh(final String repositoryRootUrl);
+ public abstract void load(@NotNull RepositoryTreeNode node, @NotNull Expander afterRefreshExpander);
+
+ @NotNull
protected abstract NodeLoadState getNodeLoadState();
- protected void refreshNodeError(final RepositoryTreeNode node, final String text) {
- if (node.isDisposed()) {
- return;
- }
- final RepositoryTreeNode existingNode = node.getNodeWithSamePathUnderModelRoot();
- if (existingNode == null) {
- return;
- }
- if (existingNode.isDisposed()) {
- return;
- }
+ protected void refreshNodeError(@NotNull RepositoryTreeNode node, @NotNull String text) {
+ RepositoryTreeNode existingNode = findExistingNode(node);
- existingNode.setErrorNode(text, getNodeLoadState());
+ if (existingNode != null) {
+ existingNode.setErrorNode(text);
+ }
}
- protected void refreshNode(final RepositoryTreeNode node, final List<DirectoryEntry> data, final Expander expander) {
- if (node.isDisposed()) {
- return;
- }
- final RepositoryTreeNode existingNode = node.getNodeWithSamePathUnderModelRoot();
- if (existingNode == null) {
- return;
+ protected void refreshNode(@NotNull RepositoryTreeNode node, @NotNull List<DirectoryEntry> data, @NotNull Expander expander) {
+ RepositoryTreeNode existingNode = findExistingNode(node);
+
+ if (existingNode != null) {
+ expander.onBeforeRefresh(existingNode);
+ existingNode.setChildren(data, getNodeLoadState());
+ expander.onAfterRefresh(existingNode);
}
+ }
- if (existingNode.isDisposed()) {
- return;
+ @Nullable
+ private static RepositoryTreeNode findExistingNode(@NotNull RepositoryTreeNode node) {
+ RepositoryTreeNode result = null;
+
+ if (!node.isDisposed()) {
+ result = node.getNodeWithSamePathUnderModelRoot();
}
- expander.onBeforeRefresh(existingNode);
- existingNode.setChildren(data, getNodeLoadState());
- expander.onAfterRefresh(existingNode);
+
+ return result == null || result.isDisposed() ? null : result;
}
}
diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/browserCache/RepositoryLoader.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/browserCache/RepositoryLoader.java
index 319699cfc1b8..6786d8648300 100644
--- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/browserCache/RepositoryLoader.java
+++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/browserCache/RepositoryLoader.java
@@ -21,6 +21,7 @@ import com.intellij.openapi.progress.EmptyProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vcs.VcsException;
+import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.svn.SvnVcs;
import org.jetbrains.idea.svn.api.Depth;
@@ -28,26 +29,29 @@ import org.jetbrains.idea.svn.auth.SvnAuthenticationProvider;
import org.jetbrains.idea.svn.browse.DirectoryEntry;
import org.jetbrains.idea.svn.browse.DirectoryEntryConsumer;
import org.jetbrains.idea.svn.dialogs.RepositoryTreeNode;
-import org.tmatesoft.svn.core.*;
+import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc2.SvnTarget;
import javax.swing.*;
-import java.util.*;
+import java.util.Collection;
+import java.util.List;
+import java.util.Queue;
+import java.util.TreeSet;
class RepositoryLoader extends Loader {
// may be several requests if: several same-level nodes are expanded simultaneosly; or browser can be opening into some expanded state
- private final Queue<Pair<RepositoryTreeNode, Expander>> myLoadQueue;
+ @NotNull private final Queue<Pair<RepositoryTreeNode, Expander>> myLoadQueue;
private boolean myQueueProcessorActive;
- RepositoryLoader(final SvnRepositoryCache cache) {
+ RepositoryLoader(@NotNull SvnRepositoryCache cache) {
super(cache);
- myLoadQueue = new LinkedList<Pair<RepositoryTreeNode, Expander>>();
+ myLoadQueue = ContainerUtil.newLinkedList();
myQueueProcessorActive = false;
}
- public void load(final RepositoryTreeNode node, final Expander afterRefreshExpander) {
+ public void load(@NotNull RepositoryTreeNode node, @NotNull Expander afterRefreshExpander) {
ApplicationManager.getApplication().assertIsDispatchThread();
final Pair<RepositoryTreeNode, Expander> data = Pair.create(node, afterRefreshExpander);
@@ -59,12 +63,12 @@ class RepositoryLoader extends Loader {
}
}
- private void setResults(final Pair<RepositoryTreeNode, Expander> data, final List<DirectoryEntry> children) {
+ private void setResults(@NotNull Pair<RepositoryTreeNode, Expander> data, @NotNull List<DirectoryEntry> children) {
myCache.put(data.first.getURL().toString(), children);
refreshNode(data.first, children, data.second);
}
- private void setError(final Pair<RepositoryTreeNode, Expander> data, final String message) {
+ private void setError(@NotNull Pair<RepositoryTreeNode, Expander> data, @NotNull String message) {
myCache.put(data.first.getURL().toString(), message);
refreshNodeError(data.first, message);
}
@@ -85,7 +89,7 @@ class RepositoryLoader extends Loader {
}
}
- private void startLoadTask(final Pair<RepositoryTreeNode, Expander> data) {
+ private void startLoadTask(@NotNull final Pair<RepositoryTreeNode, Expander> data) {
final ModalityState state = ModalityState.current();
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
@Override
@@ -101,18 +105,16 @@ class RepositoryLoader extends Loader {
});
}
- public void forceRefresh(final String repositoryRootUrl) {
- // ? remove
- }
-
+ @NotNull
protected NodeLoadState getNodeLoadState() {
return NodeLoadState.REFRESHED;
}
private class LoadTask implements Runnable {
- private final Pair<RepositoryTreeNode, Expander> myData;
- private LoadTask(final Pair<RepositoryTreeNode, Expander> data) {
+ @NotNull private final Pair<RepositoryTreeNode, Expander> myData;
+
+ private LoadTask(@NotNull Pair<RepositoryTreeNode, Expander> data) {
myData = data;
}
@@ -147,7 +149,7 @@ class RepositoryLoader extends Loader {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
- setResults(myData, new ArrayList<DirectoryEntry>(entries));
+ setResults(myData, ContainerUtil.newArrayList(entries));
startNext();
}
});
diff --git a/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/JiraRepository.java b/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/JiraRepository.java
index b8004ca70023..fa80fb161188 100644
--- a/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/JiraRepository.java
+++ b/plugins/tasks/tasks-core/jira/src/com/intellij/tasks/jira/JiraRepository.java
@@ -12,7 +12,6 @@ import com.intellij.tasks.Task;
import com.intellij.tasks.TaskBundle;
import com.intellij.tasks.TaskState;
import com.intellij.tasks.impl.BaseRepositoryImpl;
-import com.intellij.tasks.impl.TaskUtil;
import com.intellij.tasks.impl.gson.GsonUtil;
import com.intellij.tasks.jira.rest.JiraRestApi;
import com.intellij.tasks.jira.soap.JiraLegacyApi;
@@ -52,6 +51,7 @@ public class JiraRepository extends BaseRepositoryImpl {
private static final boolean REDISCOVER_API = Boolean.getBoolean("tasks.jira.rediscover.api");
public static final Pattern JIRA_ID_PATTERN = Pattern.compile("\\p{javaUpperCase}+-\\d+");
+ public static final String AUTH_COOKIE_NAME = "JSESSIONID";
/**
* Default JQL query
@@ -145,12 +145,13 @@ public class JiraRepository extends BaseRepositoryImpl {
@Nullable
@Override
public CancellableConnection createCancellableConnection() {
+ clearCookies();
// TODO cancellable connection for XML_RPC?
return new CancellableConnection() {
@Override
protected void doTest() throws Exception {
ensureApiVersionDiscovered();
- myApiVersion.findTasks("", 1);
+ myApiVersion.findTasks(mySearchQuery, 1);
}
@Override
@@ -226,20 +227,18 @@ public class JiraRepository extends BaseRepositoryImpl {
HttpClient client = getHttpClient();
// Fix for https://jetbrains.zendesk.com/agent/#/tickets/24566
// See https://confluence.atlassian.com/display/ONDEMANDKB/Getting+randomly+logged+out+of+OnDemand for details
- if (BASIC_AUTH_ONLY) {
+ // IDEA-128824, IDEA-128706 Use cookie authentication only for JIRA on-Demand
+ // TODO Make JiraVersion more suitable for such checks
+ final boolean isJiraOnDemand = StringUtil.notNullize(myJiraVersion).contains("OD");
+ if (isJiraOnDemand) {
+ LOG.info("Connecting to JIRA on-Demand. Cookie authentication is enabled unless 'tasks.jira.basic.auth.only' VM flag is used.");
+ }
+ if (BASIC_AUTH_ONLY || !isJiraOnDemand) {
// to override persisted settings
setUseHttpAuthentication(true);
}
else {
- boolean cookieAuthenticated = false;
- for (Cookie cookie : client.getState().getCookies()) {
- if (cookie.getName().equals("JSESSIONID") && !cookie.isExpired()) {
- cookieAuthenticated = true;
- break;
- }
- }
- // disable subsequent basic authorization attempts if user already was authenticated
- boolean enableBasicAuthentication = !(isRestApiSupported() && cookieAuthenticated);
+ boolean enableBasicAuthentication = !(isRestApiSupported() && containsCookie(client, AUTH_COOKIE_NAME));
if (enableBasicAuthentication != isUseHttpAuthentication()) {
LOG.info("Basic authentication for subsequent requests was " + (enableBasicAuthentication ? "enabled" : "disabled"));
}
@@ -251,14 +250,15 @@ public class JiraRepository extends BaseRepositoryImpl {
// may be null if 204 No Content received
final InputStream stream = method.getResponseBodyAsStream();
String entityContent = stream == null ? "" : StreamUtil.readText(stream, CharsetToolkit.UTF8);
- TaskUtil.prettyFormatJsonToLog(LOG, entityContent);
+ //TaskUtil.prettyFormatJsonToLog(LOG, entityContent);
// besides SC_OK, can also be SC_NO_CONTENT in issue transition requests
// see: JiraRestApi#setTaskStatus
//if (statusCode == HttpStatus.SC_OK || statusCode == HttpStatus.SC_NO_CONTENT) {
if (statusCode >= 200 && statusCode < 300) {
return entityContent;
}
- else if (method.getResponseHeader("Content-Type") != null) {
+ clearCookies();
+ if (method.getResponseHeader("Content-Type") != null) {
Header header = method.getResponseHeader("Content-Type");
if (header.getValue().startsWith("application/json")) {
JsonObject object = GSON.fromJson(entityContent, JsonObject.class);
@@ -284,6 +284,19 @@ public class JiraRepository extends BaseRepositoryImpl {
throw new Exception(TaskBundle.message("failure.http.error", statusCode, statusText));
}
+ private static boolean containsCookie(@NotNull HttpClient client, @NotNull String cookieName) {
+ for (Cookie cookie : client.getState().getCookies()) {
+ if (cookie.getName().equals(cookieName) && !cookie.isExpired()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void clearCookies() {
+ getHttpClient().getState().clearCookies();
+ }
+
// Made public for SOAP API compatibility
@Override
public HttpClient getHttpClient() {
diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/SwitchTaskCombo.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/SwitchTaskCombo.java
index f053f5012969..622c47dc552c 100644
--- a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/SwitchTaskCombo.java
+++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/SwitchTaskCombo.java
@@ -81,7 +81,7 @@ public class SwitchTaskCombo extends ComboBoxAction implements DumbAware {
public void update(AnActionEvent e) {
Project project = e.getData(CommonDataKeys.PROJECT);
Presentation presentation = e.getPresentation();
- if (project == null || project.isDisposed() || (ActionPlaces.MAIN_MENU.equals(e.getPlace()) && findFrame(e) == null)) {
+ if (project == null || project.isDisposed() || (ActionPlaces.isMainMenuOrActionSearch(e.getPlace()) && findFrame(e) == null)) {
presentation.setEnabled(false);
presentation.setText("");
presentation.setIcon(null);
diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/gitlab/GitlabRepository.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/gitlab/GitlabRepository.java
index cc66448c94e9..9df0eb07b26e 100644
--- a/plugins/tasks/tasks-core/src/com/intellij/tasks/gitlab/GitlabRepository.java
+++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/gitlab/GitlabRepository.java
@@ -4,7 +4,6 @@ import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.intellij.openapi.util.Comparing;
import com.intellij.tasks.Task;
-import com.intellij.tasks.TaskBundle;
import com.intellij.tasks.TaskRepositoryType;
import com.intellij.tasks.gitlab.model.GitlabIssue;
import com.intellij.tasks.gitlab.model.GitlabProject;
@@ -14,7 +13,9 @@ import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.xmlb.annotations.Tag;
import com.intellij.util.xmlb.annotations.Transient;
-import org.apache.http.*;
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpRequestInterceptor;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.protocol.HttpContext;
@@ -118,24 +119,7 @@ public class GitlabRepository extends NewBaseRepositoryImpl {
@Nullable
@Override
public CancellableConnection createCancellableConnection() {
- return new CancellableConnection() {
- private HttpGet myRequest = new HttpGet(getIssuesUrl());
-
- @Override
- protected void doTest() throws Exception {
- HttpResponse response = getHttpClient().execute(myRequest);
- StatusLine statusLine = response.getStatusLine();
- if (statusLine != null && statusLine.getStatusCode() != HttpStatus.SC_OK) {
- throw new Exception(TaskBundle.message("failure.http.error", statusLine.getStatusCode(), statusLine.getReasonPhrase()));
- }
- }
-
- // TODO: find more about proper request aborting in HttpClient4.x
- @Override
- public void cancel() {
- myRequest.abort();
- }
- };
+ return new HttpTestConnection(new HttpGet(getIssuesUrl()));
}
/**
diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/httpclient/NewBaseRepositoryImpl.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/httpclient/NewBaseRepositoryImpl.java
index c1648fc8f490..082d49812d5b 100644
--- a/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/httpclient/NewBaseRepositoryImpl.java
+++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/httpclient/NewBaseRepositoryImpl.java
@@ -3,6 +3,7 @@ package com.intellij.tasks.impl.httpclient;
import com.intellij.tasks.TaskRepositoryType;
import com.intellij.tasks.config.TaskSettings;
import com.intellij.tasks.impl.BaseRepository;
+import com.intellij.tasks.impl.RequestFailedException;
import com.intellij.tasks.impl.TaskUtil;
import com.intellij.util.net.HttpConfigurable;
import com.intellij.util.net.ssl.CertificateManager;
@@ -14,6 +15,7 @@ import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.AuthSchemes;
import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.impl.auth.BasicScheme;
@@ -154,4 +156,44 @@ public abstract class NewBaseRepositoryImpl extends BaseRepository {
}
}
}
+
+ public class HttpTestConnection extends CancellableConnection {
+
+ // Request can be changed during test
+ protected volatile HttpRequestBase myCurrentRequest;
+
+ public HttpTestConnection(@NotNull HttpRequestBase request) {
+ myCurrentRequest = request;
+ }
+
+ @Override
+ protected void doTest() throws Exception {
+ try {
+ test();
+ }
+ catch (IOException e) {
+ // Depending on request state AbstractExecutionAwareRequest.abort() can cause either
+ // * RequestAbortedException if connection was not yet leased
+ // * InterruptedIOException before reading response
+ // * SocketException("Socket closed") during reading response
+ // However in all cases 'aborted' flag should be properly set
+ if (!myCurrentRequest.isAborted()) {
+ throw e;
+ }
+ }
+ }
+
+ protected void test() throws Exception {
+ HttpResponse response = getHttpClient().execute(myCurrentRequest);
+ StatusLine statusLine = response.getStatusLine();
+ if (statusLine != null && statusLine.getStatusCode() != HttpStatus.SC_OK) {
+ throw RequestFailedException.forStatusCode(statusLine.getStatusCode(), statusLine.getReasonPhrase());
+ }
+ }
+
+ @Override
+ public void cancel() {
+ myCurrentRequest.abort();
+ }
+ }
}
diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/redmine/RedmineRepository.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/redmine/RedmineRepository.java
index e63b2b365e60..a4b10386aeba 100644
--- a/plugins/tasks/tasks-core/src/com/intellij/tasks/redmine/RedmineRepository.java
+++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/redmine/RedmineRepository.java
@@ -16,6 +16,7 @@ import com.intellij.util.xmlb.annotations.Tag;
import com.intellij.util.xmlb.annotations.Transient;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
+import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIBuilder;
@@ -23,6 +24,8 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
+import java.net.URI;
+import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -107,28 +110,36 @@ public class RedmineRepository extends NewBaseRepositoryImpl {
return new RedmineRepository(this);
}
+ @Nullable
@Override
- public void testConnection() throws Exception {
- // Strangely, Redmine doesn't return 401 or 403 error codes, if client sent wrong credentials, and instead
- // merely returns empty array of issues with status code of 200. This means that we should attempt to fetch
- // something more specific than issues to test proper configuration, e.g. current user information at
- // /users/current.json. Unfortunately this endpoint may be unavailable on some old servers (see IDEA-122845)
- // and in this case we have to come back to requesting issues in this case to test anything at all.
- HttpClient client = getHttpClient();
- URIBuilder uriBuilder = new URIBuilder(getRestApiUrl("users", "current.json"));
- if (isUseApiKeyAuthentication()) {
- uriBuilder.addParameter("key", getAPIKey());
- }
- HttpResponse response = client.execute(new HttpGet(uriBuilder.build()));
- //TaskUtil.prettyFormatResponseToLog(LOG, response);
- int code = response.getStatusLine().getStatusCode();
- if (code == HttpStatus.SC_NOT_FOUND) {
- getIssues("", 0, 1, true);
- return;
- }
- if (code != HttpStatus.SC_OK) {
- throw RequestFailedException.forStatusCode(code);
- }
+ public CancellableConnection createCancellableConnection() {
+ return new NewBaseRepositoryImpl.HttpTestConnection(new HttpGet()) {
+ @Override
+ protected void test() throws Exception {
+ // Strangely, Redmine doesn't return 401 or 403 error codes, if client sent wrong credentials, and instead
+ // merely returns empty array of issues with status code of 200. This means that we should attempt to fetch
+ // something more specific than issues to test proper configuration, e.g. current user information at
+ // /users/current.json. Unfortunately this endpoint may be unavailable on some old servers (see IDEA-122845)
+ // and in this case we have to come back to requesting issues in this case to test anything at all.
+
+ URIBuilder uriBuilder = new URIBuilder(getRestApiUrl("users", "current.json"));
+ if (isUseApiKeyAuthentication()) {
+ uriBuilder.addParameter("key", getAPIKey());
+ }
+ myCurrentRequest.setURI(uriBuilder.build());
+ HttpClient client = getHttpClient();
+
+ HttpResponse httpResponse = client.execute(myCurrentRequest);
+ StatusLine statusLine = httpResponse.getStatusLine();
+ if (statusLine != null && statusLine.getStatusCode() == HttpStatus.SC_NOT_FOUND) {
+ myCurrentRequest = new HttpGet(getIssuesUrl(0, 1, true));
+ statusLine = client.execute(myCurrentRequest).getStatusLine();
+ }
+ if (statusLine != null && statusLine.getStatusCode() != HttpStatus.SC_OK) {
+ throw RequestFailedException.forStatusCode(statusLine.getStatusCode(), statusLine.getReasonPhrase());
+ }
+ }
+ };
}
@Override
@@ -144,12 +155,6 @@ public class RedmineRepository extends NewBaseRepositoryImpl {
public List<RedmineIssue> fetchIssues(String query, int offset, int limit, boolean withClosed) throws Exception {
ensureProjectsDiscovered();
- URIBuilder builder = new URIBuilder(getRestApiUrl("issues.json"))
- .addParameter("offset", String.valueOf(offset))
- .addParameter("limit", String.valueOf(limit))
- .addParameter("status_id", withClosed ? "*" : "open")
- .addParameter("assigned_to_id", "me");
-
// Legacy API, can't find proper documentation
//if (StringUtil.isNotEmpty(query)) {
// builder.addParameter("fields[]", "subject").addParameter("operators[subject]", "~").addParameter("values[subject][]", query);
@@ -158,15 +163,24 @@ public class RedmineRepository extends NewBaseRepositoryImpl {
//if (myCurrentProject != null && myCurrentProject != UNSPECIFIED_PROJECT) {
// builder.addParameter("project_id", String.valueOf(myCurrentProject.getId()));
//}
- if (isUseApiKeyAuthentication()) {
- builder.addParameter("key", myAPIKey);
- }
HttpClient client = getHttpClient();
- HttpGet method = new HttpGet(builder.toString());
+ HttpGet method = new HttpGet(getIssuesUrl(offset, limit, withClosed));
IssuesWrapper wrapper = client.execute(method, new GsonSingleObjectDeserializer<IssuesWrapper>(GSON, IssuesWrapper.class));
return wrapper == null ? Collections.<RedmineIssue>emptyList() : wrapper.getIssues();
}
+ private URI getIssuesUrl(int offset, int limit, boolean withClosed) throws URISyntaxException {
+ URIBuilder builder = new URIBuilder(getRestApiUrl("issues.json"))
+ .addParameter("offset", String.valueOf(offset))
+ .addParameter("limit", String.valueOf(limit))
+ .addParameter("status_id", withClosed ? "*" : "open")
+ .addParameter("assigned_to_id", "me");
+ if (isUseApiKeyAuthentication()) {
+ builder.addParameter("key", myAPIKey);
+ }
+ return builder.build();
+ }
+
public List<RedmineProject> fetchProjects() throws Exception {
HttpClient client = getHttpClient();
// Download projects with pagination (IDEA-125056, IDEA-125157)
diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/redmine/model/RedmineIssue.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/redmine/model/RedmineIssue.java
index 07b5669a1540..aea41bdb6ca8 100644
--- a/plugins/tasks/tasks-core/src/com/intellij/tasks/redmine/model/RedmineIssue.java
+++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/redmine/model/RedmineIssue.java
@@ -19,7 +19,7 @@ public class RedmineIssue {
private IssueStatus status;
@Mandatory
private String subject;
- @Mandatory
+ // IDEA-126470 May be missing if issue was not created via web-interface
private String description;
@SerializedName("done_ratio")
private int doneRatio;
@@ -45,7 +45,7 @@ public class RedmineIssue {
return subject;
}
- @NotNull
+ @Nullable
public String getDescription() {
return description;
}
diff --git a/plugins/tasks/tasks-tests/test/com/intellij/tasks/integration/JiraIntegrationTest.java b/plugins/tasks/tasks-tests/test/com/intellij/tasks/integration/JiraIntegrationTest.java
index a849adb09c40..a3d99c33228c 100644
--- a/plugins/tasks/tasks-tests/test/com/intellij/tasks/integration/JiraIntegrationTest.java
+++ b/plugins/tasks/tasks-tests/test/com/intellij/tasks/integration/JiraIntegrationTest.java
@@ -119,14 +119,15 @@ public class JiraIntegrationTest extends TaskManagerTestCase {
}
}
- public void testBasicAuthenticationDisabling() throws Exception {
- assertTrue("Basic authentication should be enabled at first", myRepository.isUseHttpAuthentication());
- myRepository.findTask("PRJONE-1");
- assertFalse("Basic authentication should be disabled once JSESSIONID cookie was received", myRepository.isUseHttpAuthentication());
- HttpClient client = myRepository.getHttpClient();
- assertFalse(client.getParams().isAuthenticationPreemptive());
- assertNull(client.getState().getCredentials(AuthScope.ANY));
- }
+ // TODO move to on-Demand-specific tests
+ //public void testBasicAuthenticationDisabling() throws Exception {
+ // assertTrue("Basic authentication should be enabled at first", myRepository.isUseHttpAuthentication());
+ // myRepository.findTask("PRJONE-1");
+ // assertFalse("Basic authentication should be disabled once JSESSIONID cookie was received", myRepository.isUseHttpAuthentication());
+ // HttpClient client = myRepository.getHttpClient();
+ // assertFalse(client.getParams().isAuthenticationPreemptive());
+ // assertNull(client.getState().getCredentials(AuthScope.ANY));
+ //}
public void testSetTaskState() throws Exception {
changeStateAndCheck(JIRA_4_TEST_SERVER_URL, "PRJONE-8");
diff --git a/plugins/tasks/tasks-tests/test/com/intellij/tasks/integration/RedmineIntegrationTest.java b/plugins/tasks/tasks-tests/test/com/intellij/tasks/integration/RedmineIntegrationTest.java
index fa4d40dc2750..a14f48a4258e 100644
--- a/plugins/tasks/tasks-tests/test/com/intellij/tasks/integration/RedmineIntegrationTest.java
+++ b/plugins/tasks/tasks-tests/test/com/intellij/tasks/integration/RedmineIntegrationTest.java
@@ -21,11 +21,11 @@ public class RedmineIntegrationTest extends TaskManagerTestCase {
// with closed issues
Task[] found = myRepository.getIssues(null, 0, 25, true);
- assertEquals(4, found.length);
+ assertEquals(5, found.length);
// without closed issues
found = myRepository.getIssues(null, 0, 25, false);
- assertEquals(3, found.length);
+ assertEquals(4, found.length);
// unique summary
//found = myRepository.getIssues("baz", 0, 25, true);
@@ -64,14 +64,23 @@ public class RedmineIntegrationTest extends TaskManagerTestCase {
public void testCredentialsCheck() throws Exception {
myRepository.setPassword("wrong-password");
try {
- myRepository.testConnection();
- fail("testConnection() should fails, when wrong credentials specified");
+ //noinspection ConstantConditions
+ final Exception exception = myRepository.createCancellableConnection().call();
+ assertNotNull("Test connection must fail when wrong credentials specified", exception);
}
catch (Exception e) {
assertEquals(TaskBundle.message("failure.login"), e.getMessage());
}
}
+ // IDEA-126470
+ public void testIssueWithMissingDescription() throws Exception {
+ final Task issue = myRepository.findTask("8");
+ assertNotNull(issue);
+ assertNull(issue.getDescription());
+ assertEquals(issue.getSummary(), "Artificial issue with no description created via REST API. Do not update it!");
+ }
+
@Override
public void setUp() throws Exception {
super.setUp();
diff --git a/plugins/terminal/src/org/jetbrains/plugins/terminal/JBTerminalSystemSettingsProvider.java b/plugins/terminal/src/org/jetbrains/plugins/terminal/JBTerminalSystemSettingsProvider.java
index 12026184d4c4..dbc4ee5c13b6 100644
--- a/plugins/terminal/src/org/jetbrains/plugins/terminal/JBTerminalSystemSettingsProvider.java
+++ b/plugins/terminal/src/org/jetbrains/plugins/terminal/JBTerminalSystemSettingsProvider.java
@@ -48,12 +48,12 @@ import java.util.List;
/**
* @author traff
*/
-class JBTerminalSystemSettingsProvider extends DefaultTabbedSettingsProvider implements Disposable {
+public class JBTerminalSystemSettingsProvider extends DefaultTabbedSettingsProvider implements Disposable {
private Set<TerminalSettingsListener> myListeners = Sets.newHashSet();
private final MyColorSchemeDelegate myColorScheme;
- JBTerminalSystemSettingsProvider() {
+ public JBTerminalSystemSettingsProvider() {
myColorScheme = createBoundColorSchemeDelegate(null);
UISettings.getInstance().addUISettingsListener(new UISettingsListener() {
diff --git a/plugins/terminal/src/org/jetbrains/plugins/terminal/LocalTerminalDirectRunner.java b/plugins/terminal/src/org/jetbrains/plugins/terminal/LocalTerminalDirectRunner.java
index f67f84412a02..8a5f75b36594 100644
--- a/plugins/terminal/src/org/jetbrains/plugins/terminal/LocalTerminalDirectRunner.java
+++ b/plugins/terminal/src/org/jetbrains/plugins/terminal/LocalTerminalDirectRunner.java
@@ -59,7 +59,7 @@ public class LocalTerminalDirectRunner extends AbstractTerminalRunner<PtyProcess
}
}
catch (Exception e) {
- LOG.warn("Unable to get jar folder", e);
+ LOG.warn("Unable to get JAR folder", e);
}
return null;
}
diff --git a/plugins/testng/src/META-INF/plugin.xml b/plugins/testng/src/META-INF/plugin.xml
index 5fe0fb55b60f..711ace8ad744 100644
--- a/plugins/testng/src/META-INF/plugin.xml
+++ b/plugins/testng/src/META-INF/plugin.xml
@@ -14,6 +14,7 @@
<runConfigurationProducer implementation="com.theoryinpractice.testng.configuration.TestNGSuiteConfigurationProducer"/>
<configurationType implementation="com.theoryinpractice.testng.configuration.TestNGConfigurationType"/>
<psi.referenceContributor language="JAVA" implementation="com.theoryinpractice.testng.TestNGReferenceContributor"/>
+ <psi.referenceContributor language="Groovy" implementation="com.theoryinpractice.testng.TestNGReferenceContributor"/>
<psi.referenceContributor language="XML" implementation="com.theoryinpractice.testng.TestNGSuiteReferenceContributor"/>
<library.dependencyScopeSuggester implementation="com.theoryinpractice.testng.configuration.TestNGDependencyScopeSuggester"/>
diff --git a/plugins/testng/src/com/theoryinpractice/testng/TestNGReferenceContributor.java b/plugins/testng/src/com/theoryinpractice/testng/TestNGReferenceContributor.java
index 6e483fb97c3d..74bb548fcbbf 100644
--- a/plugins/testng/src/com/theoryinpractice/testng/TestNGReferenceContributor.java
+++ b/plugins/testng/src/com/theoryinpractice/testng/TestNGReferenceContributor.java
@@ -50,41 +50,41 @@ import java.util.ArrayList;
import java.util.List;
public class TestNGReferenceContributor extends PsiReferenceContributor {
- private static PsiElementPattern.Capture<PsiLiteralExpression> getElementPattern(String annotation) {
- return PlatformPatterns.psiElement(PsiLiteralExpression.class).and(new FilterPattern(new TestAnnotationFilter(annotation)));
+ private static PsiElementPattern.Capture<PsiLiteral> getElementPattern(String annotation) {
+ return PlatformPatterns.psiElement(PsiLiteral.class).and(new FilterPattern(new TestAnnotationFilter(annotation)));
}
public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) {
registrar.registerReferenceProvider(getElementPattern("dependsOnMethods"), new PsiReferenceProvider() {
@NotNull
public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull final ProcessingContext context) {
- return new MethodReference[]{new MethodReference((PsiLiteralExpression)element)};
+ return new MethodReference[]{new MethodReference((PsiLiteral)element)};
}
});
registrar.registerReferenceProvider(getElementPattern("dataProvider"), new PsiReferenceProvider() {
@NotNull
public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull final ProcessingContext context) {
- return new DataProviderReference[]{new DataProviderReference((PsiLiteralExpression)element)};
+ return new DataProviderReference[]{new DataProviderReference((PsiLiteral)element)};
}
});
registrar.registerReferenceProvider(getElementPattern("groups"), new PsiReferenceProvider() {
@NotNull
public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull final ProcessingContext context) {
- return new GroupReference[]{new GroupReference(element.getProject(), (PsiLiteralExpression)element)};
+ return new GroupReference[]{new GroupReference(element.getProject(), (PsiLiteral)element)};
}
});
registrar.registerReferenceProvider(getElementPattern("dependsOnGroups"), new PsiReferenceProvider() {
@NotNull
public PsiReference[] getReferencesByElement(@NotNull PsiElement element, @NotNull final ProcessingContext context) {
- return new GroupReference[]{new GroupReference(element.getProject(), (PsiLiteralExpression)element)};
+ return new GroupReference[]{new GroupReference(element.getProject(), (PsiLiteral)element)};
}
});
}
- private static class DataProviderReference extends PsiReferenceBase<PsiLiteralExpression> {
+ private static class DataProviderReference extends PsiReferenceBase<PsiLiteral> {
- public DataProviderReference(PsiLiteralExpression element) {
+ public DataProviderReference(PsiLiteral element) {
super(element, false);
}
@@ -156,9 +156,9 @@ public class TestNGReferenceContributor extends PsiReferenceContributor {
}
}
- private static class MethodReference extends PsiReferenceBase<PsiLiteralExpression> {
+ private static class MethodReference extends PsiReferenceBase<PsiLiteral> {
- public MethodReference(PsiLiteralExpression element) {
+ public MethodReference(PsiLiteral element) {
super(element, false);
}
@@ -181,7 +181,7 @@ public class TestNGReferenceContributor extends PsiReferenceContributor {
@Nullable
private PsiClass getDependsClass(String val) {
final String className = StringUtil.getPackageName(val);
- final PsiLiteralExpression element = getElement();
+ final PsiLiteral element = getElement();
return StringUtil.isEmpty(className) ? PsiUtil.getTopLevelClass(element)
: JavaPsiFacade.getInstance(element.getProject()).findClass(className, element.getResolveScope());
}
@@ -213,10 +213,10 @@ public class TestNGReferenceContributor extends PsiReferenceContributor {
}
}
- private static class GroupReference extends PsiReferenceBase<PsiLiteralExpression> {
+ private static class GroupReference extends PsiReferenceBase<PsiLiteral> {
private final Project myProject;
- public GroupReference(Project project, PsiLiteralExpression element) {
+ public GroupReference(Project project, PsiLiteral element) {
super(element, false);
myProject = project;
}
@@ -264,7 +264,7 @@ public class TestNGReferenceContributor extends PsiReferenceContributor {
}
public boolean isClassAcceptable(Class hintClass) {
- return PsiLiteralExpression.class.isAssignableFrom(hintClass);
+ return PsiLiteral.class.isAssignableFrom(hintClass);
}
}
}
diff --git a/plugins/testng/src/com/theoryinpractice/testng/configuration/SearchingForTestsTask.java b/plugins/testng/src/com/theoryinpractice/testng/configuration/SearchingForTestsTask.java
index 2258b16a7a2a..8358fcd253dd 100644
--- a/plugins/testng/src/com/theoryinpractice/testng/configuration/SearchingForTestsTask.java
+++ b/plugins/testng/src/com/theoryinpractice/testng/configuration/SearchingForTestsTask.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2010 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -646,6 +646,7 @@ public class SearchingForTestsTask extends Task.Backgroundable {
return result;
}
+ @NotNull
private GlobalSearchScope getSearchScope() {
final TestData data = myConfig.getPersistantData();
final Module module = myConfig.getConfigurationModule().getModule();
diff --git a/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGRunnableState.java b/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGRunnableState.java
index 0c73ae5f5761..6579990d4184 100644
--- a/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGRunnableState.java
+++ b/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGRunnableState.java
@@ -14,12 +14,6 @@
* limitations under the License.
*/
-/*
- * Created by IntelliJ IDEA.
- * User: amrk
- * Date: Jul 2, 2005
- * Time: 12:22:07 AM
- */
package com.theoryinpractice.testng.configuration;
import com.intellij.ExtensionPoints;
@@ -40,7 +34,7 @@ import com.intellij.execution.ui.ConsoleViewContentType;
import com.intellij.execution.util.JavaParametersUtil;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.Extensions;
-import com.intellij.openapi.module.LanguageLevelUtil;
+import com.intellij.openapi.module.EffectiveLanguageLevelUtil;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.impl.BackgroundableProcessIndicator;
@@ -77,7 +71,6 @@ import org.testng.remote.RemoteArgs;
import org.testng.remote.RemoteTestNG;
import org.testng.remote.strprotocol.SerializedMessageSender;
-import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
@@ -98,7 +91,7 @@ public class TestNGRunnableState extends JavaCommandLineState {
public TestNGRunnableState(ExecutionEnvironment environment, TestNGConfiguration config) {
super(environment);
- this.runnerSettings = environment.getRunnerSettings();
+ runnerSettings = environment.getRunnerSettings();
this.config = config;
//TODO need to narrow this down a bit
//setModulesToCompile(ModuleManager.getInstance(config.getProject()).getModules());
@@ -120,6 +113,7 @@ public class TestNGRunnableState extends JavaCommandLineState {
}
}
+ @NotNull
@Override
public ExecutionResult execute(@NotNull final Executor executor, @NotNull final ProgramRunner runner) throws ExecutionException {
final boolean smRunner = Registry.is("testng_sm_runner");
@@ -173,6 +167,7 @@ public class TestNGRunnableState extends JavaCommandLineState {
final String text = event.getText();
final ConsoleViewContentType consoleViewType = ConsoleViewContentType.getConsoleViewType(outputType);
final Printable printable = new Printable() {
+ @Override
public void printOn(final Printer printer) {
printer.print(text, consoleViewType);
}
@@ -188,9 +183,9 @@ public class TestNGRunnableState extends JavaCommandLineState {
});
console.attachToProcess(processHandler);
- RerunFailedTestsAction rerunFailedTestsAction = new RerunFailedTestsAction(console);
- rerunFailedTestsAction.init(console.getProperties(), getEnvironment());
+ RerunFailedTestsAction rerunFailedTestsAction = new RerunFailedTestsAction(console, console.getProperties());
rerunFailedTestsAction.setModelProvider(new Getter<TestFrameworkRunningModel>() {
+ @Override
public TestFrameworkRunningModel get() {
return console.getResultsView();
}
@@ -218,8 +213,7 @@ public class TestNGRunnableState extends JavaCommandLineState {
Disposer.register(getEnvironment().getProject(), smtConsoleView);
smtConsoleView.attachToProcess(handler);
- final RerunFailedTestsAction rerunFailedTestsAction = new RerunFailedTestsAction(smtConsoleView);
- rerunFailedTestsAction.init(testConsoleProperties, getEnvironment());
+ final RerunFailedTestsAction rerunFailedTestsAction = new RerunFailedTestsAction(smtConsoleView, testConsoleProperties);
rerunFailedTestsAction.setModelProvider(new Getter<TestFrameworkRunningModel>() {
@Override
public TestFrameworkRunningModel get() {
@@ -264,7 +258,7 @@ public class TestNGRunnableState extends JavaCommandLineState {
Module module = config.getConfigurationModule().getModule();
LanguageLevel effectiveLanguageLevel = module == null
? LanguageLevelProjectExtension.getInstance(project).getLanguageLevel()
- : LanguageLevelUtil.getEffectiveLanguageLevel(module);
+ : EffectiveLanguageLevelUtil.getEffectiveLanguageLevel(module);
final boolean is15 = effectiveLanguageLevel != LanguageLevel.JDK_1_4 && effectiveLanguageLevel != LanguageLevel.JDK_1_3;
LOG.info("Language level is " + effectiveLanguageLevel.toString());
@@ -311,7 +305,7 @@ public class TestNGRunnableState extends JavaCommandLineState {
javaParameters.getProgramParametersList().add(supportSerializationProtocol(config) ? RemoteArgs.PORT : CommandLineArgs.PORT, String.valueOf(port));
- if (data.getOutputDirectory() != null && !"".equals(data.getOutputDirectory())) {
+ if (data.getOutputDirectory() != null && !data.getOutputDirectory().isEmpty()) {
javaParameters.getProgramParametersList().add(CommandLineArgs.OUTPUT_DIRECTORY, data.getOutputDirectory());
}
@@ -379,7 +373,7 @@ public class TestNGRunnableState extends JavaCommandLineState {
try {
hostname = InetAddress.getLocalHost().getHostName();
}
- catch (UnknownHostException e) {
+ catch (UnknownHostException ignored) {
}
params.add("-Xdebug");
params.add("-Xrunjdwp:transport=dt_socket,address=" + hostname + ':' + debugPort + ",suspend=y,server=n");
diff --git a/plugins/testng/src/com/theoryinpractice/testng/model/TestProxy.java b/plugins/testng/src/com/theoryinpractice/testng/model/TestProxy.java
index a7d29ce4de98..b5e24707bba7 100644
--- a/plugins/testng/src/com/theoryinpractice/testng/model/TestProxy.java
+++ b/plugins/testng/src/com/theoryinpractice/testng/model/TestProxy.java
@@ -292,7 +292,7 @@ public class TestProxy extends AbstractTestProxy {
if (myHyperlink == null) {
return null;
}
- return new AssertEqualsDiffViewerProvider() {
+ return new AssertEqualsMultiDiffViewProvider() {
@Override
public void openDiff(Project project) {
myHyperlink.openDiff(project);
@@ -307,6 +307,16 @@ public class TestProxy extends AbstractTestProxy {
public String getActual() {
return myHyperlink.getRight();
}
+
+ @Override
+ public void openMultiDiff(Project project, AssertEqualsDiffChain chain) {
+ myHyperlink.openMultiDiff(project, chain);
+ }
+
+ @Override
+ public String getFilePath() {
+ return myHyperlink.getFilePath();
+ }
};
}
diff --git a/plugins/testng/src/com/theoryinpractice/testng/ui/actions/RerunFailedTestsAction.java b/plugins/testng/src/com/theoryinpractice/testng/ui/actions/RerunFailedTestsAction.java
index 597bb5983876..0c6eea9af3e8 100644
--- a/plugins/testng/src/com/theoryinpractice/testng/ui/actions/RerunFailedTestsAction.java
+++ b/plugins/testng/src/com/theoryinpractice/testng/ui/actions/RerunFailedTestsAction.java
@@ -1,13 +1,14 @@
package com.theoryinpractice.testng.ui.actions;
import com.intellij.execution.CantRunException;
-import com.intellij.execution.ExecutionException;
import com.intellij.execution.Executor;
import com.intellij.execution.Location;
import com.intellij.execution.actions.JavaRerunFailedTestsAction;
import com.intellij.execution.configurations.RunProfileState;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.testframework.AbstractTestProxy;
+import com.intellij.execution.testframework.SourceScope;
+import com.intellij.execution.testframework.TestConsoleProperties;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
@@ -30,23 +31,23 @@ import java.net.ServerSocket;
import java.util.*;
public class RerunFailedTestsAction extends JavaRerunFailedTestsAction {
-
- public RerunFailedTestsAction(@NotNull ComponentContainer componentContainer) {
- super(componentContainer);
+ public RerunFailedTestsAction(@NotNull ComponentContainer componentContainer, @NotNull TestConsoleProperties consoleProperties) {
+ super(componentContainer, consoleProperties);
}
@Override
- public MyRunProfile getRunProfile() {
+ protected MyRunProfile getRunProfile(@NotNull ExecutionEnvironment environment) {
final TestNGConfiguration configuration = (TestNGConfiguration)getModel().getProperties().getConfiguration();
final List<AbstractTestProxy> failedTests = getFailedTests(configuration.getProject());
return new MyRunProfile(configuration) {
+ @Override
@NotNull
public Module[] getModules() {
- return Module.EMPTY_ARRAY;
+ return configuration.getModules();
}
- public RunProfileState getState(@NotNull Executor executor, @NotNull ExecutionEnvironment env) throws ExecutionException {
-
+ @Override
+ public RunProfileState getState(@NotNull Executor executor, @NotNull ExecutionEnvironment env) {
return new TestNGRunnableState(env, configuration) {
@Override
protected SearchingForTestsTask createSearchingForTestsTask(ServerSocket serverSocket,
@@ -99,5 +100,4 @@ public class RerunFailedTestsAction extends JavaRerunFailedTestsAction {
}
};
}
-
}
diff --git a/plugins/ui-designer-core/src/com/intellij/designer/AbstractToolWindowManager.java b/plugins/ui-designer-core/src/com/intellij/designer/AbstractToolWindowManager.java
index cf0961c6feaf..b936ae2814b3 100644
--- a/plugins/ui-designer-core/src/com/intellij/designer/AbstractToolWindowManager.java
+++ b/plugins/ui-designer-core/src/com/intellij/designer/AbstractToolWindowManager.java
@@ -15,122 +15,24 @@
*/
package com.intellij.designer;
-import com.intellij.designer.designSurface.DesignerEditorPanel;
-import com.intellij.ide.util.PropertiesComponent;
-import com.intellij.openapi.actionSystem.ActionGroup;
-import com.intellij.openapi.actionSystem.AnAction;
-import com.intellij.openapi.actionSystem.DefaultActionGroup;
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.components.ProjectComponent;
+import com.intellij.designer.palette.PaletteToolWindowManager;
import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.fileEditor.FileEditorManager;
-import com.intellij.openapi.fileEditor.FileEditorManagerEvent;
-import com.intellij.openapi.fileEditor.FileEditorManagerListener;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.startup.StartupManager;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowAnchor;
-import com.intellij.openapi.wm.ex.ToolWindowEx;
-import com.intellij.util.ParameterizedRunnable;
-import com.intellij.util.messages.MessageBusConnection;
-import com.intellij.util.ui.update.MergingUpdateQueue;
-import com.intellij.util.ui.update.Update;
-import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import javax.swing.*;
-
/**
* @author Alexander Lobas
*/
-public abstract class AbstractToolWindowManager implements ProjectComponent {
- public static final String EDITOR_MODE = "UI_DESIGNER_EDITOR_MODE.";
-
- private final MergingUpdateQueue myWindowQueue = new MergingUpdateQueue(getComponentName(), 200, true, null);
- protected final Project myProject;
- protected final FileEditorManager myFileEditorManager;
- protected volatile ToolWindow myToolWindow;
- private volatile boolean myToolWindowReady;
- private volatile boolean myToolWindowDisposed;
-
- private final PropertiesComponent myPropertiesComponent;
- public final String myEditorModeKey;
- private ToggleEditorModeAction myLeftEditorModeAction;
- private ToggleEditorModeAction myRightEditorModeAction;
-
- private MessageBusConnection myConnection;
- private final FileEditorManagerListener myListener = new FileEditorManagerListener() {
- @Override
- public void fileOpened(@NotNull FileEditorManager source, @NotNull VirtualFile file) {
- bindToDesigner(getActiveDesigner());
- }
-
- @Override
- public void fileClosed(@NotNull FileEditorManager source, @NotNull VirtualFile file) {
- ApplicationManager.getApplication().invokeLater(new Runnable() {
- @Override
- public void run() {
- bindToDesigner(getActiveDesigner());
- }
- });
- }
-
- @Override
- public void selectionChanged(@NotNull FileEditorManagerEvent event) {
- bindToDesigner(getDesigner(event.getNewEditor()));
- }
- };
-
- //////////////////////////////////////////////////////////////////////////////////////////
- //
- // ToolWindow
- //
- //////////////////////////////////////////////////////////////////////////////////////////
-
+public abstract class AbstractToolWindowManager extends LightToolWindowManager {
protected AbstractToolWindowManager(Project project, FileEditorManager fileEditorManager) {
- myProject = project;
- myFileEditorManager = fileEditorManager;
- myPropertiesComponent = PropertiesComponent.getInstance(myProject);
- myEditorModeKey = EDITOR_MODE + getComponentName() + ".STATE";
- }
-
- @Override
- public void projectOpened() {
- initToolWindow();
-
- StartupManager.getInstance(myProject).registerPostStartupActivity(new Runnable() {
- public void run() {
- myToolWindowReady = true;
- if (getEditorMode() == null) {
- initListeners();
- bindToDesigner(getActiveDesigner());
- }
- }
- });
- }
-
- @Override
- public void projectClosed() {
- if (!myToolWindowDisposed) {
- disposeComponent();
- myToolWindowDisposed = true;
- myToolWindow = null;
- }
- }
-
- private void initListeners() {
- myConnection = myProject.getMessageBus().connect(myProject);
- myConnection.subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, myListener);
- }
-
- private void removeListeners() {
- myConnection.disconnect();
- myConnection = null;
+ super(project, fileEditorManager);
}
@Nullable
- private static DesignerEditorPanel getDesigner(FileEditor editor) {
+ @Override
+ protected DesignerEditorPanelFacade getDesigner(FileEditor editor) {
if (editor instanceof DesignerEditor) {
DesignerEditor designerEditor = (DesignerEditor)editor;
return designerEditor.getDesignerPanel();
@@ -138,196 +40,20 @@ public abstract class AbstractToolWindowManager implements ProjectComponent {
return null;
}
- @Nullable
- public DesignerEditorPanel getActiveDesigner() {
- for (FileEditor editor : myFileEditorManager.getSelectedEditors()) {
- DesignerEditorPanel designer = getDesigner(editor);
- if (designer != null) {
- return designer;
+ @Override
+ protected ToggleEditorModeAction createToggleAction(ToolWindowAnchor anchor) {
+ return new ToggleEditorModeAction(this, myProject, anchor) {
+ @Override
+ protected LightToolWindowManager getOppositeManager() {
+ AbstractToolWindowManager designerManager = DesignerToolWindowManager.getInstance(myProject);
+ AbstractToolWindowManager paletteManager = PaletteToolWindowManager.getInstance(myProject);
+ return myManager == designerManager ? paletteManager : designerManager;
}
- }
-
- return null;
+ };
}
@Nullable
protected static DesignerCustomizations getCustomizations() {
return DesignerCustomizations.EP_NAME.findExtension(DesignerCustomizations.class);
}
-
- private void bindToDesigner(final DesignerEditorPanel designer) {
- myWindowQueue.cancelAllUpdates();
- myWindowQueue.queue(new Update("update") {
- @Override
- public void run() {
- if (!myToolWindowReady || myToolWindowDisposed) {
- return;
- }
- if (myToolWindow == null) {
- if (designer == null) {
- return;
- }
- initToolWindow();
- }
- updateToolWindow(designer);
- }
- });
- }
-
- protected abstract void initToolWindow();
-
- protected abstract void updateToolWindow(@Nullable DesignerEditorPanel designer);
-
- protected final void initGearActions() {
- ToolWindowEx toolWindow = (ToolWindowEx)myToolWindow;
- toolWindow.setAdditionalGearActions(new DefaultActionGroup(createGearActions()));
- }
-
- protected abstract ToolWindowAnchor getAnchor();
-
- @Override
- public void initComponent() {
- }
-
- @Override
- public void disposeComponent() {
- }
-
- //////////////////////////////////////////////////////////////////////////////////////////
- //
- // LightToolWindow
- //
- //////////////////////////////////////////////////////////////////////////////////////////
-
- public final ActionGroup createGearActions() {
- DefaultActionGroup group = new DefaultActionGroup("In Editor Mode", true);
-
- if (myLeftEditorModeAction == null) {
- myLeftEditorModeAction = new ToggleEditorModeAction(this, myProject, ToolWindowAnchor.LEFT);
- }
- group.add(myLeftEditorModeAction);
-
- if (myRightEditorModeAction == null) {
- myRightEditorModeAction = new ToggleEditorModeAction(this, myProject, ToolWindowAnchor.RIGHT);
- }
- group.add(myRightEditorModeAction);
-
- return group;
- }
-
- public final void bind(DesignerEditorPanel designer) {
- if (isEditorMode()) {
- myCreateAction.run(designer);
- }
- }
-
- public final void dispose(DesignerEditorPanel designer) {
- if (isEditorMode()) {
- disposeContent(designer);
- }
- }
-
- protected final Object getContent(DesignerEditorPanel designer) {
- LightToolWindow toolWindow = (LightToolWindow)designer.getClientProperty(getComponentName());
- return toolWindow.getContent();
- }
-
- protected abstract LightToolWindow createContent(DesignerEditorPanel designer);
-
- protected final LightToolWindow createContent(DesignerEditorPanel designer,
- LightToolWindowContent content,
- String title,
- Icon icon,
- JComponent component,
- JComponent focusedComponent,
- int defaultWidth,
- AnAction[] actions) {
- return new LightToolWindow(content,
- title,
- icon,
- component,
- focusedComponent,
- designer.getContentSplitter(),
- getEditorMode(),
- this,
- myProject,
- myPropertiesComponent,
- getComponentName(),
- defaultWidth,
- actions);
- }
-
- protected final void disposeContent(DesignerEditorPanel designer) {
- String key = getComponentName();
- LightToolWindow toolWindow = (LightToolWindow)designer.getClientProperty(key);
- designer.putClientProperty(key, null);
- toolWindow.dispose();
- }
-
- private final ParameterizedRunnable<DesignerEditorPanel> myCreateAction = new ParameterizedRunnable<DesignerEditorPanel>() {
- @Override
- public void run(DesignerEditorPanel designer) {
- designer.putClientProperty(getComponentName(), createContent(designer));
- }
- };
-
- private final ParameterizedRunnable<DesignerEditorPanel> myUpdateAnchorAction = new ParameterizedRunnable<DesignerEditorPanel>() {
- @Override
- public void run(DesignerEditorPanel designer) {
- LightToolWindow toolWindow = (LightToolWindow)designer.getClientProperty(getComponentName());
- toolWindow.updateAnchor(getEditorMode());
- }
- };
-
- private final ParameterizedRunnable<DesignerEditorPanel> myDisposeAction = new ParameterizedRunnable<DesignerEditorPanel>() {
- @Override
- public void run(DesignerEditorPanel designer) {
- disposeContent(designer);
- }
- };
-
- private void runUpdateContent(ParameterizedRunnable<DesignerEditorPanel> action) {
- for (FileEditor editor : myFileEditorManager.getAllEditors()) {
- DesignerEditorPanel designer = getDesigner(editor);
- if (designer != null) {
- action.run(designer);
- }
- }
- }
-
- protected final boolean isEditorMode() {
- return getEditorMode() != null;
- }
-
- @Nullable
- final ToolWindowAnchor getEditorMode() {
- String value = myPropertiesComponent.getValue(myEditorModeKey);
- if (value == null) {
- return getAnchor();
- }
- return value.equals("ToolWindow") ? null : ToolWindowAnchor.fromText(value);
- }
-
- final void setEditorMode(@Nullable ToolWindowAnchor newState) {
- ToolWindowAnchor oldState = getEditorMode();
- myPropertiesComponent.setValue(myEditorModeKey, newState == null ? "ToolWindow" : newState.toString());
-
- if (oldState != null && newState != null) {
- runUpdateContent(myUpdateAnchorAction);
- }
- else if (newState != null) {
- removeListeners();
- updateToolWindow(null);
- runUpdateContent(myCreateAction);
- }
- else {
- runUpdateContent(myDisposeAction);
- initListeners();
- bindToDesigner(getActiveDesigner());
- }
- }
-
- final ToolWindow getToolWindow() {
- return myToolWindow;
- }
} \ No newline at end of file
diff --git a/plugins/ui-designer-core/src/com/intellij/designer/DesignerToolWindowManager.java b/plugins/ui-designer-core/src/com/intellij/designer/DesignerToolWindowManager.java
index 8c5fa6412e04..a35be4d28697 100644
--- a/plugins/ui-designer-core/src/com/intellij/designer/DesignerToolWindowManager.java
+++ b/plugins/ui-designer-core/src/com/intellij/designer/DesignerToolWindowManager.java
@@ -96,8 +96,8 @@ public final class DesignerToolWindowManager extends AbstractToolWindowManager {
}
@Override
- protected void updateToolWindow(@Nullable DesignerEditorPanel designer) {
- myToolWindowContent.update(designer);
+ protected void updateToolWindow(@Nullable DesignerEditorPanelFacade designer) {
+ myToolWindowContent.update((DesignerEditorPanel)designer);
if (designer == null) {
myToolWindow.setAvailable(false, null);
@@ -126,9 +126,9 @@ public final class DesignerToolWindowManager extends AbstractToolWindowManager {
//////////////////////////////////////////////////////////////////////////////////////////
@Override
- protected LightToolWindow createContent(DesignerEditorPanel designer) {
+ protected LightToolWindow createContent(@NotNull DesignerEditorPanelFacade designer) {
DesignerToolWindow toolWindowContent = new DesignerToolWindow(myProject, false);
- toolWindowContent.update(designer);
+ toolWindowContent.update((DesignerEditorPanel)designer);
return createContent(designer,
toolWindowContent,
diff --git a/plugins/ui-designer-core/src/com/intellij/designer/PaletteToolWindowContent.java b/plugins/ui-designer-core/src/com/intellij/designer/PaletteToolWindowContent.java
index 5e77e7c0b02d..69949491991a 100644
--- a/plugins/ui-designer-core/src/com/intellij/designer/PaletteToolWindowContent.java
+++ b/plugins/ui-designer-core/src/com/intellij/designer/PaletteToolWindowContent.java
@@ -15,19 +15,8 @@
*/
package com.intellij.designer;
-import com.intellij.designer.designSurface.DesignerEditorPanel;
-import com.intellij.designer.palette.PaletteItem;
-import org.jetbrains.annotations.Nullable;
-
public interface PaletteToolWindowContent extends LightToolWindowContent {
- @Nullable
- PaletteItem getActiveItem();
-
void clearActiveItem();
void refresh();
-
- boolean isEmpty();
-
- void loadPalette(@Nullable DesignerEditorPanel designer);
} \ No newline at end of file
diff --git a/plugins/ui-designer-core/src/com/intellij/designer/designSurface/DesignerEditorPanel.java b/plugins/ui-designer-core/src/com/intellij/designer/designSurface/DesignerEditorPanel.java
index 067924556325..87f9e2cb3332 100644
--- a/plugins/ui-designer-core/src/com/intellij/designer/designSurface/DesignerEditorPanel.java
+++ b/plugins/ui-designer-core/src/com/intellij/designer/designSurface/DesignerEditorPanel.java
@@ -78,7 +78,8 @@ import java.util.List;
/**
* @author Alexander Lobas
*/
-public abstract class DesignerEditorPanel extends JPanel implements DataProvider, ModuleProvider, RadPropertyContext {
+public abstract class DesignerEditorPanel extends JPanel
+ implements DesignerEditorPanelFacade, DataProvider, ModuleProvider, RadPropertyContext {
private static final Logger LOG = Logger.getInstance("#com.intellij.designer.designSurface.DesignerEditorPanel");
protected static final Integer LAYER_COMPONENT = JLayeredPane.DEFAULT_LAYER;
@@ -176,7 +177,7 @@ public abstract class DesignerEditorPanel extends JPanel implements DataProvider
}
private void createDesignerCard() {
- JPanel panel = new JPanel(new FillLayout());
+ JPanel panel = new JPanel(new LightFillLayout());
myContentSplitter.setInnerComponent(panel);
myLayeredPane = new MyLayeredPane();
@@ -858,103 +859,6 @@ public abstract class DesignerEditorPanel extends JPanel implements DataProvider
//
//////////////////////////////////////////////////////////////////////////////////////////
- private static final int MINIMIZE_WIDTH = 25;
-
- private static final class FillLayout implements LayoutManager2 {
- @Override
- public void addLayoutComponent(Component comp, Object constraints) {
- }
-
- @Override
- public float getLayoutAlignmentX(Container target) {
- return 0.5f;
- }
-
- @Override
- public float getLayoutAlignmentY(Container target) {
- return 0.5f;
- }
-
- @Override
- public void invalidateLayout(Container target) {
- }
-
- @Override
- public void addLayoutComponent(String name, Component comp) {
- }
-
- @Override
- public void removeLayoutComponent(Component comp) {
- }
-
- @Override
- public Dimension maximumLayoutSize(Container target) {
- return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
- }
-
- @Override
- public Dimension preferredLayoutSize(Container parent) {
- Component toolbar = parent.getComponent(0);
- Dimension toolbarSize = toolbar.isVisible() ? toolbar.getPreferredSize() : new Dimension();
- Dimension contentSize = parent.getComponent(1).getPreferredSize();
- int extraWidth = 0;
- JComponent jParent = (JComponent)parent;
- if (jParent.getClientProperty(LightToolWindow.LEFT_MIN_KEY) != null) {
- extraWidth += MINIMIZE_WIDTH;
- }
- if (jParent.getClientProperty(LightToolWindow.RIGHT_MIN_KEY) != null) {
- extraWidth += MINIMIZE_WIDTH;
- }
- return new Dimension(Math.max(toolbarSize.width, contentSize.width + extraWidth), toolbarSize.height + contentSize.height);
- }
-
- @Override
- public Dimension minimumLayoutSize(Container parent) {
- Component toolbar = parent.getComponent(0);
- Dimension toolbarSize = toolbar.isVisible() ? toolbar.getMinimumSize() : new Dimension();
- Dimension contentSize = parent.getComponent(1).getMinimumSize();
- int extraWidth = 0;
- JComponent jParent = (JComponent)parent;
- if (jParent.getClientProperty(LightToolWindow.LEFT_MIN_KEY) != null) {
- extraWidth += MINIMIZE_WIDTH;
- }
- if (jParent.getClientProperty(LightToolWindow.RIGHT_MIN_KEY) != null) {
- extraWidth += MINIMIZE_WIDTH;
- }
- return new Dimension(Math.max(toolbarSize.width, contentSize.width + extraWidth), toolbarSize.height + contentSize.height);
- }
-
- @Override
- public void layoutContainer(Container parent) {
- int leftWidth = 0;
- int rightWidth = 0;
- JComponent jParent = (JComponent)parent;
- JComponent left = (JComponent)jParent.getClientProperty(LightToolWindow.LEFT_MIN_KEY);
- if (left != null) {
- leftWidth = MINIMIZE_WIDTH;
- }
- JComponent right = (JComponent)jParent.getClientProperty(LightToolWindow.RIGHT_MIN_KEY);
- if (right != null) {
- rightWidth = MINIMIZE_WIDTH;
- }
- int extraWidth = leftWidth + rightWidth;
-
- int width = parent.getWidth() - extraWidth;
- int height = parent.getHeight();
- Component toolbar = parent.getComponent(0);
- Dimension toolbarSize = toolbar.isVisible() ? toolbar.getPreferredSize() : new Dimension();
- toolbar.setBounds(leftWidth, 0, width, toolbarSize.height);
- parent.getComponent(1).setBounds(leftWidth, toolbarSize.height, width, height - toolbarSize.height);
-
- if (left != null) {
- left.setBounds(0, 0, leftWidth, height);
- }
- if (right != null) {
- right.setBounds(width + leftWidth, 0, rightWidth, height);
- }
- }
- }
-
/**
* Size of the scene, in scroll pane view port pixels.
*/
diff --git a/plugins/ui-designer-core/src/com/intellij/designer/palette/PalettePanel.java b/plugins/ui-designer-core/src/com/intellij/designer/palette/PalettePanel.java
index a7dfef3758ae..f81baca17551 100644
--- a/plugins/ui-designer-core/src/com/intellij/designer/palette/PalettePanel.java
+++ b/plugins/ui-designer-core/src/com/intellij/designer/palette/PalettePanel.java
@@ -131,12 +131,6 @@ public class PalettePanel extends JPanel implements DataProvider, PaletteToolWin
repaint();
}
- @Override
- public boolean isEmpty() {
- return myGroups.isEmpty();
- }
-
- @Override
public void loadPalette(@Nullable DesignerEditorPanel designer) {
if (myDesigner == null && designer == null) {
return;
diff --git a/plugins/ui-designer-core/src/com/intellij/designer/palette/PaletteToolWindowManager.java b/plugins/ui-designer-core/src/com/intellij/designer/palette/PaletteToolWindowManager.java
index ae14d96e0248..3fddf66eaad6 100644
--- a/plugins/ui-designer-core/src/com/intellij/designer/palette/PaletteToolWindowManager.java
+++ b/plugins/ui-designer-core/src/com/intellij/designer/palette/PaletteToolWindowManager.java
@@ -17,6 +17,7 @@ package com.intellij.designer.palette;
import com.intellij.designer.AbstractToolWindowManager;
import com.intellij.designer.DesignerCustomizations;
+import com.intellij.designer.DesignerEditorPanelFacade;
import com.intellij.designer.LightToolWindow;
import com.intellij.designer.designSurface.DesignerEditorPanel;
import com.intellij.icons.AllIcons;
@@ -85,10 +86,10 @@ public class PaletteToolWindowManager extends AbstractToolWindowManager {
}
@Override
- protected void updateToolWindow(@Nullable DesignerEditorPanel designer) {
- myToolWindowPanel.loadPalette(designer);
+ protected void updateToolWindow(@Nullable DesignerEditorPanelFacade designer) {
+ myToolWindowPanel.loadPalette((DesignerEditorPanel)designer);
- if (myToolWindowPanel.isEmpty()) {
+ if (designer == null) {
myToolWindow.setAvailable(false, null);
}
else {
@@ -115,9 +116,9 @@ public class PaletteToolWindowManager extends AbstractToolWindowManager {
//////////////////////////////////////////////////////////////////////////////////////////
@Override
- protected LightToolWindow createContent(DesignerEditorPanel designer) {
+ protected LightToolWindow createContent(@NotNull DesignerEditorPanelFacade designer) {
PalettePanel palettePanel = new PalettePanel();
- palettePanel.loadPalette(designer);
+ palettePanel.loadPalette((DesignerEditorPanel)designer);
return createContent(designer,
palettePanel,
diff --git a/plugins/ui-designer/src/META-INF/plugin.xml b/plugins/ui-designer/src/META-INF/plugin.xml
index bca8934330a4..1dbd8d76a91c 100644
--- a/plugins/ui-designer/src/META-INF/plugin.xml
+++ b/plugins/ui-designer/src/META-INF/plugin.xml
@@ -9,6 +9,10 @@
<extensionPoints>
<extensionPoint name="formInspectionTool"
interface="com.intellij.uiDesigner.inspections.FormInspectionTool"/>
+
+ <extensionPoint qualifiedName="com.intellij.paletteItemProvider"
+ area="IDEA_PROJECT"
+ interface="com.intellij.ide.palette.PaletteItemProvider"/>
</extensionPoints>
<extensions defaultExtensionNs="com.intellij.uiDesigner">
@@ -143,11 +147,14 @@
<project-components>
<component>
- <implementation-class>com.intellij.uiDesigner.propertyInspector.UIDesignerToolWindowManager</implementation-class>
+ <implementation-class>com.intellij.uiDesigner.propertyInspector.DesignerToolWindowManager</implementation-class>
<headless-implementation-class></headless-implementation-class>
<skipForDefaultProject/>
</component>
<component>
+ <implementation-class>com.intellij.ide.palette.impl.PaletteToolWindowManager</implementation-class>
+ </component>
+ <component>
<implementation-class>com.intellij.uiDesigner.clientProperties.ClientPropertiesManager</implementation-class>
</component>
</project-components>
@@ -202,6 +209,8 @@
use-shortcut-of="SurroundWith"/>
<action id="GuiDesigner.Flatten" class="com.intellij.uiDesigner.actions.FlattenAction"/>
<separator/>
+ <action id="GuiDesigner.FormSource" class="com.intellij.uiDesigner.actions.ShowFormSourceAction"/>
+ <separator/>
<reference ref="VersionControlsGroup"/>
<separator/>
<reference ref="AddToFavorites"/>
diff --git a/java/openapi/src/com/intellij/ide/palette/PaletteDragEventListener.java b/plugins/ui-designer/src/com/intellij/ide/palette/PaletteDragEventListener.java
index 1a6b681b2a48..1a6b681b2a48 100644
--- a/java/openapi/src/com/intellij/ide/palette/PaletteDragEventListener.java
+++ b/plugins/ui-designer/src/com/intellij/ide/palette/PaletteDragEventListener.java
diff --git a/java/openapi/src/com/intellij/ide/palette/PaletteGroup.java b/plugins/ui-designer/src/com/intellij/ide/palette/PaletteGroup.java
index a19c1ab8e60d..a19c1ab8e60d 100644
--- a/java/openapi/src/com/intellij/ide/palette/PaletteGroup.java
+++ b/plugins/ui-designer/src/com/intellij/ide/palette/PaletteGroup.java
diff --git a/java/openapi/src/com/intellij/ide/palette/PaletteItem.java b/plugins/ui-designer/src/com/intellij/ide/palette/PaletteItem.java
index 372839d67266..372839d67266 100644
--- a/java/openapi/src/com/intellij/ide/palette/PaletteItem.java
+++ b/plugins/ui-designer/src/com/intellij/ide/palette/PaletteItem.java
diff --git a/java/openapi/src/com/intellij/ide/palette/PaletteItemProvider.java b/plugins/ui-designer/src/com/intellij/ide/palette/PaletteItemProvider.java
index 3f1b99d36f52..3f1b99d36f52 100644
--- a/java/openapi/src/com/intellij/ide/palette/PaletteItemProvider.java
+++ b/plugins/ui-designer/src/com/intellij/ide/palette/PaletteItemProvider.java
diff --git a/java/idea-ui/src/com/intellij/ide/palette/impl/PaletteComponentList.java b/plugins/ui-designer/src/com/intellij/ide/palette/impl/PaletteComponentList.java
index ea4f6de53401..77b58a922a87 100644
--- a/java/idea-ui/src/com/intellij/ide/palette/impl/PaletteComponentList.java
+++ b/plugins/ui-designer/src/com/intellij/ide/palette/impl/PaletteComponentList.java
@@ -42,14 +42,16 @@ import java.awt.event.*;
*/
public class PaletteComponentList extends JBList {
private final Project myProject;
+ private final PaletteWindow myPalette;
private final PaletteGroup myGroup;
private int myHoverIndex = -1;
private int myBeforeClickSelectedRow = -1;
private int myDropTargetIndex = -1;
private boolean myNeedClearSelection = false;
- public PaletteComponentList(Project project, PaletteGroup group) {
+ public PaletteComponentList(Project project, PaletteWindow palette, PaletteGroup group) {
myProject = project;
+ myPalette = palette;
myGroup = group;
setModel(new AbstractListModel() {
public int getSize() {
@@ -118,15 +120,15 @@ public class PaletteComponentList extends JBList {
addKeyListener(new KeyListener() {
public void keyPressed(KeyEvent e) {
- PaletteManager.getInstance(myProject).notifyKeyEvent(e);
+ myPalette.notifyKeyEvent(e);
}
public void keyReleased(KeyEvent e) {
- PaletteManager.getInstance(myProject).notifyKeyEvent(e);
+ myPalette.notifyKeyEvent(e);
}
public void keyTyped(KeyEvent e) {
- PaletteManager.getInstance(myProject).notifyKeyEvent(e);
+ myPalette.notifyKeyEvent(e);
}
});
@@ -395,7 +397,7 @@ public class PaletteComponentList extends JBList {
}
public void dropActionChanged(final int gestureModifiers) {
- PaletteManager.getInstance(myProject).notifyDropActionChanged(gestureModifiers);
+ myPalette.notifyDropActionChanged(gestureModifiers);
}
}
}
diff --git a/java/idea-ui/src/com/intellij/ide/palette/impl/PaletteContentWindow.java b/plugins/ui-designer/src/com/intellij/ide/palette/impl/PaletteContentWindow.java
index b5aaccad7b29..b5aaccad7b29 100644
--- a/java/idea-ui/src/com/intellij/ide/palette/impl/PaletteContentWindow.java
+++ b/plugins/ui-designer/src/com/intellij/ide/palette/impl/PaletteContentWindow.java
diff --git a/java/idea-ui/src/com/intellij/ide/palette/impl/PaletteGroupHeader.java b/plugins/ui-designer/src/com/intellij/ide/palette/impl/PaletteGroupHeader.java
index c98caefa3f75..c98caefa3f75 100644
--- a/java/idea-ui/src/com/intellij/ide/palette/impl/PaletteGroupHeader.java
+++ b/plugins/ui-designer/src/com/intellij/ide/palette/impl/PaletteGroupHeader.java
diff --git a/plugins/ui-designer/src/com/intellij/ide/palette/impl/PaletteToolWindowManager.java b/plugins/ui-designer/src/com/intellij/ide/palette/impl/PaletteToolWindowManager.java
new file mode 100644
index 000000000000..c6fe8756d1f5
--- /dev/null
+++ b/plugins/ui-designer/src/com/intellij/ide/palette/impl/PaletteToolWindowManager.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.ide.palette.impl;
+
+import com.intellij.designer.DesignerEditorPanelFacade;
+import com.intellij.designer.LightToolWindow;
+import com.intellij.icons.AllIcons;
+import com.intellij.ide.IdeBundle;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.fileEditor.FileEditorManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.wm.ToolWindowAnchor;
+import com.intellij.openapi.wm.ToolWindowManager;
+import com.intellij.ui.content.Content;
+import com.intellij.ui.content.ContentManager;
+import com.intellij.uiDesigner.AbstractToolWindowManager;
+import com.intellij.uiDesigner.designSurface.GuiEditor;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author Alexander Lobas
+ */
+public class PaletteToolWindowManager extends AbstractToolWindowManager {
+ private final PaletteWindow myToolWindowPanel;
+
+ public PaletteToolWindowManager(Project project, FileEditorManager fileEditorManager) {
+ super(project, fileEditorManager);
+ myToolWindowPanel = ApplicationManager.getApplication().isHeadlessEnvironment() ? null : new PaletteWindow(project);
+ }
+
+ public static PaletteWindow getInstance(GuiEditor designer) {
+ PaletteToolWindowManager manager = getInstance(designer.getProject());
+ if (manager.isEditorMode()) {
+ return (PaletteWindow)manager.getContent(designer);
+ }
+ return manager.myToolWindowPanel;
+ }
+
+ public static PaletteToolWindowManager getInstance(Project project) {
+ return project.getComponent(PaletteToolWindowManager.class);
+ }
+
+ @Override
+ protected void initToolWindow() {
+ myToolWindow = ToolWindowManager.getInstance(myProject)
+ .registerToolWindow(IdeBundle.message("toolwindow.palette"), false, getAnchor(), myProject, true);
+ myToolWindow.setIcon(AllIcons.Toolwindows.ToolWindowPalette);
+ initGearActions();
+
+ ContentManager contentManager = myToolWindow.getContentManager();
+ Content content = contentManager.getFactory().createContent(myToolWindowPanel, null, false);
+ content.setCloseable(false);
+ content.setPreferredFocusableComponent(myToolWindowPanel);
+ contentManager.addContent(content);
+ contentManager.setSelectedContent(content, true);
+ myToolWindow.setAvailable(false, null);
+ }
+
+ @Override
+ protected void updateToolWindow(@Nullable DesignerEditorPanelFacade designer) {
+ myToolWindowPanel.refreshPaletteIfChanged((GuiEditor)designer);
+
+ if (designer == null) {
+ myToolWindow.setAvailable(false, null);
+ }
+ else {
+ myToolWindow.setAvailable(true, null);
+ myToolWindow.show(null);
+ }
+ }
+
+ @Override
+ protected ToolWindowAnchor getAnchor() {
+ return ToolWindowAnchor.RIGHT;
+ }
+
+ @Override
+ protected LightToolWindow createContent(@NotNull DesignerEditorPanelFacade designer) {
+ PaletteWindow palettePanel = new PaletteWindow(myProject);
+ palettePanel.refreshPaletteIfChanged((GuiEditor)designer);
+
+ return createContent(designer,
+ palettePanel,
+ IdeBundle.message("toolwindow.palette"),
+ AllIcons.Toolwindows.ToolWindowPalette,
+ palettePanel,
+ palettePanel,
+ 180,
+ null);
+ }
+
+ @Override
+ public void disposeComponent() {
+ if (myToolWindowPanel != null) {
+ myToolWindowPanel.dispose();
+ }
+ }
+
+ @NotNull
+ @Override
+ public String getComponentName() {
+ return "PaletteManager";
+ }
+} \ No newline at end of file
diff --git a/java/idea-ui/src/com/intellij/ide/palette/impl/PaletteWindow.java b/plugins/ui-designer/src/com/intellij/ide/palette/impl/PaletteWindow.java
index 27f280386731..0c7b57ce999c 100644
--- a/java/idea-ui/src/com/intellij/ide/palette/impl/PaletteWindow.java
+++ b/plugins/ui-designer/src/com/intellij/ide/palette/impl/PaletteWindow.java
@@ -15,18 +15,19 @@
*/
package com.intellij.ide.palette.impl;
+import com.intellij.designer.LightToolWindowContent;
import com.intellij.ide.palette.PaletteGroup;
import com.intellij.ide.palette.PaletteItem;
import com.intellij.ide.palette.PaletteItemProvider;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.extensions.Extensions;
-import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.PopupHandler;
import com.intellij.ui.ScrollPaneFactory;
import com.intellij.ui.components.JBTabbedPane;
+import com.intellij.uiDesigner.designSurface.GuiEditor;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.HashSet;
import org.jetbrains.annotations.NonNls;
@@ -48,7 +49,7 @@ import java.util.*;
/**
* @author yole
*/
-public class PaletteWindow extends JPanel implements DataProvider {
+public class PaletteWindow extends JPanel implements LightToolWindowContent, DataProvider {
private final Project myProject;
private final ArrayList<PaletteGroupHeader> myGroupHeaders = new ArrayList<PaletteGroupHeader>();
private final PaletteItemProvider[] myProviders;
@@ -60,7 +61,6 @@ public class PaletteWindow extends JPanel implements DataProvider {
private PaletteGroupHeader myLastFocusedGroup;
@NonNls private static final String ourHelpID = "guiDesigner.uiTour.palette";
- private PaletteManager myPaletteManager;
private final DragSourceListener myDragSourceListener = new DragSourceAdapter() {
@Override
@@ -74,20 +74,17 @@ public class PaletteWindow extends JPanel implements DataProvider {
}
};
+ private GuiEditor myDesigner;
+
public PaletteWindow(Project project) {
myProject = project;
- myPaletteManager = PaletteManager.getInstance(myProject);
myProviders = Extensions.getExtensions(PaletteItemProvider.EP_NAME, project);
- for (PaletteItemProvider provider : myProviders) {
- provider.addListener(myPropertyChangeListener);
- }
setLayout(new GridLayout(1, 1));
myScrollPane.addMouseListener(new MyScrollPanePopupHandler());
myScrollPane.setBorder(null);
KeyStroke escStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
new ClearActiveItemAction().registerCustomShortcutSet(new CustomShortcutSet(escStroke), myScrollPane);
- refreshPalette();
if (!ApplicationManager.getApplication().isHeadlessEnvironment()) {
DragSource.getDefaultDragSource().addDragSourceListener(myDragSourceListener);
@@ -95,16 +92,40 @@ public class PaletteWindow extends JPanel implements DataProvider {
}
public void dispose() {
+ removePaletteProviderListener();
+
if (!ApplicationManager.getApplication().isHeadlessEnvironment()) {
DragSource.getDefaultDragSource().removeDragSourceListener(myDragSourceListener);
}
}
- public void refreshPalette() {
- refreshPalette(null);
+ private void addPaletteProviderListener() {
+ for (PaletteItemProvider provider : myProviders) {
+ provider.addListener(myPropertyChangeListener);
+ }
+ }
+
+ private void removePaletteProviderListener() {
+ for (PaletteItemProvider provider : myProviders) {
+ provider.removeListener(myPropertyChangeListener);
+ }
+ }
+
+ public void refreshPaletteIfChanged(@Nullable GuiEditor designer) {
+ removePaletteProviderListener();
+ myDesigner = designer;
+ if (designer != null) {
+ addPaletteProviderListener();
+ }
+
+ VirtualFile file = designer == null ? null : designer.getFile();
+ Set<PaletteGroup> currentGroups = new HashSet<PaletteGroup>(collectCurrentGroups(file));
+ if (!currentGroups.equals(myGroups)) {
+ refreshPalette(file);
+ }
}
- public void refreshPalette(@Nullable VirtualFile selectedFile) {
+ private void refreshPalette(@Nullable VirtualFile selectedFile) {
for (PaletteGroupHeader groupHeader : myGroupHeaders) {
groupHeader.getComponentList().removeListSelectionListener(myListSelectionListener);
}
@@ -161,7 +182,7 @@ public class PaletteWindow extends JPanel implements DataProvider {
myGroupHeaders.add(groupHeader);
myGroups.add(group);
control.add(groupHeader);
- PaletteComponentList componentList = new PaletteComponentList(myProject, group);
+ PaletteComponentList componentList = new PaletteComponentList(myProject, this, group);
control.add(componentList);
groupHeader.setComponentList(componentList);
componentList.addListSelectionListener(myListSelectionListener);
@@ -177,12 +198,6 @@ public class PaletteWindow extends JPanel implements DataProvider {
private ArrayList<PaletteGroup> collectCurrentGroups(@Nullable VirtualFile selectedFile) {
ArrayList<PaletteGroup> result = new ArrayList<PaletteGroup>();
- if (selectedFile == null) {
- VirtualFile[] editedFiles = FileEditorManager.getInstance(myProject).getSelectedFiles();
- if (editedFiles.length > 0) {
- selectedFile = editedFiles[0];
- }
- }
if (selectedFile != null) {
for (PaletteItemProvider provider : myProviders) {
PaletteGroup[] groups = provider.getActiveGroups(selectedFile);
@@ -192,24 +207,13 @@ public class PaletteWindow extends JPanel implements DataProvider {
return result;
}
- public void refreshPaletteIfChanged(VirtualFile selectedFile) {
- Set<PaletteGroup> currentGroups = new HashSet<PaletteGroup>(collectCurrentGroups(selectedFile));
- if (!currentGroups.equals(myGroups)) {
- refreshPalette(selectedFile);
- }
- }
-
- public int getActiveGroupCount() {
- return myGroups.size();
- }
-
public void clearActiveItem() {
if (getActiveItem() == null) return;
for (PaletteGroupHeader group : myGroupHeaders) {
group.getComponentList().clearSelection();
}
ListSelectionEvent event = new ListSelectionEvent(this, -1, -1, false);
- myPaletteManager.notifySelectionChanged(event);
+ notifySelectionChanged(event);
}
@Nullable
@@ -223,6 +227,16 @@ public class PaletteWindow extends JPanel implements DataProvider {
}
@Nullable
+ public <T extends PaletteItem> T getActiveItem(Class<T> cls) {
+ PaletteItem item = getActiveItem();
+ if (item != null && item.getClass().isInstance(item)) {
+ //noinspection unchecked
+ return (T)item;
+ }
+ return null;
+ }
+
+ @Nullable
public Object getData(String dataId) {
if (PlatformDataKeys.HELP_ID.is(dataId)) {
return ourHelpID;
@@ -269,6 +283,29 @@ public class PaletteWindow extends JPanel implements DataProvider {
}
}
+ void notifyKeyEvent(final KeyEvent e) {
+ if (myDesigner != null) {
+ if (e.getID() == KeyEvent.KEY_PRESSED) {
+ myDesigner.paletteKeyPressed(e);
+ }
+ else if (e.getID() == KeyEvent.KEY_RELEASED) {
+ myDesigner.paletteKeyReleased(e);
+ }
+ }
+ }
+
+ void notifyDropActionChanged(int gestureModifiers) {
+ if (myDesigner != null) {
+ myDesigner.paletteDropActionChanged(gestureModifiers);
+ }
+ }
+
+ void notifySelectionChanged(final ListSelectionEvent event) {
+ if (myDesigner != null) {
+ myDesigner.paletteValueChanged(event);
+ }
+ }
+
private class MyListSelectionListener implements ListSelectionListener {
public void valueChanged(ListSelectionEvent e) {
PaletteComponentList sourceList = (PaletteComponentList)e.getSource();
@@ -283,13 +320,13 @@ public class PaletteWindow extends JPanel implements DataProvider {
break;
}
}
- myPaletteManager.notifySelectionChanged(e);
+ notifySelectionChanged(e);
}
}
private class MyPropertyChangeListener implements PropertyChangeListener {
public void propertyChange(PropertyChangeEvent evt) {
- refreshPalette();
+ refreshPalette(myDesigner.getFile());
}
}
diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/AbstractToolWindowManager.java b/plugins/ui-designer/src/com/intellij/uiDesigner/AbstractToolWindowManager.java
new file mode 100644
index 000000000000..1a221506c1c2
--- /dev/null
+++ b/plugins/ui-designer/src/com/intellij/uiDesigner/AbstractToolWindowManager.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.uiDesigner;
+
+import com.intellij.designer.DesignerEditorPanelFacade;
+import com.intellij.designer.LightToolWindowManager;
+import com.intellij.designer.ToggleEditorModeAction;
+import com.intellij.ide.palette.impl.PaletteToolWindowManager;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.fileEditor.FileEditor;
+import com.intellij.openapi.fileEditor.FileEditorManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.wm.ToolWindowAnchor;
+import com.intellij.uiDesigner.editor.UIFormEditor;
+import com.intellij.uiDesigner.propertyInspector.DesignerToolWindowManager;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author Alexander Lobas
+ */
+public abstract class AbstractToolWindowManager extends LightToolWindowManager {
+ public AbstractToolWindowManager(Project project, FileEditorManager fileEditorManager) {
+ super(project, fileEditorManager);
+ }
+
+ @Override
+ public void projectOpened() {
+ if (!ApplicationManager.getApplication().isHeadlessEnvironment()) {
+ super.projectOpened();
+ }
+ }
+
+ @Nullable
+ @Override
+ protected DesignerEditorPanelFacade getDesigner(FileEditor editor) {
+ if (editor instanceof UIFormEditor) {
+ UIFormEditor formEditor = (UIFormEditor)editor;
+ return formEditor.getEditor();
+ }
+ return null;
+ }
+
+ @Override
+ protected ToggleEditorModeAction createToggleAction(ToolWindowAnchor anchor) {
+ return new ToggleEditorModeAction(this, myProject, anchor) {
+ @Override
+ protected LightToolWindowManager getOppositeManager() {
+ AbstractToolWindowManager designerManager = DesignerToolWindowManager.getInstance(myProject);
+ AbstractToolWindowManager paletteManager = PaletteToolWindowManager.getInstance(myProject);
+ return myManager == designerManager ? paletteManager : designerManager;
+ }
+ };
+ }
+} \ No newline at end of file
diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/FormEditingUtil.java b/plugins/ui-designer/src/com/intellij/uiDesigner/FormEditingUtil.java
index 6f9866018f4c..f2443b264b78 100644
--- a/plugins/ui-designer/src/com/intellij/uiDesigner/FormEditingUtil.java
+++ b/plugins/ui-designer/src/com/intellij/uiDesigner/FormEditingUtil.java
@@ -41,7 +41,7 @@ import com.intellij.uiDesigner.editor.UIFormEditor;
import com.intellij.uiDesigner.lw.*;
import com.intellij.uiDesigner.palette.ComponentItem;
import com.intellij.uiDesigner.palette.Palette;
-import com.intellij.uiDesigner.propertyInspector.UIDesignerToolWindowManager;
+import com.intellij.uiDesigner.propertyInspector.DesignerToolWindowManager;
import com.intellij.uiDesigner.propertyInspector.properties.BindingProperty;
import com.intellij.uiDesigner.propertyInspector.properties.IntroComponentProperty;
import com.intellij.uiDesigner.radComponents.RadAbstractGridLayoutManager;
@@ -602,7 +602,7 @@ public final class FormEditingUtil {
if (project == null) {
return null;
}
- final UIDesignerToolWindowManager toolWindowManager = UIDesignerToolWindowManager.getInstance(project);
+ final DesignerToolWindowManager toolWindowManager = DesignerToolWindowManager.getInstance(project);
if (toolWindowManager == null) {
return null;
}
@@ -702,7 +702,7 @@ public final class FormEditingUtil {
final RadContainer root = (RadContainer)getRoot(component);
if (root == null) return;
- ComponentTreeBuilder builder = UIDesignerToolWindowManager.getInstance(component.getProject()).getComponentTreeBuilder();
+ ComponentTreeBuilder builder = DesignerToolWindowManager.getInstance(editor).getComponentTreeBuilder();
// this can return null if the click to select the control also requested to grab the focus -
// the component tree will be instantiated after the event has been processed completely
if (builder != null) {
@@ -724,7 +724,7 @@ public final class FormEditingUtil {
public static void selectComponents(final GuiEditor editor, List<RadComponent> components) {
if (components.size() > 0) {
RadComponent component = components.get(0);
- ComponentTreeBuilder builder = UIDesignerToolWindowManager.getInstance(component.getProject()).getComponentTreeBuilder();
+ ComponentTreeBuilder builder = DesignerToolWindowManager.getInstance(editor).getComponentTreeBuilder();
if (builder == null) {
// race condition when handling event?
return;
@@ -780,7 +780,7 @@ public final class FormEditingUtil {
}
public static Object getNextSaveUndoGroupId(final Project project) {
- final GuiEditor guiEditor = UIDesignerToolWindowManager.getInstance(project).getActiveFormEditor();
+ final GuiEditor guiEditor = DesignerToolWindowManager.getInstance(project).getActiveFormEditor();
return guiEditor == null ? null : guiEditor.getNextSaveGroupId();
}
diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/FormHighlightingPass.java b/plugins/ui-designer/src/com/intellij/uiDesigner/FormHighlightingPass.java
index dae49482b998..e78c1d957f74 100644
--- a/plugins/ui-designer/src/com/intellij/uiDesigner/FormHighlightingPass.java
+++ b/plugins/ui-designer/src/com/intellij/uiDesigner/FormHighlightingPass.java
@@ -19,7 +19,7 @@ package com.intellij.uiDesigner;
import com.intellij.codeHighlighting.HighlightingPass;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.uiDesigner.designSurface.GuiEditor;
-import com.intellij.uiDesigner.propertyInspector.UIDesignerToolWindowManager;
+import com.intellij.uiDesigner.propertyInspector.DesignerToolWindowManager;
import org.jetbrains.annotations.NotNull;
/**
@@ -37,7 +37,7 @@ public class FormHighlightingPass implements HighlightingPass {
}
public void applyInformationToEditor() {
- UIDesignerToolWindowManager.getInstance(myEditor.getProject()).refreshErrors();
+ DesignerToolWindowManager.getInstance(myEditor).refreshErrors();
myEditor.refreshIntentionHint();
}
-}
+} \ No newline at end of file
diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/actions/ExpandSelectionAction.java b/plugins/ui-designer/src/com/intellij/uiDesigner/actions/ExpandSelectionAction.java
index c04c39ac4f4b..d1f2e6dd3688 100644
--- a/plugins/ui-designer/src/com/intellij/uiDesigner/actions/ExpandSelectionAction.java
+++ b/plugins/ui-designer/src/com/intellij/uiDesigner/actions/ExpandSelectionAction.java
@@ -18,13 +18,14 @@ package com.intellij.uiDesigner.actions;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.Presentation;
-import com.intellij.uiDesigner.*;
-import com.intellij.uiDesigner.propertyInspector.UIDesignerToolWindowManager;
-import com.intellij.uiDesigner.radComponents.RadComponent;
-import com.intellij.uiDesigner.radComponents.RadContainer;
-import com.intellij.uiDesigner.designSurface.GuiEditor;
+import com.intellij.uiDesigner.FormEditingUtil;
+import com.intellij.uiDesigner.SelectionState;
import com.intellij.uiDesigner.componentTree.ComponentPtr;
import com.intellij.uiDesigner.componentTree.ComponentTreeBuilder;
+import com.intellij.uiDesigner.designSurface.GuiEditor;
+import com.intellij.uiDesigner.propertyInspector.DesignerToolWindowManager;
+import com.intellij.uiDesigner.radComponents.RadComponent;
+import com.intellij.uiDesigner.radComponents.RadContainer;
import java.util.Stack;
@@ -43,7 +44,7 @@ public final class ExpandSelectionAction extends AnAction{
final SelectionState selectionState = editor.getSelectionState();
selectionState.setInsideChange(true);
- ComponentTreeBuilder builder = UIDesignerToolWindowManager.getInstance(editor.getProject()).getComponentTreeBuilder();
+ ComponentTreeBuilder builder = DesignerToolWindowManager.getInstance(editor).getComponentTreeBuilder();
if (builder != null) {
builder.beginUpdateSelection();
}
diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/actions/ResetValueAction.java b/plugins/ui-designer/src/com/intellij/uiDesigner/actions/ResetValueAction.java
index 108451fff59c..d9085a3d08c5 100644
--- a/plugins/ui-designer/src/com/intellij/uiDesigner/actions/ResetValueAction.java
+++ b/plugins/ui-designer/src/com/intellij/uiDesigner/actions/ResetValueAction.java
@@ -18,10 +18,7 @@ package com.intellij.uiDesigner.actions;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.uiDesigner.designSurface.GuiEditor;
-import com.intellij.uiDesigner.propertyInspector.Property;
-import com.intellij.uiDesigner.propertyInspector.PropertyInspector;
-import com.intellij.uiDesigner.propertyInspector.PropertyInspectorTable;
-import com.intellij.uiDesigner.propertyInspector.UIDesignerToolWindowManager;
+import com.intellij.uiDesigner.propertyInspector.*;
import com.intellij.uiDesigner.radComponents.RadComponent;
import java.util.ArrayList;
@@ -44,7 +41,7 @@ public class ResetValueAction extends AbstractGuiEditorAction {
public static void doResetValue(final List<RadComponent> selection, final Property property, final GuiEditor editor) {
try {
if (!editor.ensureEditable()) return;
- final PropertyInspector propertyInspector = UIDesignerToolWindowManager.getInstance(editor.getProject()).getPropertyInspector();
+ final PropertyInspector propertyInspector = DesignerToolWindowManager.getInstance(editor).getPropertyInspector();
if (propertyInspector.isEditing()) {
propertyInspector.stopEditing();
}
diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/actions/SelectAllComponentsAction.java b/plugins/ui-designer/src/com/intellij/uiDesigner/actions/SelectAllComponentsAction.java
index cdfe0686c438..2569b4fb8477 100644
--- a/plugins/ui-designer/src/com/intellij/uiDesigner/actions/SelectAllComponentsAction.java
+++ b/plugins/ui-designer/src/com/intellij/uiDesigner/actions/SelectAllComponentsAction.java
@@ -15,13 +15,13 @@
*/
package com.intellij.uiDesigner.actions;
-import com.intellij.uiDesigner.designSurface.GuiEditor;
-import com.intellij.uiDesigner.radComponents.RadComponent;
-import com.intellij.uiDesigner.propertyInspector.UIDesignerToolWindowManager;
-import com.intellij.uiDesigner.componentTree.ComponentTreeBuilder;
+import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.uiDesigner.FormEditingUtil;
+import com.intellij.uiDesigner.componentTree.ComponentTreeBuilder;
+import com.intellij.uiDesigner.designSurface.GuiEditor;
import com.intellij.uiDesigner.lw.IComponent;
-import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.uiDesigner.propertyInspector.DesignerToolWindowManager;
+import com.intellij.uiDesigner.radComponents.RadComponent;
import java.util.List;
@@ -30,7 +30,7 @@ import java.util.List;
*/
public class SelectAllComponentsAction extends AbstractGuiEditorAction {
protected void actionPerformed(final GuiEditor editor, final List<RadComponent> selection, final AnActionEvent e) {
- final ComponentTreeBuilder builder = UIDesignerToolWindowManager.getInstance(editor.getProject()).getComponentTreeBuilder();
+ final ComponentTreeBuilder builder = DesignerToolWindowManager.getInstance(editor).getComponentTreeBuilder();
builder.beginUpdateSelection();
try {
FormEditingUtil.iterate(editor.getRootContainer(), new FormEditingUtil.ComponentVisitor() {
diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/actions/ShowFormSourceAction.java b/plugins/ui-designer/src/com/intellij/uiDesigner/actions/ShowFormSourceAction.java
new file mode 100644
index 000000000000..9ff3f8f6dfa6
--- /dev/null
+++ b/plugins/ui-designer/src/com/intellij/uiDesigner/actions/ShowFormSourceAction.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.uiDesigner.actions;
+
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.uiDesigner.designSurface.GuiEditor;
+import com.intellij.uiDesigner.radComponents.RadComponent;
+
+import java.util.List;
+
+/**
+ * @author Alexander Lobas
+ */
+public class ShowFormSourceAction extends AbstractGuiEditorAction {
+ @Override
+ protected void actionPerformed(GuiEditor editor, List<RadComponent> selection, AnActionEvent e) {
+ editor.showFormSource();
+ }
+} \ No newline at end of file
diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/actions/ShrinkSelectionAction.java b/plugins/ui-designer/src/com/intellij/uiDesigner/actions/ShrinkSelectionAction.java
index ccbbe252164b..20d79845c45f 100644
--- a/plugins/ui-designer/src/com/intellij/uiDesigner/actions/ShrinkSelectionAction.java
+++ b/plugins/ui-designer/src/com/intellij/uiDesigner/actions/ShrinkSelectionAction.java
@@ -18,12 +18,12 @@ package com.intellij.uiDesigner.actions;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.Presentation;
-import com.intellij.uiDesigner.SelectionState;
import com.intellij.uiDesigner.FormEditingUtil;
-import com.intellij.uiDesigner.propertyInspector.UIDesignerToolWindowManager;
+import com.intellij.uiDesigner.SelectionState;
import com.intellij.uiDesigner.componentTree.ComponentPtr;
import com.intellij.uiDesigner.componentTree.ComponentTreeBuilder;
import com.intellij.uiDesigner.designSurface.GuiEditor;
+import com.intellij.uiDesigner.propertyInspector.DesignerToolWindowManager;
import java.util.Stack;
@@ -37,7 +37,7 @@ public final class ShrinkSelectionAction extends AnAction{
assert editor != null;
final SelectionState selectionState = editor.getSelectionState();
selectionState.setInsideChange(true);
- ComponentTreeBuilder builder = UIDesignerToolWindowManager.getInstance(editor.getProject()).getComponentTreeBuilder();
+ ComponentTreeBuilder builder = DesignerToolWindowManager.getInstance(editor).getComponentTreeBuilder();
builder.beginUpdateSelection();
try{
diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/componentTree/ComponentTreeBuilder.java b/plugins/ui-designer/src/com/intellij/uiDesigner/componentTree/ComponentTreeBuilder.java
index 25791e2815da..aa5161ea0b96 100644
--- a/plugins/ui-designer/src/com/intellij/uiDesigner/componentTree/ComponentTreeBuilder.java
+++ b/plugins/ui-designer/src/com/intellij/uiDesigner/componentTree/ComponentTreeBuilder.java
@@ -25,8 +25,8 @@ import com.intellij.uiDesigner.FormEditingUtil;
import com.intellij.uiDesigner.HierarchyChangeListener;
import com.intellij.uiDesigner.SelectionWatcher;
import com.intellij.uiDesigner.designSurface.GuiEditor;
+import com.intellij.uiDesigner.propertyInspector.DesignerToolWindowManager;
import com.intellij.uiDesigner.propertyInspector.PropertyInspector;
-import com.intellij.uiDesigner.propertyInspector.UIDesignerToolWindowManager;
import com.intellij.uiDesigner.radComponents.RadComponent;
import com.intellij.uiDesigner.radComponents.RadContainer;
import org.jetbrains.annotations.NotNull;
@@ -221,7 +221,7 @@ public final class ComponentTreeBuilder extends AbstractTreeBuilder {
}
private void updateSelection() {
- final PropertyInspector propertyInspector = UIDesignerToolWindowManager.getInstance(myEditor.getProject()).getPropertyInspector();
+ final PropertyInspector propertyInspector = DesignerToolWindowManager.getInstance(myEditor).getPropertyInspector();
if (propertyInspector.isEditing()) {
propertyInspector.stopEditing();
}
diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/DesignDropTargetListener.java b/plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/DesignDropTargetListener.java
index d96eac097f48..f3ddc85e9280 100644
--- a/plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/DesignDropTargetListener.java
+++ b/plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/DesignDropTargetListener.java
@@ -15,26 +15,26 @@
*/
package com.intellij.uiDesigner.designSurface;
-import com.intellij.ide.palette.impl.PaletteManager;
+import com.intellij.ide.palette.impl.PaletteToolWindowManager;
import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.command.CommandProcessor;
+import com.intellij.openapi.diagnostic.Logger;
import com.intellij.uiDesigner.CutCopyPasteSupport;
import com.intellij.uiDesigner.FormEditingUtil;
import com.intellij.uiDesigner.SimpleTransferable;
import com.intellij.uiDesigner.UIDesignerBundle;
import com.intellij.uiDesigner.componentTree.ComponentTree;
-import com.intellij.uiDesigner.propertyInspector.UIDesignerToolWindowManager;
import com.intellij.uiDesigner.core.GridConstraints;
import com.intellij.uiDesigner.palette.ComponentItem;
+import com.intellij.uiDesigner.propertyInspector.DesignerToolWindowManager;
import com.intellij.uiDesigner.radComponents.RadComponent;
import com.intellij.uiDesigner.radComponents.RadContainer;
import javax.swing.*;
import java.awt.*;
import java.awt.dnd.*;
-import java.util.List;
import java.util.ArrayList;
+import java.util.List;
/**
* @author yole
@@ -49,12 +49,10 @@ class DesignDropTargetListener implements DropTargetListener {
private final GuiEditor myEditor;
private final GridInsertProcessor myGridInsertProcessor;
private boolean myUseDragDelta = false;
- private final ComponentTree myComponentTree;
public DesignDropTargetListener(final GuiEditor editor) {
myEditor = editor;
myGridInsertProcessor = new GridInsertProcessor(editor);
- myComponentTree = UIDesignerToolWindowManager.getInstance(editor.getProject()).getComponentTree();
}
public void dragEnter(DropTargetDragEvent dtde) {
@@ -150,16 +148,18 @@ class DesignDropTargetListener implements DropTargetListener {
myEditor.getDragLayer().repaint();
ComponentDropLocation location = myGridInsertProcessor.processDragEvent(dtde.getLocation(), myComponentDragObject);
+ ComponentTree componentTree = DesignerToolWindowManager.getInstance(myEditor).getComponentTree();
+
if (!location.canDrop(myComponentDragObject) ||
(myDraggedComponentList != null && FormEditingUtil.isDropOnChild(myDraggedComponentList, location))) {
- if (myComponentTree != null) {
- myComponentTree.setDropTargetComponent(null);
+ if (componentTree != null) {
+ componentTree.setDropTargetComponent(null);
}
dtde.rejectDrag();
}
else {
- if (myComponentTree != null) {
- myComponentTree.setDropTargetComponent(location.getContainer());
+ if (componentTree != null) {
+ componentTree.setDropTargetComponent(location.getContainer());
}
dtde.acceptDrag(dtde.getDropAction());
}
@@ -178,8 +178,9 @@ class DesignDropTargetListener implements DropTargetListener {
public void dragExit(DropTargetEvent dte) {
try {
- if (myComponentTree != null) {
- myComponentTree.setDropTargetComponent(null);
+ ComponentTree componentTree = DesignerToolWindowManager.getInstance(myEditor).getComponentTree();
+ if (componentTree != null) {
+ componentTree.setDropTargetComponent(null);
}
myUseDragDelta = false;
if (myDraggedComponentList != null) {
@@ -198,8 +199,9 @@ class DesignDropTargetListener implements DropTargetListener {
public void drop(final DropTargetDropEvent dtde) {
try {
- if (myComponentTree != null) {
- myComponentTree.setDropTargetComponent(null);
+ ComponentTree componentTree = DesignerToolWindowManager.getInstance(myEditor).getComponentTree();
+ if (componentTree != null) {
+ componentTree.setDropTargetComponent(null);
}
@@ -221,7 +223,7 @@ class DesignDropTargetListener implements DropTargetListener {
new InsertComponentProcessor(myEditor).processComponentInsert(dtde.getLocation(), componentItem);
ApplicationManager.getApplication().invokeLater(new Runnable() {
public void run() {
- PaletteManager.getInstance(myEditor.getProject()).clearActiveItem();
+ PaletteToolWindowManager.getInstance(myEditor).clearActiveItem();
myEditor.getActiveDecorationLayer().removeFeedback();
myEditor.getLayeredPane().setCursor(null);
myEditor.getGlassLayer().requestFocus();
diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/GlassLayer.java b/plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/GlassLayer.java
index 015a9dc4653e..8122989132d8 100644
--- a/plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/GlassLayer.java
+++ b/plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/GlassLayer.java
@@ -21,7 +21,7 @@ import com.intellij.ui.popup.PopupOwner;
import com.intellij.uiDesigner.FormEditingUtil;
import com.intellij.uiDesigner.actions.*;
import com.intellij.uiDesigner.componentTree.ComponentTree;
-import com.intellij.uiDesigner.propertyInspector.UIDesignerToolWindowManager;
+import com.intellij.uiDesigner.propertyInspector.DesignerToolWindowManager;
import com.intellij.uiDesigner.radComponents.RadComponent;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -136,7 +136,7 @@ public final class GlassLayer extends JComponent implements DataProvider, PopupO
*/
public Object getData(final String dataId) {
if(CommonDataKeys.NAVIGATABLE.is(dataId)) {
- final ComponentTree componentTree = UIDesignerToolWindowManager.getInstance(myEditor.getProject()).getComponentTree();
+ final ComponentTree componentTree = DesignerToolWindowManager.getInstance(myEditor).getComponentTree();
if (componentTree != null) {
return componentTree.getData(dataId);
}
diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/GridCaptionPanel.java b/plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/GridCaptionPanel.java
index 77d3104abccc..99a982f5acd3 100644
--- a/plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/GridCaptionPanel.java
+++ b/plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/GridCaptionPanel.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2012 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,7 +20,10 @@ import com.intellij.ide.DeleteProvider;
import com.intellij.ide.dnd.*;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.editor.colors.EditorColors;
+import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.util.Pair;
+import com.intellij.ui.JBColor;
import com.intellij.ui.LightColors;
import com.intellij.uiDesigner.CaptionSelection;
import com.intellij.uiDesigner.FormEditingUtil;
@@ -33,7 +36,9 @@ import com.intellij.uiDesigner.radComponents.RadContainer;
import com.intellij.uiDesigner.radComponents.RadRootContainer;
import com.intellij.util.Alarm;
import com.intellij.util.ArrayUtil;
+import com.intellij.util.NotNullProducer;
import com.intellij.util.ui.PlatformColors;
+import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -72,7 +77,7 @@ public class GridCaptionPanel extends JPanel implements ComponentSelectionListen
myEditor.fireSelectedComponentChanged();
}
});
- setBackground(Color.LIGHT_GRAY);
+ setBackground(getGutterColor());
editor.addComponentSelectionListener(this);
final MyMouseListener listener = new MyMouseListener();
@@ -101,6 +106,17 @@ public class GridCaptionPanel extends JPanel implements ComponentSelectionListen
});
}
+ public static JBColor getGutterColor() {
+ return new JBColor(new NotNullProducer<Color>() {
+ @NotNull
+ @Override
+ public Color produce() {
+ Color color = EditorColorsManager.getInstance().getGlobalScheme().getColor(EditorColors.GUTTER_BACKGROUND);
+ return color == null ? UIUtil.getPanelBackground() : color;
+ }
+ });
+ }
+
public RadContainer getSelectedContainer() {
// when the selected component changes, and we have focus, PropertyInspector asks us about our container and selection.
// PropertyInspector's selection changed listener can be called before our own listener, so we need to update ourselves
diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/GuiEditor.java b/plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/GuiEditor.java
index dbbc27655f4e..7459a05a33c3 100644
--- a/plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/GuiEditor.java
+++ b/plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/GuiEditor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 JetBrains s.r.o.
+ * Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,9 +16,11 @@
package com.intellij.uiDesigner.designSurface;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
+import com.intellij.designer.DesignerEditorPanelFacade;
+import com.intellij.designer.LightFillLayout;
import com.intellij.ide.DeleteProvider;
-import com.intellij.ide.palette.PaletteDragEventListener;
-import com.intellij.ide.palette.impl.PaletteManager;
+import com.intellij.ide.highlighter.XmlFileHighlighter;
+import com.intellij.ide.palette.impl.PaletteToolWindowManager;
import com.intellij.lang.properties.psi.PropertiesFile;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationManager;
@@ -27,14 +29,23 @@ import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.command.undo.UndoManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.editor.EditorFactory;
+import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.event.DocumentAdapter;
import com.intellij.openapi.editor.event.DocumentEvent;
+import com.intellij.openapi.editor.ex.EditorEx;
+import com.intellij.openapi.editor.ex.util.LexerEditorHighlighter;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtil;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogBuilder;
+import com.intellij.openapi.ui.ThreeComponentsSplitter;
+import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Ref;
+import com.intellij.openapi.util.registry.Registry;
import com.intellij.openapi.vfs.ReadonlyStatusHandler;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
@@ -48,19 +59,22 @@ import com.intellij.uiDesigner.componentTree.ComponentSelectionListener;
import com.intellij.uiDesigner.componentTree.ComponentTree;
import com.intellij.uiDesigner.core.GridLayoutManager;
import com.intellij.uiDesigner.core.Util;
+import com.intellij.uiDesigner.editor.UIFormEditor;
import com.intellij.uiDesigner.lw.CompiledClassPropertiesProvider;
import com.intellij.uiDesigner.lw.IComponent;
import com.intellij.uiDesigner.lw.IProperty;
import com.intellij.uiDesigner.lw.LwRootContainer;
import com.intellij.uiDesigner.palette.ComponentItem;
+import com.intellij.uiDesigner.propertyInspector.DesignerToolWindow;
+import com.intellij.uiDesigner.propertyInspector.DesignerToolWindowManager;
import com.intellij.uiDesigner.propertyInspector.PropertyInspector;
-import com.intellij.uiDesigner.propertyInspector.UIDesignerToolWindowManager;
import com.intellij.uiDesigner.propertyInspector.properties.IntroStringProperty;
import com.intellij.uiDesigner.radComponents.RadComponent;
import com.intellij.uiDesigner.radComponents.RadContainer;
import com.intellij.uiDesigner.radComponents.RadRootContainer;
import com.intellij.uiDesigner.radComponents.RadTabbedPane;
import com.intellij.util.Alarm;
+import com.intellij.util.NotNullProducer;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -69,11 +83,13 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.event.EventListenerList;
import javax.swing.event.ListSelectionEvent;
-import javax.swing.event.ListSelectionListener;
import java.awt.*;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTarget;
-import java.awt.event.*;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Locale;
@@ -87,10 +103,11 @@ import java.util.Map;
* @author Anton Katilin
* @author Vladimir Kondratyev
*/
-public final class GuiEditor extends JPanel implements DataProvider, ModuleProvider {
+public final class GuiEditor extends JPanel implements DesignerEditorPanelFacade, DataProvider, ModuleProvider {
private static final Logger LOG = Logger.getInstance("#com.intellij.uiDesigner.GuiEditor");
private final Project myProject;
+ @NotNull private final UIFormEditor myEditor;
private Module myModule;
@NotNull private final VirtualFile myFile;
@@ -175,7 +192,9 @@ public final class GuiEditor extends JPanel implements DataProvider, ModuleProvi
*/
private boolean myInsideChange;
private final DocumentAdapter myDocumentListener;
- private final CardLayout myCardLayout;
+ private final CardLayout myCardLayout = new CardLayout();
+ private final ThreeComponentsSplitter myContentSplitter = new ThreeComponentsSplitter();
+ private final JPanel myCardPanel = new JPanel(myCardLayout);
@NonNls private final static String CARD_VALID = "valid";
@NonNls private final static String CARD_INVALID = "invalid";
@@ -198,9 +217,6 @@ public final class GuiEditor extends JPanel implements DataProvider, ModuleProvi
private final QuickFixManagerImpl myQuickFixManager;
private final GridCaptionPanel myHorzCaptionPanel;
private final GridCaptionPanel myVertCaptionPanel;
- private final MyPaletteKeyListener myPaletteKeyListener;
- private final MyPaletteDragListener myPaletteDragListener;
- private final MyPaletteSelectionListener myPaletteSelectionListener;
private ComponentPtr mySelectionAnchor;
private ComponentPtr mySelectionLead;
/**
@@ -214,11 +230,11 @@ public final class GuiEditor extends JPanel implements DataProvider, ModuleProvi
/**
* @param file file to be edited
- * @throws java.lang.IllegalArgumentException
- * if the <code>file</code>
- * is <code>null</code> or <code>file</code> is not valid PsiFile
+ * @throws java.lang.IllegalArgumentException if the <code>file</code>
+ * is <code>null</code> or <code>file</code> is not valid PsiFile
*/
- public GuiEditor(Project project, @NotNull final Module module, @NotNull final VirtualFile file) {
+ public GuiEditor(@NotNull UIFormEditor editor, @NotNull Project project, @NotNull Module module, @NotNull VirtualFile file) {
+ myEditor = editor;
LOG.assertTrue(file.isValid());
myProject = project;
@@ -227,13 +243,25 @@ public final class GuiEditor extends JPanel implements DataProvider, ModuleProvi
myCutCopyPasteSupport = new CutCopyPasteSupport(this);
- myCardLayout = new CardLayout();
- setLayout(myCardLayout);
+ setLayout(new BorderLayout());
+
+ myContentSplitter.setDividerWidth(0);
+ myContentSplitter.setDividerMouseZoneSize(Registry.intValue("ide.splitter.mouseZone"));
+ add(myContentSplitter, BorderLayout.CENTER);
myValidCard = new JPanel(new BorderLayout());
myInvalidCard = createInvalidCard();
- add(myValidCard, CARD_VALID);
- add(myInvalidCard, CARD_INVALID);
+
+ myCardPanel.add(myValidCard, CARD_VALID);
+ myCardPanel.add(myInvalidCard, CARD_INVALID);
+
+ JPanel contentPanel = new JPanel(new LightFillLayout());
+ JLabel toolbar = new JLabel();
+ toolbar.setVisible(false);
+ contentPanel.add(toolbar);
+ contentPanel.add(myCardPanel);
+
+ myContentSplitter.setInnerComponent(contentPanel);
myListenerList = new EventListenerList();
@@ -288,7 +316,7 @@ public final class GuiEditor extends JPanel implements DataProvider, ModuleProvi
readFromFile(false);
JPanel panel = new JPanel(new GridBagLayout());
- panel.setBackground(Color.LIGHT_GRAY);
+ panel.setBackground(GridCaptionPanel.getGutterColor());
myHorzCaptionPanel = new GridCaptionPanel(this, false);
myVertCaptionPanel = new GridCaptionPanel(this, true);
@@ -311,7 +339,13 @@ public final class GuiEditor extends JPanel implements DataProvider, ModuleProvi
gbc.weighty = 1.0;
myScrollPane = ScrollPaneFactory.createScrollPane(myLayeredPane);
- myScrollPane.setBackground(new JBColor(Color.WHITE, UIUtil.getListBackground()));
+ myScrollPane.setBackground(new JBColor(new NotNullProducer<Color>() {
+ @NotNull
+ @Override
+ public Color produce() {
+ return EditorColorsManager.getInstance().getGlobalScheme().getDefaultBackground();
+ }
+ }));
panel.add(myScrollPane, gbc);
myHorzCaptionPanel.attachToScrollPane(myScrollPane);
myVertCaptionPanel.attachToScrollPane(myScrollPane);
@@ -336,18 +370,28 @@ public final class GuiEditor extends JPanel implements DataProvider, ModuleProvi
myActiveDecorationLayer.installSelectionWatcher();
- final PaletteManager paletteManager = PaletteManager.getInstance(getProject());
- myPaletteKeyListener = new MyPaletteKeyListener();
- paletteManager.addKeyListener(myPaletteKeyListener);
- myPaletteDragListener = new MyPaletteDragListener();
- paletteManager.addDragEventListener(myPaletteDragListener);
- myPaletteSelectionListener = new MyPaletteSelectionListener();
- paletteManager.addSelectionListener(myPaletteSelectionListener);
-
ActionManager.getInstance().getAction("GuiDesigner.IncreaseIndent").registerCustomShortcutSet(
new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0)), myGlassLayer);
ActionManager.getInstance().getAction("GuiDesigner.DecreaseIndent").registerCustomShortcutSet(
new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, KeyEvent.SHIFT_MASK)), myGlassLayer);
+
+ UIUtil.invokeLaterIfNeeded(new Runnable() {
+ @Override
+ public void run() {
+ DesignerToolWindowManager.getInstance(myProject).bind(GuiEditor.this);
+ PaletteToolWindowManager.getInstance(myProject).bind(GuiEditor.this);
+ }
+ });
+ }
+
+ @Override
+ public ThreeComponentsSplitter getContentSplitter() {
+ return myContentSplitter;
+ }
+
+ @NotNull
+ public UIFormEditor getEditor() {
+ return myEditor;
}
@NotNull
@@ -366,13 +410,14 @@ public final class GuiEditor extends JPanel implements DataProvider, ModuleProvi
myWhere = new Exception();
}
- final PaletteManager paletteManager = PaletteManager.getInstance(getProject());
- paletteManager.removeKeyListener(myPaletteKeyListener);
- paletteManager.removeDragEventListener(myPaletteDragListener);
- paletteManager.removeSelectionListener(myPaletteSelectionListener);
myDocument.removeDocumentListener(myDocumentListener);
PsiManager.getInstance(getProject()).removePsiTreeChangeListener(myPsiTreeChangeListener);
+
+ DesignerToolWindowManager.getInstance(myProject).dispose(this);
+ PaletteToolWindowManager.getInstance(myProject).dispose(this);
myPsiTreeChangeListener.dispose();
+
+ Disposer.dispose(myContentSplitter);
}
@NotNull
@@ -440,8 +485,7 @@ public final class GuiEditor extends JPanel implements DataProvider, ModuleProvi
public void refreshAndSave(final boolean forceSync) {
// Update property inspector
- final UIDesignerToolWindowManager manager = UIDesignerToolWindowManager.getInstance(getProject());
- final PropertyInspector propertyInspector = manager.getPropertyInspector();
+ final PropertyInspector propertyInspector = DesignerToolWindowManager.getInstance(this).getPropertyInspector();
if (propertyInspector != null) {
propertyInspector.synchWithTree(forceSync);
}
@@ -490,8 +534,7 @@ public final class GuiEditor extends JPanel implements DataProvider, ModuleProvi
// Standard Swing cut/copy/paste actions should work if user is editing something inside property inspector
Project project = getProject();
if (project.isDisposed()) return null;
- final UIDesignerToolWindowManager manager = UIDesignerToolWindowManager.getInstance(project);
- final PropertyInspector inspector = manager.getPropertyInspector();
+ final PropertyInspector inspector = DesignerToolWindowManager.getInstance(this).getPropertyInspector();
if (inspector != null && inspector.isEditing()) {
return null;
}
@@ -519,7 +562,7 @@ public final class GuiEditor extends JPanel implements DataProvider, ModuleProvi
/**
* @return the component which represents DnD layer. All currently
- * dragged (moved) component are on this layer.
+ * dragged (moved) component are on this layer.
*/
public DragLayer getDragLayer() {
return myDragLayer;
@@ -527,7 +570,7 @@ public final class GuiEditor extends JPanel implements DataProvider, ModuleProvi
/**
* @return the topmost <code>UiConainer</code> which in the root of
- * component hierarchy. This method never returns <code>null</code>.
+ * component hierarchy. This method never returns <code>null</code>.
*/
@NotNull
public RadRootContainer getRootContainer() {
@@ -558,7 +601,7 @@ public final class GuiEditor extends JPanel implements DataProvider, ModuleProvi
/**
* @return the component which represents layer with active decorators
- * such as grid edit controls, inplace editors, etc.
+ * such as grid edit controls, inplace editors, etc.
*/
public InplaceEditingLayer getInplaceEditingLayer() {
return myInplaceEditingLayer;
@@ -648,7 +691,7 @@ public final class GuiEditor extends JPanel implements DataProvider, ModuleProvi
public void setStringDescriptorLocale(final Locale locale) {
myRootContainer.setStringDescriptorLocale(locale);
refreshProperties();
- UIDesignerToolWindowManager.getInstance(getProject()).updateComponentTree();
+ DesignerToolWindowManager.getInstance(this).updateComponentTree();
DaemonCodeAnalyzer.getInstance(getProject()).restart();
}
@@ -686,10 +729,10 @@ public final class GuiEditor extends JPanel implements DataProvider, ModuleProvi
});
if (!anythingModified.isNull()) {
refresh();
- final UIDesignerToolWindowManager twm = UIDesignerToolWindowManager.getInstance(getProject());
- ComponentTree tree = twm.getComponentTree();
+ DesignerToolWindow designerToolWindow = DesignerToolWindowManager.getInstance(this);
+ ComponentTree tree = designerToolWindow.getComponentTree();
if (tree != null) tree.repaint();
- PropertyInspector inspector = twm.getPropertyInspector();
+ PropertyInspector inspector = designerToolWindow.getPropertyInspector();
if (inspector != null) inspector.synchWithTree(true);
}
}
@@ -852,7 +895,7 @@ public final class GuiEditor extends JPanel implements DataProvider, ModuleProvi
restoreTabbedPaneSelectedTabs(tabbedPaneSelectedTabs);
}
myInvalid = false;
- myCardLayout.show(this, CARD_VALID);
+ myCardLayout.show(myCardPanel, CARD_VALID);
refresh();
}
catch (Exception exc) {
@@ -873,7 +916,7 @@ public final class GuiEditor extends JPanel implements DataProvider, ModuleProvi
setRootContainer(new RadRootContainer(this, "0"));
myFormInvalidLabel.setText(UIDesignerBundle.message("error.form.file.is.invalid.message", FormEditingUtil.getExceptionMessage(exc)));
myInvalid = true;
- myCardLayout.show(this, CARD_INVALID);
+ myCardLayout.show(myCardPanel, CARD_INVALID);
repaint();
}
@@ -976,14 +1019,35 @@ public final class GuiEditor extends JPanel implements DataProvider, ModuleProvi
return undoManager.isUndoInProgress() || undoManager.isRedoInProgress();
}
- private boolean isActiveEditor() {
- return UIDesignerToolWindowManager.getInstance(getProject()).getActiveFormEditor() == this;
- }
-
void hideIntentionHint() {
myQuickFixManager.hideIntentionHint();
}
+ public void showFormSource() {
+ EditorFactory editorFactory = EditorFactory.getInstance();
+
+ Editor editor = editorFactory.createViewer(myDocument, myProject);
+
+ try {
+ ((EditorEx)editor).setHighlighter(
+ new LexerEditorHighlighter(new XmlFileHighlighter(), EditorColorsManager.getInstance().getGlobalScheme()));
+
+ JComponent component = editor.getComponent();
+ component.setPreferredSize(new Dimension(640, 480));
+
+ DialogBuilder dialog = new DialogBuilder(myProject);
+
+ dialog.title("Form - " + myFile.getPresentableName()).dimensionKey("GuiDesigner.FormSource.Dialog");
+ dialog.centerPanel(component).setPreferredFocusComponent(editor.getContentComponent());
+ dialog.addOkAction();
+
+ dialog.show();
+ }
+ finally {
+ editorFactory.releaseEditor(editor);
+ }
+ }
+
private final class MyLayeredPane extends JBLayeredPane implements Scrollable {
/**
* All components allocate whole pane's area.
@@ -1051,8 +1115,7 @@ public final class GuiEditor extends JPanel implements DataProvider, ModuleProvi
}
public void update(final AnActionEvent e) {
- final UIDesignerToolWindowManager manager = UIDesignerToolWindowManager.getInstance(getProject());
- PropertyInspector inspector = manager.getPropertyInspector();
+ PropertyInspector inspector = DesignerToolWindowManager.getInstance(GuiEditor.this).getPropertyInspector();
e.getPresentation().setEnabled(inspector != null && !inspector.isEditing());
}
}
@@ -1073,9 +1136,8 @@ public final class GuiEditor extends JPanel implements DataProvider, ModuleProvi
}
public boolean canDeleteElement(@NotNull final DataContext dataContext) {
- final UIDesignerToolWindowManager manager = UIDesignerToolWindowManager.getInstance(getProject());
return
- !manager.getPropertyInspector().isEditing() &&
+ !DesignerToolWindowManager.getInstance(GuiEditor.this).getPropertyInspector().isEditing() &&
!myInplaceEditingLayer.isEditing() &&
FormEditingUtil.canDeleteSelection(GuiEditor.this);
}
@@ -1179,39 +1241,30 @@ public final class GuiEditor extends JPanel implements DataProvider, ModuleProvi
}
}
- private class MyPaletteKeyListener extends KeyAdapter {
- @Override
- public void keyPressed(KeyEvent e) {
- PaletteManager paletteManager = PaletteManager.getInstance(getProject());
- if (e.getKeyCode() == KeyEvent.VK_SHIFT && paletteManager.getActiveItem(ComponentItem.class) != null && isActiveEditor()) {
- setDesignTimeInsets(12);
- }
+ public void paletteKeyPressed(KeyEvent e) {
+ if (e.getKeyCode() == KeyEvent.VK_SHIFT && PaletteToolWindowManager.getInstance(this).getActiveItem(ComponentItem.class) != null) {
+ setDesignTimeInsets(12);
}
+ }
- @Override
- public void keyReleased(KeyEvent e) {
- if (e.getKeyCode() == KeyEvent.VK_SHIFT) {
- setDesignTimeInsets(2);
- }
+ public void paletteKeyReleased(KeyEvent e) {
+ if (e.getKeyCode() == KeyEvent.VK_SHIFT) {
+ setDesignTimeInsets(2);
}
}
- private class MyPaletteDragListener implements PaletteDragEventListener {
- public void dropActionChanged(int gestureModifiers) {
- if ((gestureModifiers & InputEvent.SHIFT_MASK) != 0 && isActiveEditor()) {
- setDesignTimeInsets(12);
- }
- else {
- setDesignTimeInsets(2);
- }
+ public void paletteDropActionChanged(int gestureModifiers) {
+ if ((gestureModifiers & InputEvent.SHIFT_MASK) != 0) {
+ setDesignTimeInsets(12);
+ }
+ else {
+ setDesignTimeInsets(2);
}
}
- private class MyPaletteSelectionListener implements ListSelectionListener {
- public void valueChanged(ListSelectionEvent e) {
- if (PaletteManager.getInstance(getProject()).getActiveItem() == null) {
- myProcessor.cancelPaletteInsert();
- }
+ public void paletteValueChanged(ListSelectionEvent e) {
+ if (PaletteToolWindowManager.getInstance(this).getActiveItem() == null) {
+ myProcessor.cancelPaletteInsert();
}
}
-}
+} \ No newline at end of file
diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/InsertComponentProcessor.java b/plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/InsertComponentProcessor.java
index b088447afa0b..4eb3f32a0ed3 100644
--- a/plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/InsertComponentProcessor.java
+++ b/plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/InsertComponentProcessor.java
@@ -17,7 +17,7 @@ package com.intellij.uiDesigner.designSurface;
import com.intellij.CommonBundle;
import com.intellij.codeInsight.FileModificationService;
-import com.intellij.ide.palette.impl.PaletteManager;
+import com.intellij.ide.palette.impl.PaletteToolWindowManager;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.diagnostic.Logger;
@@ -63,7 +63,6 @@ import java.util.Map;
public final class InsertComponentProcessor extends EventProcessor {
private static final Logger LOG = Logger.getInstance("#com.intellij.uiDesigner.designSurface.InsertComponentProcessor");
- private final PaletteManager myPaletteManager;
private final GuiEditor myEditor;
private boolean mySticky;
private RadComponent myInsertedComponent;
@@ -87,7 +86,6 @@ public final class InsertComponentProcessor extends EventProcessor {
public InsertComponentProcessor(@NotNull final GuiEditor editor) {
myEditor = editor;
myGridInsertProcessor = new GridInsertProcessor(editor);
- myPaletteManager = PaletteManager.getInstance(editor.getProject());
}
public void setSticky(final boolean sticky) {
@@ -261,7 +259,7 @@ public final class InsertComponentProcessor extends EventProcessor {
private ComponentItem getComponentToInsert() {
return (myComponentToInsert != null)
? myComponentToInsert
- : myPaletteManager.getActiveItem(ComponentItem.class);
+ : PaletteToolWindowManager.getInstance(myEditor).getActiveItem(ComponentItem.class);
}
public void processComponentInsert(@NotNull final Point point, final ComponentItem item) {
@@ -295,7 +293,7 @@ public final class InsertComponentProcessor extends EventProcessor {
setCursor(Cursor.getDefaultCursor());
if (myInsertedComponent == null) {
if (!mySticky) {
- PaletteManager.getInstance(myEditor.getProject()).clearActiveItem();
+ PaletteToolWindowManager.getInstance(myEditor).clearActiveItem();
}
return;
}
@@ -328,7 +326,7 @@ public final class InsertComponentProcessor extends EventProcessor {
checkBindTopLevelPanel();
if (!mySticky) {
- PaletteManager.getInstance(myEditor.getProject()).clearActiveItem();
+ PaletteToolWindowManager.getInstance(myEditor).clearActiveItem();
}
myEditor.refreshAndSave(false);
@@ -578,7 +576,7 @@ public final class InsertComponentProcessor extends EventProcessor {
}
public Cursor processMouseMoveEvent(final MouseEvent e) {
- final ComponentItem componentItem = myPaletteManager.getActiveItem(ComponentItem.class);
+ final ComponentItem componentItem = PaletteToolWindowManager.getInstance(myEditor).getActiveItem(ComponentItem.class);
if (componentItem != null) {
return myGridInsertProcessor.processMouseMoveEvent(e.getPoint(), false, new ComponentItemDragObject(componentItem));
}
diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/MainProcessor.java b/plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/MainProcessor.java
index 3816a3aa66f8..951ae951f56e 100644
--- a/plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/MainProcessor.java
+++ b/plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/MainProcessor.java
@@ -15,7 +15,7 @@
*/
package com.intellij.uiDesigner.designSurface;
-import com.intellij.ide.palette.impl.PaletteManager;
+import com.intellij.ide.palette.impl.PaletteToolWindowManager;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.uiDesigner.FormEditingUtil;
@@ -58,7 +58,7 @@ public final class MainProcessor extends EventProcessor{
if (e.getKeyCode() == KeyEvent.VK_SHIFT) {
if (e.getID() == KeyEvent.KEY_PRESSED) {
if ((myCurrentProcessor != null && myCurrentProcessor.isDragActive()) ||
- (PaletteManager.getInstance(myEditor.getProject()).getActiveItem(ComponentItem.class) != null &&
+ (PaletteToolWindowManager.getInstance(myEditor).getActiveItem(ComponentItem.class) != null &&
myCurrentProcessor != myInsertComponentProcessor)) {
myEditor.setDesignTimeInsets(12);
}
@@ -151,7 +151,7 @@ public final class MainProcessor extends EventProcessor{
Cursor cursor = Cursor.getDefaultCursor();
if(id==MouseEvent.MOUSE_MOVED){
- if (PaletteManager.getInstance(myEditor.getProject()).getActiveItem(ComponentItem.class) != null) {
+ if (PaletteToolWindowManager.getInstance(myEditor).getActiveItem(ComponentItem.class) != null) {
if (myInsertFeedbackEnabled) {
cursor = myInsertComponentProcessor.processMouseMoveEvent(e);
}
@@ -292,7 +292,7 @@ public final class MainProcessor extends EventProcessor{
return;
}
- final ComponentItem selectedItem = PaletteManager.getInstance(myEditor.getProject()).getActiveItem(ComponentItem.class);
+ final ComponentItem selectedItem = PaletteToolWindowManager.getInstance(myEditor).getActiveItem(ComponentItem.class);
if (selectedItem != null) {
myInsertComponentProcessor.setSticky(UIUtil.isControlKeyDown(e));
myCurrentProcessor = myInsertComponentProcessor;
@@ -341,7 +341,7 @@ public final class MainProcessor extends EventProcessor{
return true;
}
}
- else if (PaletteManager.getInstance(myEditor.getProject()).getActiveItem(ComponentItem.class) != null) {
+ else if (PaletteToolWindowManager.getInstance(myEditor).getActiveItem(ComponentItem.class) != null) {
cancelPaletteInsert();
return true;
}
@@ -349,7 +349,7 @@ public final class MainProcessor extends EventProcessor{
}
void cancelPaletteInsert() {
- PaletteManager.getInstance(myEditor.getProject()).clearActiveItem();
+ PaletteToolWindowManager.getInstance(myEditor).clearActiveItem();
myEditor.getLayeredPane().setCursor(Cursor.getDefaultCursor());
myEditor.getActiveDecorationLayer().removeFeedback();
}
diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/PassiveDecorationLayer.java b/plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/PassiveDecorationLayer.java
index 070612857a53..1153adadfdf0 100644
--- a/plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/PassiveDecorationLayer.java
+++ b/plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/PassiveDecorationLayer.java
@@ -17,7 +17,7 @@ package com.intellij.uiDesigner.designSurface;
import com.intellij.uiDesigner.FormEditingUtil;
import com.intellij.uiDesigner.componentTree.ComponentTree;
-import com.intellij.uiDesigner.propertyInspector.UIDesignerToolWindowManager;
+import com.intellij.uiDesigner.propertyInspector.DesignerToolWindowManager;
import com.intellij.uiDesigner.radComponents.RadButtonGroup;
import com.intellij.uiDesigner.radComponents.RadComponent;
import com.intellij.uiDesigner.radComponents.RadRootContainer;
@@ -56,7 +56,7 @@ class PassiveDecorationLayer extends JComponent{
final Set<RadButtonGroup> paintedGroups = new HashSet<RadButtonGroup>();
final RadRootContainer rootContainer = myEditor.getRootContainer();
- final ComponentTree componentTree = UIDesignerToolWindowManager.getInstance(component.getProject()).getComponentTree();
+ final ComponentTree componentTree = DesignerToolWindowManager.getInstance(myEditor).getComponentTree();
final Collection<RadButtonGroup> selectedGroups = componentTree != null
? componentTree.getSelectedElements(RadButtonGroup.class)
: Collections.<RadButtonGroup>emptyList();
diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/QuickFixManagerImpl.java b/plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/QuickFixManagerImpl.java
index 15e1c34daf78..241ae963a3cd 100644
--- a/plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/QuickFixManagerImpl.java
+++ b/plugins/ui-designer/src/com/intellij/uiDesigner/designSurface/QuickFixManagerImpl.java
@@ -18,14 +18,12 @@ package com.intellij.uiDesigner.designSurface;
import com.intellij.uiDesigner.ErrorAnalyzer;
import com.intellij.uiDesigner.ErrorInfo;
import com.intellij.uiDesigner.FormEditingUtil;
-import com.intellij.uiDesigner.propertyInspector.UIDesignerToolWindowManager;
+import com.intellij.uiDesigner.componentTree.ComponentSelectionListener;
import com.intellij.uiDesigner.quickFixes.QuickFixManager;
import com.intellij.uiDesigner.radComponents.RadComponent;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
-import javax.swing.event.TreeSelectionEvent;
-import javax.swing.event.TreeSelectionListener;
import java.awt.*;
import java.util.ArrayList;
@@ -35,9 +33,9 @@ import java.util.ArrayList;
public class QuickFixManagerImpl extends QuickFixManager<GlassLayer> {
public QuickFixManagerImpl(final GuiEditor editor, final GlassLayer component, final JViewport viewPort) {
super(editor, component, viewPort);
- final UIDesignerToolWindowManager toolWindowManager = UIDesignerToolWindowManager.getInstance(editor.getProject());
- toolWindowManager.addComponentSelectionListener(new TreeSelectionListener() {
- public void valueChanged(TreeSelectionEvent e) {
+ editor.addComponentSelectionListener(new ComponentSelectionListener() {
+ @Override
+ public void selectedComponentChanged(GuiEditor source) {
hideIntentionHint();
updateIntentionHintVisibility();
}
diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/editor/UIFormEditor.java b/plugins/ui-designer/src/com/intellij/uiDesigner/editor/UIFormEditor.java
index 796b880b6244..c457500c703c 100644
--- a/plugins/ui-designer/src/com/intellij/uiDesigner/editor/UIFormEditor.java
+++ b/plugins/ui-designer/src/com/intellij/uiDesigner/editor/UIFormEditor.java
@@ -48,14 +48,14 @@ public final class UIFormEditor extends UserDataHolderBase implements /*Navigata
private final GuiEditor myEditor;
private UIFormEditor.MyBackgroundEditorHighlighter myBackgroundEditorHighlighter;
- public UIFormEditor(final Project project, final VirtualFile file){
+ public UIFormEditor(@NotNull final Project project, @NotNull final VirtualFile file){
final VirtualFile vf = file instanceof LightVirtualFile ? ((LightVirtualFile)file).getOriginalFile() : file;
final Module module = ModuleUtil.findModuleForFile(vf, project);
if (module == null) {
throw new IllegalArgumentException("No module for file " + file + " in project " + project);
}
myFile = file;
- myEditor = new GuiEditor(project, module, file);
+ myEditor = new GuiEditor(this, project, module, file);
}
@NotNull
diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/editor/UIFormEditorProvider.java b/plugins/ui-designer/src/com/intellij/uiDesigner/editor/UIFormEditorProvider.java
index 8500c056204a..1e043a3be4af 100644
--- a/plugins/ui-designer/src/com/intellij/uiDesigner/editor/UIFormEditorProvider.java
+++ b/plugins/ui-designer/src/com/intellij/uiDesigner/editor/UIFormEditorProvider.java
@@ -15,7 +15,6 @@
*/
package com.intellij.uiDesigner.editor;
-import com.intellij.openapi.application.ex.ApplicationManagerEx;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.fileEditor.FileEditorPolicy;
@@ -66,9 +65,6 @@ public final class UIFormEditorProvider implements FileEditorProvider, DumbAware
}
@NotNull public FileEditorPolicy getPolicy() {
- return
- ApplicationManagerEx.getApplicationEx().isInternal() ?
- FileEditorPolicy.PLACE_BEFORE_DEFAULT_EDITOR : FileEditorPolicy.HIDE_DEFAULT_EDITOR;
+ return FileEditorPolicy.HIDE_DEFAULT_EDITOR;
}
-
-}
+} \ No newline at end of file
diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/DesignerToolWindow.java b/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/DesignerToolWindow.java
new file mode 100644
index 000000000000..e8164e19e21e
--- /dev/null
+++ b/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/DesignerToolWindow.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.uiDesigner.propertyInspector;
+
+import com.intellij.designer.LightToolWindowContent;
+import com.intellij.openapi.actionSystem.DataProvider;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.Splitter;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.ui.IdeBorderFactory;
+import com.intellij.ui.ScrollPaneFactory;
+import com.intellij.ui.SideBorder;
+import com.intellij.uiDesigner.componentTree.ComponentTree;
+import com.intellij.uiDesigner.componentTree.ComponentTreeBuilder;
+import com.intellij.uiDesigner.designSurface.GuiEditor;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeModel;
+import java.awt.*;
+
+/**
+ * @author Alexander Lobas
+ */
+public class DesignerToolWindow implements LightToolWindowContent {
+ private final MyToolWindowPanel myToolWindowPanel = new MyToolWindowPanel();
+ private ComponentTree myComponentTree;
+ private ComponentTreeBuilder myComponentTreeBuilder;
+ private PropertyInspector myPropertyInspector;
+
+ public DesignerToolWindow(Project project) {
+ myComponentTree = new ComponentTree(project);
+
+ JScrollPane scrollPane = ScrollPaneFactory.createScrollPane(myComponentTree);
+ scrollPane.setBorder(IdeBorderFactory.createBorder(SideBorder.BOTTOM));
+ scrollPane.setPreferredSize(new Dimension(250, -1));
+ myComponentTree.initQuickFixManager(scrollPane.getViewport());
+
+ myPropertyInspector = new PropertyInspector(project, myComponentTree);
+
+ myToolWindowPanel.setFirstComponent(scrollPane);
+ myToolWindowPanel.setSecondComponent(myPropertyInspector);
+ }
+
+ @Override
+ public void dispose() {
+ clearTreeBuilder();
+ myToolWindowPanel.dispose();
+ myComponentTree = null;
+ myPropertyInspector = null;
+ }
+
+ private void clearTreeBuilder() {
+ if (myComponentTreeBuilder != null) {
+ Disposer.dispose(myComponentTreeBuilder);
+ myComponentTreeBuilder = null;
+ }
+ }
+
+ public void update(GuiEditor designer) {
+ clearTreeBuilder();
+
+ myComponentTree.setModel(new DefaultTreeModel(new DefaultMutableTreeNode()));
+ myComponentTree.setEditor(designer);
+ myPropertyInspector.setEditor(designer);
+
+ if (designer == null) {
+ myComponentTree.setFormEditor(null);
+ }
+ else {
+ myComponentTree.setFormEditor(designer.getEditor());
+ myComponentTreeBuilder = new ComponentTreeBuilder(myComponentTree, designer);
+ }
+ }
+
+ public JComponent getToolWindowPanel() {
+ return myToolWindowPanel;
+ }
+
+ public ComponentTree getComponentTree() {
+ return myComponentTree;
+ }
+
+ public ComponentTreeBuilder getComponentTreeBuilder() {
+ return myComponentTreeBuilder;
+ }
+
+ public void updateComponentTree() {
+ if (myComponentTreeBuilder != null) {
+ myComponentTreeBuilder.queueUpdate();
+ }
+ }
+
+ public PropertyInspector getPropertyInspector() {
+ return myPropertyInspector;
+ }
+
+ public void refreshErrors() {
+ if (myComponentTree != null) {
+ myComponentTree.refreshIntentionHint();
+ myComponentTree.repaint(myComponentTree.getVisibleRect());
+ }
+
+ // PropertyInspector
+ if (myPropertyInspector != null) {
+ myPropertyInspector.refreshIntentionHint();
+ myPropertyInspector.repaint(myPropertyInspector.getVisibleRect());
+ }
+ }
+
+ private class MyToolWindowPanel extends Splitter implements DataProvider {
+ MyToolWindowPanel() {
+ super(true, 0.33f);
+ }
+
+ @Nullable
+ public Object getData(@NonNls String dataId) {
+ if (GuiEditor.DATA_KEY.is(dataId) && myComponentTree != null) {
+ return myComponentTree.getData(dataId);
+ }
+ return null;
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/DesignerToolWindowManager.java b/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/DesignerToolWindowManager.java
new file mode 100644
index 000000000000..36e6935dae99
--- /dev/null
+++ b/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/DesignerToolWindowManager.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.uiDesigner.propertyInspector;
+
+import com.intellij.designer.DesignerEditorPanelFacade;
+import com.intellij.designer.LightToolWindow;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.fileEditor.FileEditorManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.wm.ToolWindowAnchor;
+import com.intellij.openapi.wm.ToolWindowManager;
+import com.intellij.openapi.wm.impl.content.ToolWindowContentUi;
+import com.intellij.ui.content.Content;
+import com.intellij.ui.content.ContentManager;
+import com.intellij.uiDesigner.AbstractToolWindowManager;
+import com.intellij.uiDesigner.UIDesignerBundle;
+import com.intellij.uiDesigner.designSurface.GuiEditor;
+import icons.UIDesignerIcons;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author Alexander Lobas
+ */
+public class DesignerToolWindowManager extends AbstractToolWindowManager {
+ private final DesignerToolWindow myToolWindowPanel;
+
+ public DesignerToolWindowManager(Project project, FileEditorManager fileEditorManager) {
+ super(project, fileEditorManager);
+ myToolWindowPanel = ApplicationManager.getApplication().isHeadlessEnvironment() ? null : new DesignerToolWindow(project);
+ }
+
+ public static DesignerToolWindow getInstance(GuiEditor designer) {
+ DesignerToolWindowManager manager = getInstance(designer.getProject());
+ if (manager.isEditorMode()) {
+ return (DesignerToolWindow)manager.getContent(designer);
+ }
+ return manager.myToolWindowPanel;
+ }
+
+ public static DesignerToolWindowManager getInstance(Project project) {
+ return project.getComponent(DesignerToolWindowManager.class);
+ }
+
+ @Nullable
+ public GuiEditor getActiveFormEditor() {
+ return (GuiEditor)getActiveDesigner();
+ }
+
+ @Override
+ protected void initToolWindow() {
+ myToolWindow = ToolWindowManager.getInstance(myProject).registerToolWindow(UIDesignerBundle.message("toolwindow.ui.designer.name"),
+ false, getAnchor(), myProject, true);
+ myToolWindow.setIcon(UIDesignerIcons.ToolWindowUIDesigner);
+
+ if (!ApplicationManager.getApplication().isHeadlessEnvironment()) {
+ myToolWindow.getComponent().putClientProperty(ToolWindowContentUi.HIDE_ID_LABEL, "true");
+ }
+
+ initGearActions();
+
+ ContentManager contentManager = myToolWindow.getContentManager();
+ Content content =
+ contentManager.getFactory()
+ .createContent(myToolWindowPanel.getToolWindowPanel(), UIDesignerBundle.message("toolwindow.ui.designer.title"), false);
+ content.setCloseable(false);
+ content.setPreferredFocusableComponent(myToolWindowPanel.getComponentTree());
+ contentManager.addContent(content);
+ contentManager.setSelectedContent(content, true);
+ myToolWindow.setAvailable(false, null);
+ }
+
+ @Override
+ protected void updateToolWindow(@Nullable DesignerEditorPanelFacade designer) {
+ myToolWindowPanel.update((GuiEditor)designer);
+
+ if (designer == null) {
+ myToolWindow.setAvailable(false, null);
+ }
+ else {
+ myToolWindow.setAvailable(true, null);
+ myToolWindow.show(null);
+ }
+ }
+
+ @Override
+ protected ToolWindowAnchor getAnchor() {
+ return ToolWindowAnchor.LEFT;
+ }
+
+ @Override
+ protected LightToolWindow createContent(@NotNull DesignerEditorPanelFacade designer) {
+ DesignerToolWindow toolWindowContent = new DesignerToolWindow(myProject);
+ toolWindowContent.update((GuiEditor)designer);
+
+ return createContent(designer,
+ toolWindowContent,
+ UIDesignerBundle.message("toolwindow.ui.designer.title"),
+ UIDesignerIcons.ToolWindowUIDesigner,
+ toolWindowContent.getToolWindowPanel(),
+ toolWindowContent.getComponentTree(),
+ 320,
+ null);
+ }
+
+ @Override
+ public void disposeComponent() {
+ if (myToolWindowPanel != null) {
+ myToolWindowPanel.dispose();
+ }
+ }
+
+ @NotNull
+ @Override
+ public String getComponentName() {
+ return "UIDesignerToolWindowManager";
+ }
+} \ No newline at end of file
diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/PropertyInspectorTable.java b/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/PropertyInspectorTable.java
index 059ba0407107..e4b7fccedbff 100644
--- a/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/PropertyInspectorTable.java
+++ b/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/PropertyInspectorTable.java
@@ -281,7 +281,8 @@ public final class PropertyInspectorTable extends Table implements DataProvider{
return myEditor;
}
else if (PlatformDataKeys.FILE_EDITOR.is(dataId)) {
- return UIDesignerToolWindowManager.getInstance(myProject).getActiveFormFileEditor();
+ GuiEditor designer = DesignerToolWindowManager.getInstance(myProject).getActiveFormEditor();
+ return designer == null ? null : designer.getEditor();
}
else if (PlatformDataKeys.HELP_ID.is(dataId)) {
return ourHelpID;
diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/UIDesignerToolWindowManager.java b/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/UIDesignerToolWindowManager.java
deleted file mode 100644
index a30b4c65db07..000000000000
--- a/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/UIDesignerToolWindowManager.java
+++ /dev/null
@@ -1,264 +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.uiDesigner.propertyInspector;
-
-import com.intellij.openapi.actionSystem.DataProvider;
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.components.ProjectComponent;
-import com.intellij.openapi.fileEditor.FileEditor;
-import com.intellij.openapi.fileEditor.FileEditorManager;
-import com.intellij.openapi.fileEditor.FileEditorManagerEvent;
-import com.intellij.openapi.fileEditor.FileEditorManagerListener;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.startup.StartupManager;
-import com.intellij.openapi.ui.Splitter;
-import com.intellij.openapi.util.Disposer;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.openapi.wm.ToolWindow;
-import com.intellij.openapi.wm.ToolWindowAnchor;
-import com.intellij.openapi.wm.ToolWindowManager;
-import com.intellij.ui.IdeBorderFactory;
-import com.intellij.ui.ScrollPaneFactory;
-import com.intellij.ui.SideBorder;
-import com.intellij.uiDesigner.UIDesignerBundle;
-import com.intellij.uiDesigner.componentTree.ComponentTree;
-import com.intellij.uiDesigner.componentTree.ComponentTreeBuilder;
-import com.intellij.uiDesigner.designSurface.GuiEditor;
-import com.intellij.uiDesigner.editor.UIFormEditor;
-import com.intellij.util.containers.ContainerUtil;
-import com.intellij.util.ui.update.MergingUpdateQueue;
-import com.intellij.util.ui.update.Update;
-import icons.UIDesignerIcons;
-import org.jetbrains.annotations.NonNls;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import javax.swing.*;
-import javax.swing.event.TreeSelectionListener;
-import javax.swing.tree.DefaultMutableTreeNode;
-import javax.swing.tree.DefaultTreeModel;
-import java.awt.*;
-import java.util.List;
-
-/**
- * @author yole
- */
-public class UIDesignerToolWindowManager implements ProjectComponent {
- private final Project myProject;
- private MyToolWindowPanel myToolWindowPanel;
- private ComponentTree myComponentTree;
- private ComponentTreeBuilder myComponentTreeBuilder;
- private PropertyInspector myPropertyInspector;
- private final FileEditorManager myFileEditorManager;
- private ToolWindow myToolWindow;
- private boolean myToolWindowReady = false;
- private boolean myToolWindowDisposed = false;
- private final List<TreeSelectionListener> myPendingListeners = ContainerUtil.createLockFreeCopyOnWriteList();
-
- public UIDesignerToolWindowManager(final Project project, final FileEditorManager fileEditorManager) {
- myProject = project;
- myFileEditorManager = fileEditorManager;
- MyFileEditorManagerListener listener = new MyFileEditorManagerListener();
- myFileEditorManager.addFileEditorManagerListener(listener,project);
- }
-
- public void projectOpened() {
- StartupManager.getInstance(myProject).registerPostStartupActivity(new Runnable() {
- public void run() {
- myToolWindowReady = true;
- }
- });
- }
-
- private void checkInitToolWindow() {
- if (myToolWindowReady && !myToolWindowDisposed && myToolWindow == null) {
- initToolWindow();
- }
- }
-
- private void initToolWindow() {
- myToolWindowPanel = new MyToolWindowPanel();
- myComponentTree = new ComponentTree(myProject);
- for (TreeSelectionListener listener : myPendingListeners) {
- myComponentTree.addTreeSelectionListener(listener);
- }
- myPendingListeners.clear();
- final JScrollPane scrollPane = ScrollPaneFactory.createScrollPane(myComponentTree);
- scrollPane.setBorder(IdeBorderFactory.createBorder(SideBorder.BOTTOM));
- scrollPane.setPreferredSize(new Dimension(250, -1));
- myComponentTree.initQuickFixManager(scrollPane.getViewport());
- myPropertyInspector= new PropertyInspector(myProject, myComponentTree);
- myToolWindowPanel.setFirstComponent(scrollPane);
- myToolWindowPanel.setSecondComponent(myPropertyInspector);
- myToolWindow = ToolWindowManager.getInstance(myProject).registerToolWindow(UIDesignerBundle.message("toolwindow.ui.designer"),
- myToolWindowPanel,
- ToolWindowAnchor.LEFT, myProject, true);
- myToolWindow.setIcon(UIDesignerIcons.ToolWindowUIDesigner);
- myToolWindow.setAvailable(false, null);
- }
-
- public void projectClosed() {
- if (myToolWindowPanel != null) {
- if (myComponentTreeBuilder != null) {
- Disposer.dispose(myComponentTreeBuilder);
- }
- myToolWindowPanel = null;
- myToolWindow = null;
- myToolWindowDisposed = true;
- }
- }
-
- @NotNull @NonNls
- public String getComponentName() {
- return "UIDesignerToolWindowManager";
- }
-
- public void initComponent() {
- }
-
- public void disposeComponent() {
- }
-
- private final MergingUpdateQueue myQueue = new MergingUpdateQueue("property.inspector", 200, true, null);
-
- private void processFileEditorChange(final UIFormEditor newEditor) {
- myQueue.cancelAllUpdates();
- myQueue.queue(new Update("update") {
- public void run() {
- if (!myToolWindowReady || myToolWindowDisposed) return;
- GuiEditor activeFormEditor = newEditor != null ? newEditor.getEditor() : null;
- if (myToolWindow == null) {
- if (activeFormEditor == null) return;
- initToolWindow();
- }
- if (myComponentTreeBuilder != null) {
- Disposer.dispose(myComponentTreeBuilder);
- myComponentTreeBuilder = null;
- }
- myComponentTree.setModel(new DefaultTreeModel(new DefaultMutableTreeNode()));
- myComponentTree.setEditor(activeFormEditor);
- myComponentTree.setFormEditor(newEditor);
- myPropertyInspector.setEditor(activeFormEditor);
- if (activeFormEditor == null) {
- myToolWindow.setAvailable(false, null);
- }
- else {
- myComponentTreeBuilder = new ComponentTreeBuilder(myComponentTree, activeFormEditor);
- myToolWindow.setAvailable(true, null);
- myToolWindow.show(null);
- }
- }
- });
- }
-
- @Nullable
- public UIFormEditor getActiveFormFileEditor() {
- FileEditor[] fileEditors = myFileEditorManager.getSelectedEditors();
- for (FileEditor fileEditor : fileEditors) {
- if (fileEditor instanceof UIFormEditor) {
- return (UIFormEditor)fileEditor;
- }
- }
- return null;
- }
-
- @Nullable
- public GuiEditor getActiveFormEditor() {
- UIFormEditor formEditor = getActiveFormFileEditor();
- return formEditor == null ? null : formEditor.getEditor();
- }
-
- public static UIDesignerToolWindowManager getInstance(Project project) {
- return project.getComponent(UIDesignerToolWindowManager.class);
- }
-
- public ComponentTree getComponentTree() {
- checkInitToolWindow();
- return myComponentTree;
- }
-
- public ComponentTreeBuilder getComponentTreeBuilder() {
- return myComponentTreeBuilder;
- }
-
- public PropertyInspector getPropertyInspector() {
- return myPropertyInspector;
- }
-
- public void refreshErrors() {
- if (myComponentTree != null) {
- myComponentTree.refreshIntentionHint();
- myComponentTree.repaint(myComponentTree.getVisibleRect());
- }
-
- // PropertyInspector
- if (myPropertyInspector != null) {
- myPropertyInspector.refreshIntentionHint();
- myPropertyInspector.repaint(myPropertyInspector.getVisibleRect());
- }
- }
-
- public void updateComponentTree() {
- final ComponentTreeBuilder builder = myComponentTreeBuilder;
- if (builder != null) {
- builder.queueUpdate();
- }
- }
-
- public void addComponentSelectionListener(TreeSelectionListener treeSelectionListener) {
- if (myComponentTree != null) {
- myComponentTree.addTreeSelectionListener(treeSelectionListener);
- }
- else {
- myPendingListeners.add(treeSelectionListener);
- }
- }
-
- private class MyFileEditorManagerListener implements FileEditorManagerListener {
- public void fileOpened(@NotNull FileEditorManager source, @NotNull VirtualFile file) {
- processFileEditorChange(getActiveFormFileEditor());
- }
-
- public void fileClosed(@NotNull FileEditorManager source, @NotNull VirtualFile file) {
- ApplicationManager.getApplication().invokeLater(new Runnable() {
- @Override
- public void run() {
- processFileEditorChange(getActiveFormFileEditor());
- }
- });
- }
-
- public void selectionChanged(@NotNull FileEditorManagerEvent event) {
- UIFormEditor newEditor = event.getNewEditor() instanceof UIFormEditor ? (UIFormEditor)event.getNewEditor() : null;
- processFileEditorChange(newEditor);
- }
- }
-
- private class MyToolWindowPanel extends Splitter implements DataProvider {
- MyToolWindowPanel() {
- super(true, 0.33f);
- }
-
- @Nullable
- public Object getData(@NonNls String dataId) {
- if (GuiEditor.DATA_KEY.is(dataId)) {
- return getActiveFormEditor();
- }
- return null;
- }
- }
-}
diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/editors/BindingEditor.java b/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/editors/BindingEditor.java
index 03c65b6640b1..c7547c7ff710 100644
--- a/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/editors/BindingEditor.java
+++ b/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/editors/BindingEditor.java
@@ -25,8 +25,8 @@ import com.intellij.uiDesigner.FormEditingUtil;
import com.intellij.uiDesigner.core.Spacer;
import com.intellij.uiDesigner.inspections.FormInspectionUtil;
import com.intellij.uiDesigner.lw.IRootContainer;
+import com.intellij.uiDesigner.propertyInspector.DesignerToolWindowManager;
import com.intellij.uiDesigner.propertyInspector.InplaceContext;
-import com.intellij.uiDesigner.propertyInspector.UIDesignerToolWindowManager;
import com.intellij.uiDesigner.propertyInspector.properties.BindingProperty;
import com.intellij.uiDesigner.radComponents.RadComponent;
import com.intellij.uiDesigner.radComponents.RadErrorComponent;
@@ -67,7 +67,8 @@ public final class BindingEditor extends ComboBoxPropertyEditor<String> {
SwingUtilities.invokeLater(
new Runnable(){
public void run(){
- UIDesignerToolWindowManager.getInstance(project).getPropertyInspector().requestFocus();
+ DesignerToolWindowManager.getInstance(DesignerToolWindowManager.getInstance(project).getActiveFormEditor())
+ .getPropertyInspector().requestFocus();
}
}
);
diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/editors/string/StringEditor.java b/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/editors/string/StringEditor.java
index 99a6bbc82fcf..2f22910f08af 100644
--- a/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/editors/string/StringEditor.java
+++ b/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/editors/string/StringEditor.java
@@ -26,9 +26,9 @@ import com.intellij.ui.DocumentAdapter;
import com.intellij.uiDesigner.UIDesignerBundle;
import com.intellij.uiDesigner.designSurface.GuiEditor;
import com.intellij.uiDesigner.lw.StringDescriptor;
-import com.intellij.uiDesigner.propertyInspector.PropertyEditor;
-import com.intellij.uiDesigner.propertyInspector.UIDesignerToolWindowManager;
+import com.intellij.uiDesigner.propertyInspector.DesignerToolWindowManager;
import com.intellij.uiDesigner.propertyInspector.InplaceContext;
+import com.intellij.uiDesigner.propertyInspector.PropertyEditor;
import com.intellij.uiDesigner.propertyInspector.properties.IntroStringProperty;
import com.intellij.uiDesigner.radComponents.RadComponent;
import com.intellij.util.ui.UIUtil;
@@ -170,7 +170,7 @@ public final class StringEditor extends PropertyEditor<StringDescriptor> {
public void actionPerformed(final ActionEvent e) {
// 1. Show editor dialog
- final GuiEditor guiEditor = UIDesignerToolWindowManager.getInstance(myProject).getActiveFormEditor();
+ final GuiEditor guiEditor = DesignerToolWindowManager.getInstance(myProject).getActiveFormEditor();
LOG.assertTrue(guiEditor != null);
final StringEditorDialog dialog = new StringEditorDialog(
diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/properties/BindingProperty.java b/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/properties/BindingProperty.java
index 58306f72167a..70d7d3017a95 100644
--- a/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/properties/BindingProperty.java
+++ b/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/properties/BindingProperty.java
@@ -39,10 +39,10 @@ import com.intellij.uiDesigner.compiler.AsmCodeGenerator;
import com.intellij.uiDesigner.designSurface.GuiEditor;
import com.intellij.uiDesigner.designSurface.InsertComponentProcessor;
import com.intellij.uiDesigner.inspections.FormInspectionUtil;
+import com.intellij.uiDesigner.propertyInspector.DesignerToolWindowManager;
import com.intellij.uiDesigner.propertyInspector.Property;
import com.intellij.uiDesigner.propertyInspector.PropertyEditor;
import com.intellij.uiDesigner.propertyInspector.PropertyRenderer;
-import com.intellij.uiDesigner.propertyInspector.UIDesignerToolWindowManager;
import com.intellij.uiDesigner.propertyInspector.editors.BindingEditor;
import com.intellij.uiDesigner.propertyInspector.renderers.LabelPropertyRenderer;
import com.intellij.uiDesigner.quickFixes.CreateFieldFix;
@@ -177,7 +177,7 @@ public final class BindingProperty extends Property<RadComponent, String> {
}
// Commit document before refactoring starts
- GuiEditor editor = UIDesignerToolWindowManager.getInstance(project).getActiveFormEditor();
+ GuiEditor editor = DesignerToolWindowManager.getInstance(project).getActiveFormEditor();
if (editor != null) {
editor.refreshAndSave(false);
}
diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/quickFixes/ShowHintAction.java b/plugins/ui-designer/src/com/intellij/uiDesigner/quickFixes/ShowHintAction.java
index f08294c5cbff..beb87f197151 100644
--- a/plugins/ui-designer/src/com/intellij/uiDesigner/quickFixes/ShowHintAction.java
+++ b/plugins/ui-designer/src/com/intellij/uiDesigner/quickFixes/ShowHintAction.java
@@ -17,8 +17,8 @@ package com.intellij.uiDesigner.quickFixes;
import com.intellij.openapi.actionSystem.*;
import com.intellij.uiDesigner.designSurface.GuiEditor;
+import com.intellij.uiDesigner.propertyInspector.DesignerToolWindowManager;
import com.intellij.uiDesigner.propertyInspector.PropertyInspector;
-import com.intellij.uiDesigner.propertyInspector.UIDesignerToolWindowManager;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
@@ -46,8 +46,7 @@ final class ShowHintAction extends AnAction {
myManager.showIntentionHint();
// 2. Commit possible non committed value and show popup
- final UIDesignerToolWindowManager manager = UIDesignerToolWindowManager.getInstance(editor.getProject());
- final PropertyInspector propertyInspector = manager.getPropertyInspector();
+ final PropertyInspector propertyInspector = DesignerToolWindowManager.getInstance(myManager.getEditor()).getPropertyInspector();
if(propertyInspector != null && propertyInspector.isEditing()) {
propertyInspector.stopEditing();
}
diff --git a/plugins/ui-designer/src/messages/UIDesignerBundle.properties b/plugins/ui-designer/src/messages/UIDesignerBundle.properties
index 9fabc533616f..d544e3993776 100644
--- a/plugins/ui-designer/src/messages/UIDesignerBundle.properties
+++ b/plugins/ui-designer/src/messages/UIDesignerBundle.properties
@@ -271,7 +271,8 @@ add.component.choose.icon=Choose Icon File
inspection.no.scroll.pane=Scrollable component not in JScrollPane
inspection.no.scroll.pane.quickfix=Surround with JScrollPane
surround.with.popup.title=Surround With
-toolwindow.ui.designer=UI Designer
+toolwindow.ui.designer.name=UI Designer
+toolwindow.ui.designer.title=Component Tree
error.cannot.delete.unused.field=Cannot delete unused field: {0}
command.delete.unused.field=Delete Unused Field
error.for.component=Component {0}: {1}
@@ -546,6 +547,8 @@ action.GuiDesigner.GenerateMain.text=Form main()
action.GuiDesigner.GenerateMain.description=Generate a main() method to show the UI form
action.GuiDesigner.ReloadCustomComponents.text=Reload Custom Components
action.GuiDesigner.ReloadCustomComponents.description=Reload modified custom component classes and recreate forms
+action.GuiDesigner.FormSource.text=Form Source
+action.GuiDesigner.FormSource.description=Show form XML content
action.NewDialog.text=Dialog
action.NewForm.text=GUI Form
default.field.accessibility=Default accessibility &for UI-bound fields\:
diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/run/HighlightingOutputConsole.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/run/HighlightingOutputConsole.java
index 350973b4369d..90f088d86ad6 100644
--- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/run/HighlightingOutputConsole.java
+++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/run/HighlightingOutputConsole.java
@@ -29,6 +29,7 @@ import com.intellij.openapi.fileTypes.FileTypeEditorHighlighterProviders;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
@@ -107,6 +108,7 @@ public class HighlightingOutputConsole extends AdditionalTabComponent implements
}
}
+ @NotNull
public String getTabTitle() {
return TAB_TITLE;
}
diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/run/XsltRunConfiguration.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/run/XsltRunConfiguration.java
index b45a08825d01..8cf2c67d4bc9 100644
--- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/run/XsltRunConfiguration.java
+++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/run/XsltRunConfiguration.java
@@ -15,7 +15,6 @@
*/
package org.intellij.lang.xpath.xslt.run;
-import com.intellij.diagnostic.logging.DebuggerLogConsoleManager;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.Executor;
import com.intellij.execution.configurations.*;
@@ -140,32 +139,29 @@ public final class XsltRunConfiguration extends LocatableConfigurationBase imple
return state;
}
- //invoke before run/debug tabs are shown.
- //Should be overriden to add additional tabs for run/debug toolwindow
@Override
public void createAdditionalTabComponents(final AdditionalTabComponentManager manager, ProcessHandler startedProcess) {
- if (myOutputType == OutputType.CONSOLE) {
- final HighlightingOutputConsole console = new HighlightingOutputConsole(getProject(), myFileType);
-
- final List<XsltRunnerExtension> extensions = XsltRunnerExtension.getExtensions(this, manager instanceof DebuggerLogConsoleManager);
- boolean consoleTabAdded = false;
- for (XsltRunnerExtension extension : extensions) {
- if (extension.createTabs(getProject(), manager, console, startedProcess)) {
- consoleTabAdded = true;
- }
- }
- if (!consoleTabAdded) {
- manager.addAdditionalTabComponent(console, console.getTabTitle()); // TODO: verify parameter
- }
-
- final OutputTabAdapter listener = new OutputTabAdapter(startedProcess, console);
+ if (myOutputType == OutputType.CONSOLE) {
+ final HighlightingOutputConsole console = new HighlightingOutputConsole(getProject(), myFileType);
+
+ boolean consoleTabAdded = false;
+ for (XsltRunnerExtension extension : XsltRunnerExtension.getExtensions(this, false /* doesn't matter, xslt debugger uses own flag */)) {
+ if (extension.createTabs(getProject(), manager, console, startedProcess)) {
+ consoleTabAdded = true;
+ }
+ }
+ if (!consoleTabAdded) {
+ manager.addAdditionalTabComponent(console, console.getTabTitle()); // TODO: verify parameter
+ }
- if (startedProcess.isStartNotified()) {
- listener.startNotified(new ProcessEvent(startedProcess));
- } else {
- startedProcess.addProcessListener(listener);
- }
+ final OutputTabAdapter listener = new OutputTabAdapter(startedProcess, console);
+ if (startedProcess.isStartNotified()) {
+ listener.startNotified(new ProcessEvent(startedProcess));
+ }
+ else {
+ startedProcess.addProcessListener(listener);
}
+ }
}
@Override
diff --git a/plugins/xpath/xpath-view/src/org/intellij/plugins/xpathView/ShowXPathAction.java b/plugins/xpath/xpath-view/src/org/intellij/plugins/xpathView/ShowXPathAction.java
index 8423fe767e1a..748a7063b200 100644
--- a/plugins/xpath/xpath-view/src/org/intellij/plugins/xpathView/ShowXPathAction.java
+++ b/plugins/xpath/xpath-view/src/org/intellij/plugins/xpathView/ShowXPathAction.java
@@ -51,7 +51,7 @@ public class ShowXPathAction extends XPathAction {
super.update(event);
final Presentation presentation = event.getPresentation();
- if (ActionPlaces.MAIN_MENU.equals(event.getPlace()) && presentation.getText().startsWith("Show ")) {
+ if (ActionPlaces.isMainMenuOrActionSearch(event.getPlace()) && presentation.getText().startsWith("Show ")) {
final String text = presentation.getText().substring("Show ".length());
presentation.setText(Character.toUpperCase(text.charAt(0)) + text.substring(1));
}
diff --git a/plugins/xpath/xpath-view/src/org/intellij/plugins/xpathView/XPathAction.java b/plugins/xpath/xpath-view/src/org/intellij/plugins/xpathView/XPathAction.java
index 20e3597c8f2f..734ec9efe9a4 100644
--- a/plugins/xpath/xpath-view/src/org/intellij/plugins/xpathView/XPathAction.java
+++ b/plugins/xpath/xpath-view/src/org/intellij/plugins/xpathView/XPathAction.java
@@ -41,10 +41,11 @@ public abstract class XPathAction extends AnAction {
// provide icon for toolbar
if (ActionPlaces.MAIN_TOOLBAR.equals(event.getPlace())) {
updateToolbar(event);
- } else if (ActionPlaces.MAIN_MENU.equals(event.getPlace())) {
- updateMainMenu(event);
- } else if (ActionPlaces.EDITOR_POPUP.equals(event.getPlace())) {
- presentation.setVisible(presentation.isEnabled());
+ } else if (ActionPlaces.isMainMenuOrActionSearch(event.getPlace())) {
+ updateMainMenu(event);
+ }
+ else if (ActionPlaces.EDITOR_POPUP.equals(event.getPlace())) {
+ presentation.setVisible(presentation.isEnabled());
}
}
diff --git a/plugins/xpath/xpath-view/src/org/intellij/plugins/xpathView/search/SearchScope.java b/plugins/xpath/xpath-view/src/org/intellij/plugins/xpathView/search/SearchScope.java
index 775d90280d07..4c42e86f5f58 100644
--- a/plugins/xpath/xpath-view/src/org/intellij/plugins/xpathView/search/SearchScope.java
+++ b/plugins/xpath/xpath-view/src/org/intellij/plugins/xpathView/search/SearchScope.java
@@ -22,10 +22,7 @@ import com.intellij.openapi.roots.ContentIterator;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.OrderEnumerator;
import com.intellij.openapi.roots.ProjectRootManager;
-import com.intellij.openapi.util.Condition;
-import com.intellij.openapi.util.InvalidDataException;
-import com.intellij.openapi.util.JDOMExternalizable;
-import com.intellij.openapi.util.WriteExternalException;
+import com.intellij.openapi.util.*;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
@@ -189,12 +186,12 @@ public class SearchScope implements JDOMExternalizable {
switch (getScopeType()) {
case PROJECT:
//noinspection unchecked
- ProjectRootManager.getInstance(project).getFileIndex().iterateContent(new MyFileIterator(processor, Condition.TRUE));
+ ProjectRootManager.getInstance(project).getFileIndex().iterateContent(new MyFileIterator(processor, Conditions.<VirtualFile>alwaysTrue()));
break;
case MODULE:
final Module module = ModuleManager.getInstance(project).findModuleByName(getModuleName());
//noinspection unchecked
- ModuleRootManager.getInstance(module).getFileIndex().iterateContent(new MyFileIterator(processor, Condition.TRUE));
+ ModuleRootManager.getInstance(module).getFileIndex().iterateContent(new MyFileIterator(processor, Conditions.<VirtualFile>alwaysTrue()));
break;
case DIRECTORY:
final String dirName = getPath();
diff --git a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/XsltDebuggerExtension.java b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/XsltDebuggerExtension.java
index 038d5be4d7d4..a6aa2473e7ba 100644
--- a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/XsltDebuggerExtension.java
+++ b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/XsltDebuggerExtension.java
@@ -17,11 +17,13 @@
package org.intellij.plugins.xsltDebugger;
import com.intellij.diagnostic.logging.AdditionalTabComponent;
+import com.intellij.diagnostic.logging.LogConsoleManagerBase;
import com.intellij.execution.CantRunException;
import com.intellij.execution.configurations.AdditionalTabComponentManager;
import com.intellij.execution.configurations.SimpleJavaParameters;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.process.ProcessListener;
+import com.intellij.execution.runners.RunTab;
import com.intellij.icons.AllIcons;
import com.intellij.ide.plugins.IdeaPluginDescriptor;
import com.intellij.ide.plugins.PluginManager;
@@ -39,7 +41,6 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiManager;
import com.intellij.util.PlatformIcons;
import com.intellij.util.net.NetUtils;
-import com.intellij.xdebugger.impl.ui.DebuggerSessionTabBase;
import org.intellij.lang.xpath.xslt.XsltSupport;
import org.intellij.lang.xpath.xslt.impl.XsltChecker;
import org.intellij.lang.xpath.xslt.run.XsltRunConfiguration;
@@ -87,11 +88,12 @@ public class XsltDebuggerExtension extends XsltRunnerExtension {
AdditionalTabComponentManager manager,
AdditionalTabComponent outputConsole,
ProcessHandler process) {
- if (manager instanceof DebuggerSessionTabBase) {
- final DebuggerSessionTabBase mgr = (DebuggerSessionTabBase)manager;
- mgr.addAdditionalTabComponent(new OutputTabComponent(outputConsole), "XSLT-Output", AllIcons.Debugger.Console);
- mgr.addAdditionalTabComponent(StructureTabComponent.create(process, outputConsole), "XSLT-Structure", PlatformIcons.FLATTEN_PACKAGES_ICON);
- } else {
+ if (manager instanceof RunTab) {
+ LogConsoleManagerBase runTab = ((RunTab)manager).getLogConsoleManager();
+ runTab.addAdditionalTabComponent(new OutputTabComponent(outputConsole), "XSLT-Output", AllIcons.Debugger.Console);
+ runTab.addAdditionalTabComponent(StructureTabComponent.create(process, outputConsole), "XSLT-Structure", PlatformIcons.FLATTEN_PACKAGES_ICON);
+ }
+ else {
manager.addAdditionalTabComponent(new OutputTabComponent(outputConsole), "XSLT-Output");
manager.addAdditionalTabComponent(StructureTabComponent.create(process, outputConsole), "XSLT-Structure");
}
diff --git a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/AbstractTabComponent.java b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/AbstractTabComponent.java
index 5e9182baa27e..0dadd1db18ab 100644
--- a/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/AbstractTabComponent.java
+++ b/plugins/xslt-debugger/src/org/intellij/plugins/xsltDebugger/ui/AbstractTabComponent.java
@@ -1,6 +1,7 @@
package org.intellij.plugins.xsltDebugger.ui;
import com.intellij.diagnostic.logging.AdditionalTabComponent;
+import org.jetbrains.annotations.NotNull;
import javax.swing.*;
@@ -16,6 +17,7 @@ abstract class AbstractTabComponent extends AdditionalTabComponent {
myTabTitle = tabTitle;
}
+ @NotNull
@Override
public String getTabTitle() {
return myTabTitle;
@@ -44,4 +46,4 @@ abstract class AbstractTabComponent extends AdditionalTabComponent {
@Override
public void dispose() {
}
-} \ No newline at end of file
+}
diff --git a/python/edu/build/pycharm_edu_build.gant b/python/edu/build/pycharm_edu_build.gant
index 28d829e68b34..356df8c7d4c7 100644
--- a/python/edu/build/pycharm_edu_build.gant
+++ b/python/edu/build/pycharm_edu_build.gant
@@ -158,7 +158,6 @@ public layoutEducational(String classesPath, Set usedJars) {
usedJars = collectUsedJars(modules(), approvedJars(), ["/ant/"], null)
}
- def appInfo = appInfoFile()
def paths = new Paths(home)
buildSearchableOptions("${projectBuilder.moduleOutput(findModule("platform-resources"))}/search", [], {
projectBuilder.moduleRuntimeClasspath(findModule("main_pycharm_edu"), false).each {
@@ -166,8 +165,9 @@ public layoutEducational(String classesPath, Set usedJars) {
}
}, "-Didea.platform.prefix=PyCharmEdu -Didea.no.jre.check=true")
+ def appInfo = appInfoFile()
if (!dryRun) {
- wireBuildDate("PE-${buildNumber}", appInfo)
+ wireBuildDate(buildNumber, appInfo)
}
Map args = [
@@ -223,7 +223,7 @@ private layoutPlugins(layouts) {
}
private String appInfoFile() {
- return "$pythonEduHome/resources/idea/PyCharmEduApplicationInfo.xml"
+ return "$home/out/pycharmEDU/classes/production/python-educational/idea/PyCharmEduApplicationInfo.xml"
}
private layoutFull(Map args, String target, Set usedJars) {
@@ -405,7 +405,7 @@ private layoutMac(Map _args, String target) {
args.icns = "$pythonCommunityHome/resources/PyCharmCore.icns"
args.bundleIdentifier = "com.jetbrains.pycharm"
args.platform_prefix = "PyCharmEdu"
- args.help_id = "PY"
+ args.help_id = "PE"
args."idea.properties.path" = "${paths.distAll}/bin/idea.properties"
args."idea.properties" = ["idea.no.jre.check": true, "ide.mac.useNativeClipboard": "false"];
layoutMacApp(target, ch, args)
diff --git a/python/edu/build/upload_pythonInfo.xml b/python/edu/build/upload_pythonInfo.xml
index f8d9477d1a3f..0633ad82f8c0 100644
--- a/python/edu/build/upload_pythonInfo.xml
+++ b/python/edu/build/upload_pythonInfo.xml
@@ -20,7 +20,7 @@
</fileset>
<fileset dir="${home}/community/lib">
<include name="commons-net-3.1.jar"/>
- <include name="jsch-0.1.50.jar"/>
+ <include name="jsch-0.1.51.jar"/>
</fileset>
</classpath>
diff --git a/python/edu/course-creator/resources/META-INF/plugin.xml b/python/edu/course-creator/resources/META-INF/plugin.xml
index 6a9a9ea90276..0e7f75c90051 100644
--- a/python/edu/course-creator/resources/META-INF/plugin.xml
+++ b/python/edu/course-creator/resources/META-INF/plugin.xml
@@ -26,6 +26,10 @@
<codeInsight.lineMarkerProvider language="Python"
implementationClass="org.jetbrains.plugins.coursecreator.highlighting.CCTaskLineMarkerProvider"/>
<treeStructureProvider implementation="org.jetbrains.plugins.coursecreator.projectView.CCTreeStructureProvider"/>
+ <codeInsight.lineMarkerProvider language="Python" implementationClass="org.jetbrains.plugins.coursecreator.RunTestsLineMarker"/>
+ <fileTypeFactory implementation="org.jetbrains.plugins.coursecreator.AnswerFileTypeFactory" />
+ <refactoring.elementListenerProvider implementation="org.jetbrains.plugins.coursecreator.CCRefactoringElementListenerProvider"/>
+ <errorHandler implementation="com.intellij.diagnostic.ITNReporter"/>
</extensions>
<application-components>
@@ -52,9 +56,19 @@
<action id="AddTaskWindow" class="org.jetbrains.plugins.coursecreator.actions.AddTaskWindow">
<add-to-group group-id="EditorPopupMenu" anchor="before" relative-to-action="CopyReference"/>
</action>
+ <action id="ShowPreview" class="org.jetbrains.plugins.coursecreator.actions.CCShowPreview">
+ <add-to-group group-id="ProjectViewPopupMenu" anchor="first"/>
+ </action>
+ <action id="RenameLesson" class="org.jetbrains.plugins.coursecreator.actions.CCRenameLesson">
+ <add-to-group group-id="ProjectViewPopupMenu" anchor="before" relative-to-action="CutCopyPasteGroup"/>
+ </action>
+ <action id="RenameTask" class="org.jetbrains.plugins.coursecreator.actions.CCRenameTask">
+ <add-to-group group-id="ProjectViewPopupMenu" anchor="before" relative-to-action="CutCopyPasteGroup"/>
+ </action>
<action id="PackCourse" class="org.jetbrains.plugins.coursecreator.actions.CreateCourseArchive">
<add-to-group group-id="MainToolBar" anchor="last" />
</action>
+ <action id="CCRunTests" class="org.jetbrains.plugins.coursecreator.CCRunTests" text="Run tests" description="Run tests"/>
</actions>
</idea-plugin> \ No newline at end of file
diff --git a/python/edu/course-creator/resources/fileTemplates/internal/task.answer.ft b/python/edu/course-creator/resources/fileTemplates/internal/task.answer.ft
new file mode 100644
index 000000000000..f0a4bcecdd24
--- /dev/null
+++ b/python/edu/course-creator/resources/fileTemplates/internal/task.answer.ft
@@ -0,0 +1 @@
+# TODO: type solution here
diff --git a/python/edu/course-creator/resources/fileTemplates/internal/task.py.ft b/python/edu/course-creator/resources/fileTemplates/internal/task.py.ft
deleted file mode 100644
index 0256e108786c..000000000000
--- a/python/edu/course-creator/resources/fileTemplates/internal/task.py.ft
+++ /dev/null
@@ -1 +0,0 @@
-# TODO: type solution here \ No newline at end of file
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/AnswerFileType.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/AnswerFileType.java
new file mode 100644
index 000000000000..3b8189aadffc
--- /dev/null
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/AnswerFileType.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.plugins.coursecreator;
+
+import com.jetbrains.python.PythonFileType;
+import org.jetbrains.annotations.NotNull;
+
+public class AnswerFileType extends PythonFileType {
+
+ @NotNull
+ @Override
+ public String getDefaultExtension() {
+ return "answer";
+ }
+
+ @NotNull
+ @Override
+ public String getDescription() {
+ return "Answer file";
+ }
+
+ @NotNull
+ @Override
+ public String getName() {
+ return "Answer";
+ }
+}
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/AnswerFileTypeFactory.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/AnswerFileTypeFactory.java
new file mode 100644
index 000000000000..e4adcbc5b386
--- /dev/null
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/AnswerFileTypeFactory.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.plugins.coursecreator;
+
+
+import com.intellij.openapi.fileTypes.FileTypeConsumer;
+import com.intellij.openapi.fileTypes.FileTypeFactory;
+import org.jetbrains.annotations.NotNull;
+
+public class AnswerFileTypeFactory extends FileTypeFactory {
+ @Override
+ public void createFileTypes(@NotNull FileTypeConsumer fileTypeConsumer) {
+ fileTypeConsumer.consume(AnswerFileType.INSTANCE, "answer");
+ }
+}
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCEditorFactoryListener.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCEditorFactoryListener.java
index 1eb8690aad22..acb0d43d0d12 100644
--- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCEditorFactoryListener.java
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCEditorFactoryListener.java
@@ -35,6 +35,9 @@ public class CCEditorFactoryListener implements EditorFactoryListener {
final Lesson lesson = course.getLesson(lessonDir.getName());
final Task task = lesson.getTask(taskDir.getName());
final TaskFile taskFile = task.getTaskFile(virtualFile.getName());
+ if (taskFile == null) {
+ return;
+ }
TaskFileModificationListener listener = new TaskFileModificationListener(taskFile);
CCProjectService.addDocumentListener(editor.getDocument(), listener);
editor.getDocument().addDocumentListener(listener);
@@ -54,13 +57,10 @@ public class CCEditorFactoryListener implements EditorFactoryListener {
editor.getSelectionModel().removeSelection();
}
- private class TaskFileModificationListener extends StudyDocumentListener {
-
- private final TaskFile myTaskFile;
+ private static class TaskFileModificationListener extends StudyDocumentListener {
public TaskFileModificationListener(TaskFile taskFile) {
super(taskFile);
- myTaskFile = taskFile;
}
@Override
@@ -71,10 +71,5 @@ public class CCEditorFactoryListener implements EditorFactoryListener {
taskWindow.setReplacementLength(taskWindow.getLength() + 1);
}
}
-
- @Override
- protected boolean needModify() {
- return myTaskFile.isTrackChanges();
- }
}
}
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCProjectComponent.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCProjectComponent.java
index 34de943d2ad0..8b524dbffd4b 100644
--- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCProjectComponent.java
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCProjectComponent.java
@@ -1,22 +1,33 @@
package org.jetbrains.plugins.coursecreator;
+import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.ProjectComponent;
+import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.editor.event.EditorFactoryEvent;
import com.intellij.openapi.editor.impl.EditorFactoryImpl;
-import com.intellij.openapi.fileEditor.FileEditor;
-import com.intellij.openapi.fileEditor.FileEditorManager;
+import com.intellij.openapi.fileEditor.*;
import com.intellij.openapi.fileEditor.impl.text.PsiAwareTextEditorImpl;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.openapi.vfs.VirtualFileAdapter;
+import com.intellij.openapi.vfs.VirtualFileEvent;
+import com.intellij.openapi.vfs.VirtualFileManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.coursecreator.format.Course;
+import org.jetbrains.plugins.coursecreator.format.Lesson;
+import org.jetbrains.plugins.coursecreator.format.Task;
+import org.jetbrains.plugins.coursecreator.format.TaskFile;
+
+import java.io.IOException;
public class CCProjectComponent implements ProjectComponent {
+ private static final Logger LOG = Logger.getInstance(CCProjectComponent.class.getName());
private final Project myProject;
+ private FileDeletedListener myListener;
public CCProjectComponent(Project project) {
myProject = project;
@@ -37,15 +48,46 @@ public class CCProjectComponent implements ProjectComponent {
StartupManager.getInstance(myProject).runWhenProjectIsInitialized(new Runnable() {
@Override
public void run() {
- Course course = CCProjectService.getInstance(myProject).getCourse();
+ final Course course = CCProjectService.getInstance(myProject).getCourse();
if (course != null) {
- EditorFactory.getInstance().addEditorFactoryListener(new CCEditorFactoryListener(), myProject);
+ myProject.getMessageBus().connect(myProject).subscribe(
+ FileEditorManagerListener.FILE_EDITOR_MANAGER, new FileEditorManagerAdapter() {
+ @Override
+ public void selectionChanged(@NotNull FileEditorManagerEvent event) {
+ final VirtualFile oldFile = event.getOldFile();
+ if (oldFile == null) {
+ return;
+ }
+ if (CCProjectService.getInstance(myProject).isTaskFile(oldFile)) {
+ FileEditorManager.getInstance(myProject).closeFile(oldFile);
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ oldFile.delete(myProject);
+ }
+ catch (IOException e) {
+ LOG.error(e);
+ }
+ }
+ });
+ }
+ }
+ });
+ myListener = new FileDeletedListener();
+ VirtualFileManager.getInstance().addVirtualFileListener(myListener);
+ final CCEditorFactoryListener editorFactoryListener = new CCEditorFactoryListener();
+ EditorFactory.getInstance().addEditorFactoryListener(editorFactoryListener, myProject);
VirtualFile[] files = FileEditorManager.getInstance(myProject).getOpenFiles();
for (VirtualFile file : files) {
+ if (CCProjectService.getInstance(myProject).isTaskFile(file)) {
+ FileEditorManager.getInstance(myProject).closeFile(file);
+ continue;
+ }
FileEditor fileEditor = FileEditorManager.getInstance(myProject).getSelectedEditor(file);
if (fileEditor instanceof PsiAwareTextEditorImpl) {
Editor editor = ((PsiAwareTextEditorImpl)fileEditor).getEditor();
- new CCEditorFactoryListener().editorCreated(new EditorFactoryEvent(new EditorFactoryImpl(ProjectManager.getInstance()), editor ));
+ editorFactoryListener.editorCreated(new EditorFactoryEvent(new EditorFactoryImpl(ProjectManager.getInstance()), editor));
}
}
}
@@ -54,5 +96,94 @@ public class CCProjectComponent implements ProjectComponent {
}
public void projectClosed() {
+ if (myListener != null) {
+ VirtualFileManager.getInstance().removeVirtualFileListener(myListener);
+ }
+ }
+
+ private class FileDeletedListener extends VirtualFileAdapter {
+
+ @Override
+ public void fileDeleted(@NotNull VirtualFileEvent event) {
+ if (myProject.isDisposed() || !myProject.isOpen()) {
+ return;
+ }
+ Course course = CCProjectService.getInstance(myProject).getCourse();
+ if (course == null) {
+ return;
+ }
+ VirtualFile removedFile = event.getFile();
+ if (removedFile.getName().contains(".answer")) {
+ deleteTaskFile(course, removedFile);
+ }
+ if (removedFile.getName().contains("task")) {
+ deleteTask(course, removedFile);
+ }
+ if (removedFile.getName().contains("lesson")) {
+ deleteLesson(course, removedFile);
+ }
+ }
+
+ private void deleteLesson(Course course, VirtualFile file) {
+ VirtualFile courseDir = file.getParent();
+ if (!courseDir.getName().equals(myProject.getName())) {
+ return;
+ }
+ Lesson lesson = course.getLesson(file.getName());
+ if (lesson != null) {
+ course.getLessons().remove(lesson);
+ course.getLessonsMap().remove(file.getName());
+ }
+ }
+
+ private void deleteTask(Course course, VirtualFile removedFile) {
+ VirtualFile lessonDir = removedFile.getParent();
+ if (lessonDir == null || !lessonDir.getName().contains("lesson")) {
+ return;
+ }
+ VirtualFile courseDir = lessonDir.getParent();
+ if (!courseDir.getName().equals(myProject.getName())) {
+ return;
+ }
+ Lesson lesson = course.getLesson(lessonDir.getName());
+ if (lesson == null) {
+ return;
+ }
+ Task task = lesson.getTask(removedFile.getName());
+ if (task == null) {
+ return;
+ }
+ lesson.getTaskList().remove(task);
+ lesson.getTasksMap().remove(removedFile.getName());
+ }
+
+ private void deleteTaskFile(Course course, VirtualFile removedFile) {
+ VirtualFile taskDir = removedFile.getParent();
+ if (taskDir == null || !taskDir.getName().contains("task")) {
+ return;
+ }
+ VirtualFile lessonDir = taskDir.getParent();
+ if (lessonDir == null || !lessonDir.getName().contains("lesson")) {
+ return;
+ }
+ VirtualFile courseDir = lessonDir.getParent();
+ if (!courseDir.getName().equals(myProject.getName())) {
+ return;
+ }
+ Lesson lesson = course.getLesson(lessonDir.getName());
+ if (lesson == null) {
+ return;
+ }
+ Task task = lesson.getTask(taskDir.getName());
+ if (task == null) {
+ return;
+ }
+ TaskFile taskFile = task.getTaskFile(removedFile.getName());
+ if (taskFile == null) {
+ return;
+ }
+ String name = CCProjectService.getRealTaskFileName(removedFile.getName());
+ task.getTaskFiles().remove(name);
+ }
}
}
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCProjectService.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCProjectService.java
index 1e38bab865cb..c06925e9a453 100644
--- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCProjectService.java
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCProjectService.java
@@ -32,6 +32,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.coursecreator.format.*;
import java.io.File;
+import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -70,6 +71,9 @@ public class CCProjectService implements PersistentStateComponent<Element> {
@Override
public void loadState(Element el) {
myCourse = XmlSerializer.deserialize(el.getChild(COURSE_ELEMENT), Course.class);
+ if (myCourse != null) {
+ myCourse.init();
+ }
}
public static CCProjectService getInstance(@NotNull Project project) {
@@ -115,7 +119,7 @@ public class CCProjectService implements PersistentStateComponent<Element> {
}
List<TaskWindow> taskWindows = taskFile.getTaskWindows();
for (TaskWindow taskWindow : taskWindows) {
- taskWindow.drawHighlighter(editor);
+ taskWindow.drawHighlighter(editor, false);
}
}
@@ -131,8 +135,52 @@ public class CCProjectService implements PersistentStateComponent<Element> {
myDocumentListeners.remove(document);
}
- public static boolean indexIsValid(int index, List<TaskWindow> collection) {
+ public static boolean indexIsValid(int index, Collection collection) {
int size = collection.size();
return index >= 0 && index < size;
}
+
+ public boolean isTaskFile(VirtualFile file) {
+ if (myCourse == null || file == null) {
+ return false;
+ }
+ VirtualFile taskDir = file.getParent();
+ if (taskDir != null) {
+ String taskDirName = taskDir.getName();
+ if (taskDirName.contains("task")) {
+ VirtualFile lessonDir = taskDir.getParent();
+ if (lessonDir != null) {
+ String lessonDirName = lessonDir.getName();
+ int lessonIndex = getIndex(lessonDirName, "lesson");
+ List<Lesson> lessons = myCourse.getLessons();
+ if (!indexIsValid(lessonIndex, lessons)) {
+ return false;
+ }
+ Lesson lesson = lessons.get(lessonIndex);
+ int taskIndex = getIndex(taskDirName, "task");
+ List<Task> tasks = lesson.getTaskList();
+ if (!indexIsValid(taskIndex, tasks)) {
+ return false;
+ }
+ Task task = tasks.get(taskIndex);
+ return task.isTaskFile(file.getName());
+ }
+ }
+ }
+ return false;
+ }
+
+ public static int getIndex(@NotNull final String fullName, @NotNull final String logicalName) {
+ if (!fullName.contains(logicalName)) {
+ throw new IllegalArgumentException();
+ }
+ return Integer.parseInt(fullName.substring(logicalName.length())) - 1;
+ }
+ public static String getRealTaskFileName(String name) {
+ if (!name.contains(".answer")) {
+ return null;
+ }
+ int nameEnd = name.indexOf(".answer");
+ return name.substring(0, nameEnd) + ".py";
+ }
}
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCRefactoringElementListenerProvider.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCRefactoringElementListenerProvider.java
new file mode 100644
index 000000000000..601e4fc7cb40
--- /dev/null
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCRefactoringElementListenerProvider.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.plugins.coursecreator;
+
+import com.intellij.psi.PsiDirectory;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.refactoring.listeners.RefactoringElementAdapter;
+import com.intellij.refactoring.listeners.RefactoringElementListener;
+import com.intellij.refactoring.listeners.RefactoringElementListenerProvider;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.plugins.coursecreator.format.Course;
+import org.jetbrains.plugins.coursecreator.format.Lesson;
+import org.jetbrains.plugins.coursecreator.format.Task;
+import org.jetbrains.plugins.coursecreator.format.TaskFile;
+
+import java.util.Map;
+
+public class CCRefactoringElementListenerProvider implements RefactoringElementListenerProvider {
+ @Nullable
+ @Override
+ public RefactoringElementListener getListener(PsiElement element) {
+ return new CCRenameListener(element);
+ }
+
+
+ static class CCRenameListener extends RefactoringElementAdapter {
+
+ private String myElementName;
+
+ public CCRenameListener(PsiElement element) {
+ if (element instanceof PsiFile) {
+ PsiFile psiFile = (PsiFile)element;
+ myElementName = psiFile.getName();
+ }
+ }
+
+ @Override
+ protected void elementRenamedOrMoved(@NotNull PsiElement newElement) {
+ if (newElement instanceof PsiFile && myElementName != null) {
+ PsiFile psiFile = (PsiFile)newElement;
+ if (myElementName.contains(".answer")) {
+ //this is task file
+ renameTaskFile(psiFile, myElementName);
+ }
+ }
+ }
+
+ private static void renameTaskFile(PsiFile file, String oldName) {
+ PsiDirectory taskDir = file.getContainingDirectory();
+ Course course = CCProjectService.getInstance(file.getProject()).getCourse();
+ if (course == null) {
+ return;
+ }
+ if (taskDir == null || !taskDir.getName().contains("task")) {
+ return;
+ }
+ PsiDirectory lessonDir = taskDir.getParent();
+ if (lessonDir == null || !lessonDir.getName().contains("lesson")) {
+ return;
+ }
+ Lesson lesson = course.getLesson(lessonDir.getName());
+ if (lesson == null) {
+ return;
+ }
+ Task task = lesson.getTask(taskDir.getName());
+ if (task == null) {
+ return;
+ }
+ Map<String, TaskFile> taskFiles = task.getTaskFiles();
+ TaskFile taskFile = task.getTaskFile(oldName);
+ String realTaskFileName = CCProjectService.getRealTaskFileName(oldName);
+ taskFiles.remove(realTaskFileName);
+ taskFiles.put(CCProjectService.getRealTaskFileName(file.getName()), taskFile);
+ }
+
+ @Override
+ public void undoElementMovedOrRenamed(@NotNull PsiElement newElement, @NotNull String oldQualifiedName) {
+
+ }
+ }
+}
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCRunTests.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCRunTests.java
new file mode 100644
index 000000000000..d078972e3f56
--- /dev/null
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/CCRunTests.java
@@ -0,0 +1,284 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.plugins.coursecreator;
+
+import com.intellij.execution.*;
+import com.intellij.execution.actions.ConfigurationContext;
+import com.intellij.execution.configurations.ConfigurationFactory;
+import com.intellij.execution.executors.DefaultRunExecutor;
+import com.intellij.icons.AllIcons;
+import com.intellij.ide.projectView.ProjectView;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.Presentation;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.openapi.vfs.VirtualFileManager;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.util.containers.HashMap;
+import com.jetbrains.python.run.PythonConfigurationType;
+import com.jetbrains.python.run.PythonRunConfiguration;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.plugins.coursecreator.actions.CreateCourseArchive;
+import org.jetbrains.plugins.coursecreator.format.*;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Map;
+
+public class CCRunTests extends AnAction {
+ private static final Logger LOG = Logger.getInstance(CCRunTests.class.getName());
+
+ public CCRunTests() {
+ getTemplatePresentation().setIcon(AllIcons.Actions.Lightning);
+ }
+
+ @Override
+ public void update(@NotNull AnActionEvent e) {
+ Presentation presentation = e.getPresentation();
+ final ConfigurationContext context = ConfigurationContext.getFromContext(e.getDataContext());
+ Location location = context.getLocation();
+ if (location == null) {
+ return;
+ }
+ PsiElement psiElement = location.getPsiElement();
+ PsiFile psiFile = psiElement.getContainingFile();
+ if (psiFile != null && psiFile.getName().contains(".answer")) {
+ presentation.setEnabled(true);
+ presentation.setText("Run tests from '" + psiFile.getName() + "'");
+ }
+ else {
+ presentation.setEnabled(false);
+ }
+ }
+
+ public void actionPerformed(@NotNull AnActionEvent e) {
+ final ConfigurationContext context = ConfigurationContext.getFromContext(e.getDataContext());
+ run(context);
+ }
+
+ public static void run(final @NotNull ConfigurationContext context) {
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ @Override
+ public void run() {
+ final Project project = context.getProject();
+ PsiElement location = context.getPsiLocation();
+ final Course course = CCProjectService.getInstance(project).getCourse();
+ if (course == null || location == null) {
+ return;
+ }
+ PsiFile psiFile = location.getContainingFile();
+ final VirtualFile virtualFile = psiFile.getVirtualFile();
+ final VirtualFile taskDir = virtualFile.getParent();
+ if (taskDir == null) {
+ return;
+ }
+ final Task task = getTask(course, taskDir);
+ if (task == null) {
+ return;
+ }
+ for (final Map.Entry<String, TaskFile> entry : task.getTaskFiles().entrySet()) {
+ final String name = entry.getKey();
+ createTestEnvironment(taskDir, name, entry.getValue(), project);
+ VirtualFile testFile = taskDir.findChild("tests.py");
+ if (testFile == null) {
+ return;
+ }
+ executeTests(project, virtualFile, taskDir, testFile);
+ clearTestEnvironment(taskDir, project);
+ }
+ }
+ });
+ }
+
+ private static void createTestEnvironment(@NotNull final VirtualFile taskDir, final String fileName, @NotNull final TaskFile taskFile,
+ @NotNull final Project project) {
+ try {
+ String answerFileName = FileUtil.getNameWithoutExtension(fileName) + ".answer";
+ final VirtualFile answerFile = taskDir.findChild(answerFileName);
+ if (answerFile == null) {
+ LOG.debug("could not find answer file " + answerFileName);
+ return;
+ }
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ @Override
+ public void run() {
+ final FileDocumentManager documentManager = FileDocumentManager.getInstance();
+ documentManager.saveAllDocuments();
+ }
+ });
+ answerFile.copy(project, taskDir, fileName);
+ flushWindows(taskFile, answerFile);
+ createResourceFiles(answerFile, project);
+ }
+ catch (IOException e) {
+ LOG.error(e);
+ }
+ }
+
+ private static void clearTestEnvironment(@NotNull final VirtualFile taskDir, @NotNull final Project project) {
+ try {
+ VirtualFile ideaDir = project.getBaseDir().findChild(".idea");
+ if (ideaDir == null) {
+ LOG.debug("idea directory doesn't exist");
+ return;
+ }
+ VirtualFile courseResourceDir = ideaDir.findChild("course");
+ if (courseResourceDir == null) {
+ return;
+ }
+ courseResourceDir.delete(project);
+ VirtualFile[] taskDirChildren = taskDir.getChildren();
+ for (VirtualFile file : taskDirChildren) {
+ if (file.getName().contains("_windows")) {
+ file.delete(project);
+ }
+ if (CCProjectService.getInstance(project).isTaskFile(file)) {
+ file.delete(project);
+ }
+ }
+ }
+ catch (IOException e) {
+ LOG.error(e);
+ }
+ }
+
+ private static void executeTests(@NotNull final Project project,
+ @NotNull final VirtualFile virtualFile,
+ @NotNull final VirtualFile taskDir,
+ @NotNull final VirtualFile testFile) {
+ final ConfigurationFactory factory = PythonConfigurationType.getInstance().getConfigurationFactories()[0];
+ final RunnerAndConfigurationSettings settings =
+ RunManager.getInstance(project).createRunConfiguration("test", factory);
+
+ final PythonRunConfiguration configuration = (PythonRunConfiguration)settings.getConfiguration();
+ configuration.setScriptName(testFile.getPath());
+ VirtualFile userFile = taskDir.findChild(virtualFile.getNameWithoutExtension() + ".py");
+ if (userFile == null) {
+ return;
+ }
+ VirtualFile ideaDir = project.getBaseDir().findChild(".idea");
+ if (ideaDir == null) {
+ return;
+ }
+ VirtualFileManager.getInstance().refreshWithoutFileWatcher(true);
+ ProjectView.getInstance(project).refresh();
+ VirtualFile courseDir = ideaDir.findChild("course");
+ if (courseDir == null) {
+ return;
+ }
+ configuration.setScriptParameters(courseDir.getPath() + " " + userFile.getPath());
+ Executor executor = DefaultRunExecutor.getRunExecutorInstance();
+ ProgramRunnerUtil.executeConfiguration(project, settings, executor);
+ }
+
+ @Nullable
+ private static Task getTask(@NotNull final Course course, @NotNull final VirtualFile taskDir) {
+ if (!taskDir.getName().contains("task")) {
+ return null;
+ }
+ VirtualFile lessonDir = taskDir.getParent();
+ if (lessonDir == null || !lessonDir.getName().contains("lesson")) {
+ return null;
+ }
+ Lesson lesson = course.getLesson(lessonDir.getName());
+ if (lesson == null) {
+ return null;
+ }
+ return lesson.getTask(taskDir.getName());
+ }
+
+
+ //some tests could compare task files after user modifications with initial task files
+ private static void createResourceFiles(@NotNull final VirtualFile file, @NotNull final Project project) {
+ VirtualFile taskDir = file.getParent();
+ int index = CCProjectService.getIndex(taskDir.getName(), "task");
+ VirtualFile lessonDir = taskDir.getParent();
+ int lessonIndex = CCProjectService.getIndex(lessonDir.getName(), "lesson");
+ Course course = CCProjectService.getInstance(project).getCourse();
+ if (course == null) {
+ return;
+ }
+ VirtualFile ideaDir = project.getBaseDir().findChild(".idea");
+ assert ideaDir != null;
+ try {
+ VirtualFile taskResourceDir = ideaDir.createChildDirectory(project, "course").createChildDirectory(project, lessonDir.getName())
+ .createChildDirectory(project, taskDir.getName());
+ if (CCProjectService.indexIsValid(lessonIndex, course.getLessons())) {
+ Lesson lesson = course.getLessons().get(lessonIndex);
+ if (CCProjectService.indexIsValid(index, lesson.getTaskList())) {
+ Task task = lesson.getTaskList().get(index);
+ HashMap<TaskFile, TaskFile> taskFilesCopy = new HashMap<TaskFile, TaskFile>();
+ for (Map.Entry<String, TaskFile> entry : task.getTaskFiles().entrySet()) {
+ CreateCourseArchive.createUserFile(project, taskFilesCopy, taskResourceDir, taskDir, entry);
+ CreateCourseArchive.resetTaskFiles(taskFilesCopy);
+ }
+ }
+ }
+ }
+ catch (IOException e) {
+ LOG.error(e);
+ }
+ }
+
+ @SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
+ public static VirtualFile flushWindows(TaskFile taskFile, VirtualFile file) {
+ VirtualFile taskDir = file.getParent();
+ VirtualFile fileWindows = null;
+ final Document document = FileDocumentManager.getInstance().getDocument(file);
+ if (document == null) {
+ LOG.debug("Couldn't flush windows");
+ return null;
+ }
+ if (taskDir != null) {
+ String name = file.getNameWithoutExtension() + "_windows";
+ PrintWriter printWriter = null;
+ try {
+ fileWindows = taskDir.createChildData(taskFile, name);
+ printWriter = new PrintWriter(new FileOutputStream(fileWindows.getPath()));
+ for (TaskWindow taskWindow : taskFile.getTaskWindows()) {
+ int start = taskWindow.getRealStartOffset(document);
+ String windowDescription = document.getText(new TextRange(start, start + taskWindow.getReplacementLength()));
+ printWriter.println("#study_plugin_window = " + windowDescription);
+ }
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ @Override
+ public void run() {
+ FileDocumentManager.getInstance().saveDocument(document);
+ }
+ });
+ }
+ catch (IOException e) {
+ LOG.error(e);
+ }
+ finally {
+ if (printWriter != null) {
+ printWriter.close();
+ }
+ }
+ }
+ return fileWindows;
+ }
+}
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/RunTestsLineMarker.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/RunTestsLineMarker.java
new file mode 100644
index 000000000000..93e0a706f367
--- /dev/null
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/RunTestsLineMarker.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.plugins.coursecreator;
+
+import com.intellij.codeHighlighting.Pass;
+import com.intellij.codeInsight.daemon.GutterIconNavigationHandler;
+import com.intellij.codeInsight.daemon.LineMarkerInfo;
+import com.intellij.codeInsight.daemon.LineMarkerProvider;
+import com.intellij.execution.actions.ConfigurationContext;
+import com.intellij.icons.AllIcons;
+import com.intellij.ide.DataManager;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.editor.markup.GutterIconRenderer;
+import com.intellij.psi.PsiComment;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiWhiteSpace;
+import com.intellij.psi.util.PsiUtilBase;
+import com.intellij.util.Function;
+import com.jetbrains.python.psi.PyFile;
+import com.jetbrains.python.psi.PyImportStatement;
+import com.jetbrains.python.psi.PyStatement;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.awt.event.MouseEvent;
+import java.util.Collection;
+import java.util.List;
+
+public class RunTestsLineMarker implements LineMarkerProvider {
+ @Nullable
+ @Override
+ public LineMarkerInfo getLineMarkerInfo(@NotNull PsiElement element) {
+ return null;
+ }
+
+ @Override
+ public void collectSlowLineMarkers(@NotNull List<PsiElement> elements, @NotNull Collection<LineMarkerInfo> result) {
+ for (PsiElement element : elements) {
+ if (isFirstCodeLine(element)) {
+ PsiFile psiFile = element.getContainingFile();
+ if (psiFile == null || !psiFile.getName().contains(".answer")) {
+ continue;
+ }
+ result.add(new LineMarkerInfo<PsiElement>(
+ element, element.getTextRange(), AllIcons.Actions.Lightning, Pass.UPDATE_OVERRIDEN_MARKERS,
+ new Function<PsiElement, String>() {
+ @Override
+ public String fun(PsiElement e) {
+ return "Run tests from file '" + e.getContainingFile().getName() + "'";
+ }
+ },
+ new GutterIconNavigationHandler<PsiElement>() {
+ @Override
+ public void navigate(MouseEvent e, PsiElement elt) {
+ executeCurrentScript(elt);
+ }
+ },
+ GutterIconRenderer.Alignment.RIGHT));
+ }
+ }
+ }
+
+ private static void executeCurrentScript(PsiElement elt) {
+ Editor editor = PsiUtilBase.findEditor(elt);
+ assert editor != null;
+
+ final ConfigurationContext context =
+ ConfigurationContext.getFromContext(DataManager.getInstance().getDataContext(editor.getComponent()));
+ CCRunTests.run(context);
+ }
+
+ private static boolean isFirstCodeLine(PsiElement element) {
+ return element instanceof PyStatement &&
+ element.getParent() instanceof PyFile &&
+ !isNothing(element) &&
+ nothingBefore(element);
+ }
+
+ private static boolean nothingBefore(PsiElement element) {
+ element = element.getPrevSibling();
+ while (element != null) {
+ if (!isNothing(element)) {
+ return false;
+ }
+ element = element.getPrevSibling();
+ }
+
+ return true;
+ }
+
+ private static boolean isNothing(PsiElement element) {
+ return (element instanceof PsiComment) || (element instanceof PyImportStatement) || (element instanceof PsiWhiteSpace);
+ }
+}
+
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/StudyDocumentListener.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/StudyDocumentListener.java
index d803e0e8fd97..965bd31771a0 100644
--- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/StudyDocumentListener.java
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/StudyDocumentListener.java
@@ -44,9 +44,6 @@ public abstract class StudyDocumentListener extends DocumentAdapter {
@Override
public void documentChanged(DocumentEvent e) {
if (e instanceof DocumentEventImpl) {
- if (!needModify()) {
- return;
- }
DocumentEventImpl event = (DocumentEventImpl)e;
Document document = e.getDocument();
int offset = e.getOffset();
@@ -65,7 +62,5 @@ public abstract class StudyDocumentListener extends DocumentAdapter {
}
protected abstract void updateTaskWindowLength(CharSequence fragment, TaskWindow taskWindow, int change);
-
- protected abstract boolean needModify();
}
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/AddTaskWindow.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/AddTaskWindow.java
index ff88cea5fd42..0bc631dbd784 100644
--- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/AddTaskWindow.java
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/AddTaskWindow.java
@@ -13,6 +13,7 @@ import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.coursecreator.CCProjectService;
import org.jetbrains.plugins.coursecreator.format.*;
import org.jetbrains.plugins.coursecreator.ui.CreateTaskWindowDialog;
@@ -59,12 +60,12 @@ public class AddTaskWindow extends DumbAwareAction {
}
int index = taskFile.getTaskWindows().size() + 1;
taskFile.addTaskWindow(taskWindow, index);
- taskWindow.drawHighlighter(editor);
+ taskWindow.drawHighlighter(editor, false);
DaemonCodeAnalyzerImpl.getInstance(project).restart(file);
}
@Override
- public void update(AnActionEvent event) {
+ public void update(@NotNull AnActionEvent event) {
final Presentation presentation = event.getPresentation();
final Project project = event.getData(CommonDataKeys.PROJECT);
if (project == null) {
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCRename.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCRename.java
new file mode 100644
index 000000000000..321a86a5ba35
--- /dev/null
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCRename.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.plugins.coursecreator.actions;
+
+import com.intellij.ide.IdeView;
+import com.intellij.ide.projectView.ProjectView;
+import com.intellij.ide.util.DirectoryChooserUtil;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.CommonDataKeys;
+import com.intellij.openapi.actionSystem.LangDataKeys;
+import com.intellij.openapi.actionSystem.Presentation;
+import com.intellij.openapi.project.DumbAwareAction;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiDirectory;
+import com.intellij.psi.PsiFile;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.plugins.coursecreator.CCProjectService;
+import org.jetbrains.plugins.coursecreator.format.Course;
+
+import javax.swing.*;
+
+public abstract class CCRename extends DumbAwareAction {
+ public CCRename(String text, String description, Icon icon) {
+ super(text, description, icon);
+ }
+
+ @Override
+ public void update(@NotNull AnActionEvent event) {
+ final Presentation presentation = event.getPresentation();
+ final Project project = event.getData(CommonDataKeys.PROJECT);
+ if (project == null) {
+ presentation.setVisible(false);
+ presentation.setEnabled(false);
+ return;
+ }
+
+ final IdeView view = event.getData(LangDataKeys.IDE_VIEW);
+ if (view == null) {
+ presentation.setVisible(false);
+ presentation.setEnabled(false);
+ return;
+ }
+
+ final PsiDirectory[] directories = view.getDirectories();
+ if (directories.length == 0) {
+ presentation.setVisible(false);
+ presentation.setEnabled(false);
+ return;
+ }
+ final PsiFile file = CommonDataKeys.PSI_FILE.getData(event.getDataContext());
+ final PsiDirectory directory = DirectoryChooserUtil.getOrChooseDirectory(view);
+ if (file != null ||directory == null || !directory.getName().contains(getFolderName())) {
+ presentation.setEnabled(false);
+ presentation.setVisible(false);
+ return;
+ }
+ presentation.setVisible(true);
+ presentation.setEnabled(true);
+ }
+
+ public abstract String getFolderName();
+
+ @Override
+ public void actionPerformed(@NotNull AnActionEvent e) {
+ final IdeView view = e.getData(LangDataKeys.IDE_VIEW);
+ final Project project = e.getData(CommonDataKeys.PROJECT);
+
+ if (view == null || project == null) {
+ return;
+ }
+ final PsiDirectory directory = DirectoryChooserUtil.getOrChooseDirectory(view);
+ if (directory == null || !directory.getName().contains(getFolderName())) {
+ return;
+ }
+ Course course = CCProjectService.getInstance(project).getCourse();
+ if (course == null) {
+ return;
+ }
+ if (!processRename(project, directory, course)) return;
+ ProjectView.getInstance(project).refresh();
+ }
+
+ public abstract boolean processRename(Project project, PsiDirectory directory, Course course);
+}
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCRenameLesson.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCRenameLesson.java
new file mode 100644
index 000000000000..3f580454ed6e
--- /dev/null
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCRenameLesson.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.plugins.coursecreator.actions;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.Messages;
+import com.intellij.psi.PsiDirectory;
+import org.jetbrains.plugins.coursecreator.format.Course;
+import org.jetbrains.plugins.coursecreator.format.Lesson;
+
+public class CCRenameLesson extends CCRename {
+
+ public CCRenameLesson() {
+ super("Rename Lesson", "Rename Lesson", null);
+ }
+
+ @Override
+ public String getFolderName() {
+ return "lesson";
+ }
+
+ @Override
+ public boolean processRename(Project project, PsiDirectory directory, Course course) {
+ Lesson lesson = course.getLesson(directory.getName());
+ if (lesson == null) {
+ return false;
+ }
+ String newName = Messages.showInputDialog(project, "Enter new name", "Rename " + getFolderName(), null);
+ if (newName == null) {
+ return false;
+ }
+ lesson.setName(newName);
+ return true;
+ }
+}
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCRenameTask.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCRenameTask.java
new file mode 100644
index 000000000000..342621bf0d47
--- /dev/null
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCRenameTask.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.plugins.coursecreator.actions;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.Messages;
+import com.intellij.psi.PsiDirectory;
+import org.jetbrains.plugins.coursecreator.format.Course;
+import org.jetbrains.plugins.coursecreator.format.Lesson;
+import org.jetbrains.plugins.coursecreator.format.Task;
+
+public class CCRenameTask extends CCRename {
+ public CCRenameTask() {
+ super("Rename Task", "Rename Task", null);
+ }
+
+ @Override
+ public String getFolderName() {
+ return "task";
+ }
+
+ @Override
+ public boolean processRename(Project project, PsiDirectory directory, Course course) {
+ PsiDirectory lessonDir = directory.getParent();
+ if (lessonDir == null || !lessonDir.getName().contains("lesson")) {
+ return false;
+ }
+ Lesson lesson = course.getLesson(lessonDir.getName());
+ if (lesson == null) {
+ return false;
+ }
+ Task task = lesson.getTask(directory.getName());
+ if (task == null) {
+ return false;
+ }
+ String newName = Messages.showInputDialog(project, "Enter new name", "Rename " + getFolderName(), null);
+ if (newName == null) {
+ return false;
+ }
+ task.setName(newName);
+ return true;
+
+ }
+}
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCShowPreview.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCShowPreview.java
new file mode 100644
index 000000000000..bccaacaf1957
--- /dev/null
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CCShowPreview.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jetbrains.plugins.coursecreator.actions;
+
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.CommonDataKeys;
+import com.intellij.openapi.actionSystem.Presentation;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.fileEditor.FileEditorManager;
+import com.intellij.openapi.project.DumbAwareAction;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiDirectory;
+import com.intellij.psi.PsiFile;
+import com.intellij.util.containers.hash.HashMap;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.plugins.coursecreator.CCProjectService;
+import org.jetbrains.plugins.coursecreator.format.*;
+
+import java.util.Map;
+
+public class CCShowPreview extends DumbAwareAction {
+ public CCShowPreview() {
+ super("Show preview","Show preview", null);
+ }
+
+ @Override
+ public void update(@NotNull AnActionEvent e) {
+ Presentation presentation = e.getPresentation();
+ presentation.setEnabled(false);
+ presentation.setVisible(false);
+ final PsiFile file = CommonDataKeys.PSI_FILE.getData(e.getDataContext());
+ if (file != null && file.getName().contains(".answer")) {
+ presentation.setEnabled(true);
+ presentation.setVisible(true);
+ }
+ }
+
+ @Override
+ public void actionPerformed(@NotNull AnActionEvent e) {
+ final Project project = e.getProject();
+ if (project == null) {
+ return;
+ }
+ final PsiFile file = CommonDataKeys.PSI_FILE.getData(e.getDataContext());
+ if (file == null || !file.getName().contains(".answer")) {
+ return;
+ }
+ final PsiDirectory taskDir = file.getContainingDirectory();
+ if (taskDir == null) {
+ return;
+ }
+ PsiDirectory lessonDir = taskDir.getParentDirectory();
+ if (lessonDir == null) {
+ return;
+ }
+ Course course = CCProjectService.getInstance(project).getCourse();
+ if (course == null) {
+ return;
+ }
+ Lesson lesson = course.getLesson(lessonDir.getName());
+ Task task = lesson.getTask(taskDir.getName());
+ TaskFile taskFile = task.getTaskFile(file.getName());
+ final Map<TaskFile, TaskFile> taskFilesCopy = new HashMap<TaskFile, TaskFile>();
+ for (final Map.Entry<String, TaskFile> entry : task.getTaskFiles().entrySet()) {
+ if (entry.getValue() == taskFile) {
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ @Override
+ public void run() {
+ CreateCourseArchive.createUserFile(project, taskFilesCopy, taskDir.getVirtualFile(), taskDir.getVirtualFile(), entry);
+ }
+ });
+ }
+ }
+ String userFileName = FileUtil.getNameWithoutExtension(file.getName()) + ".py";
+ VirtualFile userFile = taskDir.getVirtualFile().findChild(userFileName);
+ if (userFile != null) {
+ FileEditorManager.getInstance(project).openFile(userFile, true);
+ Editor editor = FileEditorManager.getInstance(project).getSelectedTextEditor();
+ if (editor == null) {
+ return;
+ }
+ for (TaskWindow taskWindow : taskFile.getTaskWindows()) {
+ taskWindow.drawHighlighter(editor, true);
+ }
+ CreateCourseArchive.resetTaskFiles(taskFilesCopy);
+ }
+ }
+} \ No newline at end of file
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CreateCourseArchive.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CreateCourseArchive.java
index 05428f4e82d1..8db49156c987 100644
--- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CreateCourseArchive.java
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CreateCourseArchive.java
@@ -18,6 +18,7 @@ import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.util.io.ZipUtil;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.coursecreator.CCProjectService;
import org.jetbrains.plugins.coursecreator.StudyDocumentListener;
import org.jetbrains.plugins.coursecreator.format.*;
@@ -29,8 +30,8 @@ import java.util.zip.ZipOutputStream;
public class CreateCourseArchive extends DumbAwareAction {
private static final Logger LOG = Logger.getInstance(CreateCourseArchive.class.getName());
- String myZipName;
- String myLocationDir;
+ private String myZipName;
+ private String myLocationDir;
public void setZipName(String zipName) {
myZipName = zipName;
@@ -60,46 +61,124 @@ public class CreateCourseArchive extends DumbAwareAction {
}
final VirtualFile baseDir = project.getBaseDir();
final Map<String, Lesson> lessons = course.getLessonsMap();
- //List<FileEditor> editorList = new ArrayList<FileEditor>();
- Map<VirtualFile, TaskFile> taskFiles = new HashMap<VirtualFile, TaskFile>();
+ //map to store initial task file
+ final Map<TaskFile, TaskFile> taskFiles = new HashMap<TaskFile, TaskFile>();
for (Map.Entry<String, Lesson> lesson : lessons.entrySet()) {
final VirtualFile lessonDir = baseDir.findChild(lesson.getKey());
if (lessonDir == null) continue;
for (Map.Entry<String, Task> task : lesson.getValue().myTasksMap.entrySet()) {
final VirtualFile taskDir = lessonDir.findChild(task.getKey());
if (taskDir == null) continue;
- for (Map.Entry<String, TaskFile> entry : task.getValue().task_files.entrySet()) {
- final VirtualFile file = taskDir.findChild(entry.getKey());
- if (file == null) continue;
- final Document document = FileDocumentManager.getInstance().getDocument(file);
- if (document == null) continue;
- final TaskFile taskFile = entry.getValue();
- document.addDocumentListener(new InsertionListener(taskFile));
- taskFiles.put(file, taskFile);
- taskFile.setTrackChanges(false);
- Collections.sort(taskFile.getTaskWindows());
- for (int i = taskFile.getTaskWindows().size() - 1; i >=0 ; i--) {
- final TaskWindow taskWindow = taskFile.getTaskWindows().get(i);
- final String taskText = taskWindow.getTaskText();
- final int lineStartOffset = document.getLineStartOffset(taskWindow.line);
- final int offset = lineStartOffset + taskWindow.start;
- CommandProcessor.getInstance().executeCommand(project, new Runnable() {
- @Override
- public void run() {
- ApplicationManager.getApplication().runWriteAction(new Runnable() {
- @Override
- public void run() {
- document.replaceString(offset, offset + taskWindow.getReplacementLength(), taskText);
- FileDocumentManager.getInstance().saveDocument(document);
- }
- });
- }
- }, "x", "qwe");
- }
+ for (final Map.Entry<String, TaskFile> entry : task.getValue().task_files.entrySet()) {
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ @Override
+ public void run() {
+ createUserFile(project, taskFiles, taskDir, taskDir, entry);
+ }
+ });
}
}
}
generateJson(project);
+ packCourse(baseDir, lessons);
+ resetTaskFiles(taskFiles);
+ synchronize(project);
+ }
+
+ public static void createUserFile(@NotNull final Project project,
+ @NotNull final Map<TaskFile, TaskFile> taskFilesCopy,
+ @NotNull final VirtualFile userFileDir,
+ @NotNull final VirtualFile answerFileDir,
+ @NotNull final Map.Entry<String, TaskFile> taskFiles) {
+ final String name = taskFiles.getKey();
+ VirtualFile file = userFileDir.findChild(name);
+ if (file != null) {
+ try {
+ file.delete(project);
+ }
+ catch (IOException e) {
+ LOG.error(e);
+ }
+ }
+ try {
+ userFileDir.createChildData(project, name);
+ }
+ catch (IOException e) {
+ LOG.error(e);
+ }
+
+ file = userFileDir.findChild(name);
+ assert file != null;
+ String answerFileName = file.getNameWithoutExtension() + ".answer";
+ VirtualFile answerFile = answerFileDir.findChild(answerFileName);
+ if (answerFile == null) {
+ return;
+ }
+ final Document answerDocument = FileDocumentManager.getInstance().getDocument(answerFile);
+ if (answerDocument == null) {
+ return;
+ }
+ final Document document = FileDocumentManager.getInstance().getDocument(file);
+ if (document == null) return;
+ final TaskFile taskFile = taskFiles.getValue();
+ TaskFile taskFileSaved = new TaskFile();
+ taskFile.copy(taskFileSaved);
+ CommandProcessor.getInstance().executeCommand(project, new Runnable() {
+ @Override
+ public void run() {
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ @Override
+ public void run() {
+ document.replaceString(0, document.getTextLength(), answerDocument.getText());
+ }
+ });
+ }
+ }, "x", "qwe");
+ InsertionListener listener = new InsertionListener(taskFile);
+ document.addDocumentListener(listener);
+ taskFilesCopy.put(taskFile, taskFileSaved);
+ Collections.sort(taskFile.getTaskWindows());
+ for (int i = taskFile.getTaskWindows().size() - 1; i >= 0; i--) {
+ final TaskWindow taskWindow = taskFile.getTaskWindows().get(i);
+ replaceTaskWindow(project, document, taskWindow);
+ }
+ document.removeDocumentListener(listener);
+ }
+
+ private static void replaceTaskWindow(@NotNull final Project project,
+ @NotNull final Document document,
+ @NotNull final TaskWindow taskWindow) {
+ final String taskText = taskWindow.getTaskText();
+ final int lineStartOffset = document.getLineStartOffset(taskWindow.line);
+ final int offset = lineStartOffset + taskWindow.start;
+ CommandProcessor.getInstance().executeCommand(project, new Runnable() {
+ @Override
+ public void run() {
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ @Override
+ public void run() {
+ document.replaceString(offset, offset + taskWindow.getReplacementLength(), taskText);
+ FileDocumentManager.getInstance().saveDocument(document);
+ }
+ });
+ }
+ }, "x", "qwe");
+ }
+
+ private static void synchronize(@NotNull final Project project) {
+ VirtualFileManager.getInstance().refreshWithoutFileWatcher(true);
+ ProjectView.getInstance(project).refresh();
+ }
+
+ public static void resetTaskFiles(@NotNull final Map<TaskFile, TaskFile> taskFiles) {
+ for (Map.Entry<TaskFile, TaskFile> entry : taskFiles.entrySet()) {
+ TaskFile realTaskFile = entry.getKey();
+ TaskFile savedTaskFile = entry.getValue();
+ realTaskFile.update(savedTaskFile);
+ }
+ }
+
+ private void packCourse(@NotNull final VirtualFile baseDir, @NotNull final Map<String, Lesson> lessons) {
try {
File zipFile = new File(myLocationDir, myZipName + ".zip");
ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFile)));
@@ -108,7 +187,12 @@ public class CreateCourseArchive extends DumbAwareAction {
final VirtualFile lessonDir = baseDir.findChild(entry.getKey());
if (lessonDir == null) continue;
- ZipUtil.addFileOrDirRecursively(zos, null, new File(lessonDir.getPath()), lessonDir.getName(), null, null);
+ ZipUtil.addFileOrDirRecursively(zos, null, new File(lessonDir.getPath()), lessonDir.getName(), new FileFilter() {
+ @Override
+ public boolean accept(File pathname) {
+ return !pathname.getName().contains(".answer");
+ }
+ }, null);
}
ZipUtil.addFileOrDirRecursively(zos, null, new File(baseDir.getPath(), "hints"), "hints", null, null);
ZipUtil.addFileOrDirRecursively(zos, null, new File(baseDir.getPath(), "course.json"), "course.json", null, null);
@@ -119,36 +203,9 @@ public class CreateCourseArchive extends DumbAwareAction {
catch (IOException e1) {
LOG.error(e1);
}
-
- for (Map.Entry<VirtualFile, TaskFile> entry: taskFiles.entrySet()) {
- TaskFile value = entry.getValue();
- final Document document = FileDocumentManager.getInstance().getDocument(entry.getKey());
- if (document == null) {
- continue;
- }
- for (final TaskWindow taskWindow : value.getTaskWindows()){
- final int lineStartOffset = document.getLineStartOffset(taskWindow.line);
- final int offset = lineStartOffset + taskWindow.start;
- CommandProcessor.getInstance().executeCommand(project, new Runnable() {
- @Override
- public void run() {
- ApplicationManager.getApplication().runWriteAction(new Runnable() {
- @Override
- public void run() {
- document.replaceString(offset, offset + taskWindow.length, taskWindow.getPossibleAnswer());
- FileDocumentManager.getInstance().saveDocument(document);
- }
- });
- }
- }, "x", "qwe");
- }
- value.setTrackChanges(true);
- }
- VirtualFileManager.getInstance().refreshWithoutFileWatcher(true);
- ProjectView.getInstance(project).refresh();
}
- private void generateJson(Project project) {
+ private static void generateJson(@NotNull final Project project) {
final CCProjectService service = CCProjectService.getInstance(project);
final Course course = service.getCourse();
final Gson gson = new GsonBuilder().setPrettyPrinting().excludeFieldsWithoutExposeAnnotation().create();
@@ -179,7 +236,7 @@ public class CreateCourseArchive extends DumbAwareAction {
}
}
- private class InsertionListener extends StudyDocumentListener {
+ private static class InsertionListener extends StudyDocumentListener {
public InsertionListener(TaskFile taskFile) {
super(taskFile);
@@ -187,12 +244,7 @@ public class CreateCourseArchive extends DumbAwareAction {
@Override
protected void updateTaskWindowLength(CharSequence fragment, TaskWindow taskWindow, int change) {
- //we don't need to update task window length
- }
-
- @Override
- protected boolean needModify() {
- return true;
+ //we don't need to update task window length
}
}
} \ No newline at end of file
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CreateTask.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CreateTask.java
index 0940135b97be..57a37b3f4194 100644
--- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CreateTask.java
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CreateTask.java
@@ -18,6 +18,7 @@ import com.intellij.openapi.ui.Messages;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiElement;
import com.intellij.util.PlatformIcons;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.coursecreator.CCProjectService;
import org.jetbrains.plugins.coursecreator.format.Course;
import org.jetbrains.plugins.coursecreator.format.Lesson;
@@ -29,7 +30,7 @@ public class CreateTask extends DumbAwareAction {
}
@Override
- public void actionPerformed(AnActionEvent e) {
+ public void actionPerformed(final AnActionEvent e) {
final IdeView view = e.getData(LangDataKeys.IDE_VIEW);
final Project project = e.getData(CommonDataKeys.PROJECT);
@@ -42,7 +43,7 @@ public class CreateTask extends DumbAwareAction {
final CCProjectService service = CCProjectService.getInstance(project);
final Course course = service.getCourse();
final Lesson lesson = course.getLesson(directory.getName());
- final int size = lesson.getTasklist().size();
+ final int size = lesson.getTaskList().size();
final String taskName = Messages.showInputDialog("Name:", "Task Name", null, "task" + (size + 1), null);
if (taskName == null) return;
@@ -54,17 +55,16 @@ public class CreateTask extends DumbAwareAction {
if (taskDirectory != null) {
final FileTemplate template = FileTemplateManager.getInstance().getInternalTemplate("task.html");
final FileTemplate testsTemplate = FileTemplateManager.getInstance().getInternalTemplate("tests");
- final FileTemplate taskTemplate = FileTemplateManager.getInstance().getInternalTemplate("task.py");
+ final FileTemplate taskTemplate = FileTemplateManager.getInstance().getInternalTemplate("task.answer");
try {
final PsiElement taskFile = FileTemplateUtil.createFromTemplate(template, "task.html", null, taskDirectory);
final PsiElement testsFile = FileTemplateUtil.createFromTemplate(testsTemplate, "tests.py", null, taskDirectory);
- final PsiElement taskPyFile = FileTemplateUtil.createFromTemplate(taskTemplate, "file1" + ".py", null, taskDirectory);
+ final PsiElement taskPyFile = FileTemplateUtil.createFromTemplate(taskTemplate, "file1", null, taskDirectory);
final Task task = new Task(taskName);
- task.addTaskFile(taskPyFile.getContainingFile().getName(), size + 1);
+ task.addTaskFile("file1.py", size + 1);
task.setIndex(size + 1);
lesson.addTask(task, taskDirectory);
-
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
@@ -84,7 +84,7 @@ public class CreateTask extends DumbAwareAction {
}
@Override
- public void update(AnActionEvent event) {
+ public void update(@NotNull AnActionEvent event) {
final Presentation presentation = event.getPresentation();
final Project project = event.getData(CommonDataKeys.PROJECT);
if (project == null) {
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CreateTaskFile.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CreateTaskFile.java
index 5aafcebefd6e..368be275a5a4 100644
--- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CreateTaskFile.java
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/actions/CreateTaskFile.java
@@ -55,10 +55,10 @@ public class CreateTaskFile extends DumbAwareAction {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
- final FileTemplate taskTemplate = FileTemplateManager.getInstance().getInternalTemplate("task.py");
+ final FileTemplate taskTemplate = FileTemplateManager.getInstance().getInternalTemplate("task.answer");
try {
- final PsiElement taskPyFile = FileTemplateUtil.createFromTemplate(taskTemplate, taskFileName + ".py", null, taskDir);
- task.addTaskFile(taskPyFile.getContainingFile().getName(), index);
+ final PsiElement taskPyFile = FileTemplateUtil.createFromTemplate(taskTemplate, taskFileName, null, taskDir);
+ task.addTaskFile(taskFileName + ".py", index);
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/Course.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/Course.java
index eb62d59cd9b1..e124a6eb305d 100644
--- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/Course.java
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/Course.java
@@ -4,10 +4,7 @@ import com.google.gson.annotations.Expose;
import com.intellij.psi.PsiDirectory;
import org.jetbrains.annotations.NotNull;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
public class Course {
@Expose public List<Lesson> lessons = new ArrayList<Lesson>();
@@ -52,4 +49,13 @@ public class Course {
public String getDescription() {
return description;
}
+
+ public void init() {
+ lessons.clear();
+ for (Lesson lesson: myLessonsMap.values()) {
+ lessons.add(lesson);
+ lesson.init();
+ }
+ Collections.sort(lessons);
+ }
}
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/Lesson.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/Lesson.java
index 38720140caf1..bd91e8ec30af 100644
--- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/Lesson.java
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/Lesson.java
@@ -4,12 +4,9 @@ import com.google.gson.annotations.Expose;
import com.intellij.psi.PsiDirectory;
import org.jetbrains.annotations.NotNull;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
-public class Lesson {
+public class Lesson implements Comparable{
@Expose public String name;
@Expose public List<Task> task_list = new ArrayList<Task>();
@@ -27,11 +24,15 @@ public class Lesson {
task_list.add(task);
}
+ public void setName(String name) {
+ this.name = name;
+ }
+
public Task getTask(@NotNull final String name) {
return myTasksMap.get(name);
}
- public List<Task> getTasklist() {
+ public List<Task> getTaskList() {
return task_list;
}
@@ -42,4 +43,22 @@ public class Lesson {
public int getIndex() {
return myIndex;
}
+
+ public Map<String, Task> getTasksMap() {
+ return myTasksMap;
+ }
+
+ public void init() {
+ task_list.clear();
+ for (Task task : myTasksMap.values()) {
+ task_list.add(task);
+ }
+ Collections.sort(task_list);
+ }
+
+ @Override
+ public int compareTo(@NotNull Object o) {
+ Lesson lesson = (Lesson) o;
+ return myIndex - lesson.getIndex();
+ }
}
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/Task.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/Task.java
index e6c085b5d6a1..886add86ceb4 100644
--- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/Task.java
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/Task.java
@@ -2,11 +2,12 @@ package org.jetbrains.plugins.coursecreator.format;
import com.google.gson.annotations.Expose;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.plugins.coursecreator.CCProjectService;
import java.util.HashMap;
import java.util.Map;
-public class Task {
+public class Task implements Comparable{
@Expose public String name;
@Expose public Map<String, TaskFile> task_files = new HashMap<String, TaskFile>();
public int myIndex;
@@ -28,7 +29,8 @@ public class Task {
}
public TaskFile getTaskFile(@NotNull final String name) {
- return task_files.get(name);
+ String fileName = CCProjectService.getRealTaskFileName(name);
+ return fileName != null ? task_files.get(fileName) : null;
}
public void setIndex(int index) {
@@ -38,4 +40,18 @@ public class Task {
public Map<String, TaskFile> getTaskFiles() {
return task_files;
}
+
+ public boolean isTaskFile(String name) {
+ return task_files.get(name) != null;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public int compareTo(@NotNull Object o) {
+ Task task = (Task) o;
+ return myIndex - task.getIndex();
+ }
}
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/TaskFile.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/TaskFile.java
index 85f0d91983f2..b88e375bc265 100644
--- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/TaskFile.java
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/TaskFile.java
@@ -13,15 +13,6 @@ import java.util.List;
public class TaskFile {
@Expose public List<TaskWindow> task_windows = new ArrayList<TaskWindow>();
public int myIndex;
- public boolean myTrackChanges = true;
-
- public boolean isTrackChanges() {
- return myTrackChanges;
- }
-
- public void setTrackChanges(boolean trackChanges) {
- myTrackChanges = trackChanges;
- }
public TaskFile() {}
@@ -108,4 +99,22 @@ public class TaskFile {
}
}
}
+
+ public void copy(@NotNull final TaskFile target) {
+ target.setIndex(myIndex);
+ for (TaskWindow taskWindow : task_windows) {
+ TaskWindow savedWindow = new TaskWindow(taskWindow.getLine(), taskWindow.getStart(),
+ taskWindow.getLength(), "");
+ target.getTaskWindows().add(savedWindow);
+ savedWindow.setIndex(taskWindow.getIndex());
+ }
+ }
+
+ public void update(@NotNull final TaskFile source) {
+ for (TaskWindow taskWindow : source.getTaskWindows()) {
+ TaskWindow taskWindowUpdated = task_windows.get(taskWindow.getIndex() - 1);
+ taskWindowUpdated.setLine(taskWindow.getLine());
+ taskWindowUpdated.setStart(taskWindow.getStart());
+ }
+ }
}
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/TaskWindow.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/TaskWindow.java
index cb6418ec75d7..6b1be7ef3e7d 100644
--- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/TaskWindow.java
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/format/TaskWindow.java
@@ -68,16 +68,17 @@ public class TaskWindow implements Comparable{
}
}
- public void drawHighlighter(@NotNull final Editor editor) {
+ public void drawHighlighter(@NotNull final Editor editor, boolean useLength) {
int startOffset = editor.getDocument().getLineStartOffset(line) + start;
- int endOffset = startOffset + myReplacementLength;
+ int highlighterLength = useLength ? length : myReplacementLength;
+ int endOffset = startOffset + highlighterLength;
TextAttributes defaultTestAttributes =
EditorColorsManager.getInstance().getGlobalScheme().getAttributes(EditorColors.LIVE_TEMPLATE_ATTRIBUTES);
RangeHighlighter highlighter =
editor.getMarkupModel().addRangeHighlighter(startOffset, endOffset, HighlighterLayer.LAST + 1, defaultTestAttributes,
HighlighterTargetArea.EXACT_RANGE);
highlighter.setGreedyToLeft(true);
- highlighter.setGreedyToRight(true);
+ highlighter.setGreedyToRight(false);
}
public int getIndex() {
@@ -123,10 +124,6 @@ public class TaskWindow implements Comparable{
return lineDiff;
}
- public String getPossibleAnswer() {
- return possible_answer;
- }
-
public int getLength() {
return length;
}
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/projectView/CCDirectoryNode.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/projectView/CCDirectoryNode.java
index 1a7304123f0a..0969c54563c2 100644
--- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/projectView/CCDirectoryNode.java
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/projectView/CCDirectoryNode.java
@@ -26,6 +26,8 @@ public class CCDirectoryNode extends PsiDirectoryNode {
@Override
protected void updateImpl(PresentationData data) {
+ //TODO:change presentable name for files with suffix _answer
+
String valueName = myValue.getName();
final Course course = CCProjectService.getInstance(myProject).getCourse();
if (course == null) return;
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/projectView/CCTreeStructureProvider.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/projectView/CCTreeStructureProvider.java
index 69b78ec9a92b..b4fb50a96dc4 100644
--- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/projectView/CCTreeStructureProvider.java
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/projectView/CCTreeStructureProvider.java
@@ -2,9 +2,11 @@ package org.jetbrains.plugins.coursecreator.projectView;
import com.intellij.ide.projectView.TreeStructureProvider;
import com.intellij.ide.projectView.ViewSettings;
+import com.intellij.ide.projectView.impl.nodes.PsiFileNode;
import com.intellij.ide.util.treeView.AbstractTreeNode;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -27,11 +29,21 @@ public class CCTreeStructureProvider implements TreeStructureProvider, DumbAware
Project project = node.getProject();
if (project != null) {
if (node.getValue() instanceof PsiDirectory) {
- PsiDirectory directory = (PsiDirectory) node.getValue();
+ PsiDirectory directory = (PsiDirectory)node.getValue();
nodes.add(new CCDirectoryNode(project, directory, settings));
- } else {
- nodes.add(node);
+ continue;
}
+ if (node instanceof PsiFileNode) {
+ PsiFileNode fileNode = (PsiFileNode)node;
+ VirtualFile virtualFile = fileNode.getVirtualFile();
+ if (virtualFile == null) {
+ continue;
+ }
+ if (CCProjectService.getInstance(project).isTaskFile(virtualFile)) {
+ continue;
+ }
+ }
+ nodes.add(node);
}
}
return nodes;
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/ui/CreateCourseArchivePanel.form b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/ui/CreateCourseArchivePanel.form
index 920dcb9494a7..096a85f8da59 100644
--- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/ui/CreateCourseArchivePanel.form
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/ui/CreateCourseArchivePanel.form
@@ -27,7 +27,7 @@
<component id="160bb" class="javax.swing.JTextField" binding="myNameField" default-binding="true">
<constraints>
<grid row="0" column="1" row-span="2" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
- <preferred-size width="150" height="-1"/>
+ <preferred-size width="300" height="-1"/>
</grid>
</constraints>
<properties/>
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/ui/CreateTaskWindowDialog.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/ui/CreateTaskWindowDialog.java
index c7e8f715672c..53a4a77b97f7 100644
--- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/ui/CreateTaskWindowDialog.java
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/ui/CreateTaskWindowDialog.java
@@ -150,4 +150,10 @@ public class CreateTaskWindowDialog extends DialogWrapper {
public void validateInput() {
super.initValidation();
}
+
+ @Nullable
+ @Override
+ public JComponent getPreferredFocusedComponent() {
+ return myPanel.getPreferredFocusedComponent();
+ }
}
diff --git a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/ui/CreateTaskWindowPanel.java b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/ui/CreateTaskWindowPanel.java
index 21a7eb063c63..a50840deaf2f 100644
--- a/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/ui/CreateTaskWindowPanel.java
+++ b/python/edu/course-creator/src/org/jetbrains/plugins/coursecreator/ui/CreateTaskWindowPanel.java
@@ -37,6 +37,7 @@ public class CreateTaskWindowPanel extends JPanel {
}
});
+ myTaskWindowText.grabFocus();
myHintName.getDocument().addDocumentListener(new DocumentAdapter() {
@Override
protected void textChanged(DocumentEvent e) {
@@ -93,4 +94,8 @@ public class CreateTaskWindowPanel extends JPanel {
public void setGeneratedHintName(String generatedHintName) {
myGeneratedHintName = generatedHintName;
}
+
+ public JComponent getPreferredFocusedComponent() {
+ return myTaskWindowText;
+ }
}
diff --git a/python/edu/learn-python/resources/META-INF/plugin.xml b/python/edu/learn-python/resources/META-INF/plugin.xml
index 8e8bddcce5e5..b6ff0ce5d0d7 100644
--- a/python/edu/learn-python/resources/META-INF/plugin.xml
+++ b/python/edu/learn-python/resources/META-INF/plugin.xml
@@ -40,7 +40,7 @@
<actions>
<action id="CheckAction" class="com.jetbrains.python.edu.actions.StudyCheckAction" text="check"
- description="Runs tests for current tasks" icon="/icons/icon.jpg">
+ description="Runs tests for current tasks">
</action>
<action id="PrevWindowAction" class="com.jetbrains.python.edu.actions.StudyPrevWindowAction" text="PrevWindowAction" description="prev">
</action>
@@ -60,10 +60,12 @@
<add-to-group group-id="MainToolBar" anchor="last"/>
</action>
- <action id="WelcomeScreen.LearnPython" class="com.jetbrains.python.edu.actions.StudyNewProject" icon="StudyIcons.EducationalProjectType">
+ <action id="WelcomeScreen.PythonIntro" class="com.jetbrains.python.edu.actions.StudyIntroductionCourseAction" icon="StudyIcons.EducationalProjectType">
<add-to-group group-id="WelcomeScreen.QuickStart" anchor="first"/>
</action>
+ <action id="ReloadCourseAction" class="com.jetbrains.python.edu.actions.StudyReloadCourseAction"/>
+
</actions>
<extensions defaultExtensionNs="com.intellij">
@@ -74,6 +76,7 @@
<highlightErrorFilter implementation="com.jetbrains.python.edu.StudyHighlightErrorFilter"/>
<applicationService serviceInterface="com.intellij.openapi.fileEditor.impl.EditorEmptyTextPainter"
serviceImplementation="com.jetbrains.python.edu.StudyInstructionPainter" overrides="true"/>
+ <errorHandler implementation="com.intellij.diagnostic.ITNReporter"/>
</extensions>
<extensions defaultExtensionNs="Pythonid">
<visitorFilter language="Python" implementationClass="com.jetbrains.python.edu.highlighting.StudyVisitorFilter"/>
diff --git a/python/edu/learn-python/resources/courses/introduction_course.zip b/python/edu/learn-python/resources/courses/introduction_course.zip
index c39695e0c380..4fd2dab43830 100644
--- a/python/edu/learn-python/resources/courses/introduction_course.zip
+++ b/python/edu/learn-python/resources/courses/introduction_course.zip
Binary files differ
diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/StudyDirectoryProjectGenerator.java b/python/edu/learn-python/src/com/jetbrains/python/edu/StudyDirectoryProjectGenerator.java
index 59bd8bc2ea7c..b558667734bc 100644
--- a/python/edu/learn-python/src/com/jetbrains/python/edu/StudyDirectoryProjectGenerator.java
+++ b/python/edu/learn-python/src/com/jetbrains/python/edu/StudyDirectoryProjectGenerator.java
@@ -53,7 +53,7 @@ public class StudyDirectoryProjectGenerator extends PythonProjectGenerator imple
@NotNull
@Override
public String getName() {
- return "Learn Python";
+ return "Educational";
}
diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/StudyTestRunner.java b/python/edu/learn-python/src/com/jetbrains/python/edu/StudyTestRunner.java
index b0cd5ba89fed..1800deb0a0d9 100644
--- a/python/edu/learn-python/src/com/jetbrains/python/edu/StudyTestRunner.java
+++ b/python/edu/learn-python/src/com/jetbrains/python/edu/StudyTestRunner.java
@@ -61,7 +61,9 @@ public class StudyTestRunner {
try {
while ((line = testOutputReader.readLine()) != null) {
if (line.contains(TEST_FAILED)) {
- return line.substring(TEST_FAILED.length(), line.length());
+ String res = line.substring(TEST_FAILED.length(), line.length());
+ StudyUtils.closeSilently(testOutputReader);
+ return res;
}
}
}
diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyIntroductionCourseAction.java b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyIntroductionCourseAction.java
new file mode 100644
index 000000000000..ed1fff22878f
--- /dev/null
+++ b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyIntroductionCourseAction.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2000-2013 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.edu.actions;
+
+import com.intellij.ide.impl.ProjectUtil;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.project.ProjectManager;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.jetbrains.python.configuration.PyConfigurableInterpreterList;
+import com.jetbrains.python.edu.StudyDirectoryProjectGenerator;
+import com.jetbrains.python.edu.StudyUtils;
+import com.jetbrains.python.edu.course.CourseInfo;
+import com.jetbrains.python.newProject.actions.GenerateProjectCallback;
+import com.jetbrains.python.newProject.actions.ProjectSpecificSettingsStep;
+import icons.StudyIcons;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.File;
+import java.util.List;
+import java.util.Map;
+
+public class StudyIntroductionCourseAction extends AnAction {
+
+ public StudyIntroductionCourseAction() {
+ super("Introduction to Python", "Introduction to Python", StudyIcons.EducationalProjectType);
+ }
+
+ @Override
+ public void actionPerformed(@NotNull AnActionEvent e) {
+ final File projectDir = new File(ProjectUtil.getBaseDir(), "PythonIntroduction");
+ if (projectDir.exists()) {
+ ProjectUtil.openProject(projectDir.getPath(), null, false);
+ }
+ else {
+ final GenerateProjectCallback callback = new GenerateProjectCallback(null);
+ final StudyDirectoryProjectGenerator generator = new StudyDirectoryProjectGenerator();
+ final Map<CourseInfo, File> courses = generator.getCourses();
+ CourseInfo introCourse = null;
+ for (CourseInfo info : courses.keySet()) {
+ if ("Introduction to Python".equals(info.getName())) {
+ introCourse = info;
+ }
+ }
+ if (introCourse == null) {
+ introCourse = StudyUtils.getFirst(courses.keySet());
+ }
+ generator.setSelectedCourse(introCourse);
+ final ProjectSpecificSettingsStep step = new ProjectSpecificSettingsStep(generator, callback, true);
+
+ step.createPanel(); // initialize panel to set location
+ step.setLocation(projectDir.toString());
+
+ final Project project = ProjectManager.getInstance().getDefaultProject();
+ final List<Sdk> sdks = PyConfigurableInterpreterList.getInstance(project).getAllPythonSdks();
+ Sdk sdk = sdks.isEmpty() ? null : sdks.iterator().next();
+ step.setSdk(sdk);
+ callback.consume(step);
+ }
+ }
+}
diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyRefreshTaskFileAction.java b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyRefreshTaskFileAction.java
index a9448ddea0e3..a6c16d2553bf 100644
--- a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyRefreshTaskFileAction.java
+++ b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyRefreshTaskFileAction.java
@@ -22,108 +22,139 @@ import com.jetbrains.python.edu.StudyTaskManager;
import com.jetbrains.python.edu.StudyUtils;
import com.jetbrains.python.edu.course.*;
import com.jetbrains.python.edu.editor.StudyEditor;
+import org.jetbrains.annotations.NotNull;
import java.io.*;
public class StudyRefreshTaskFileAction extends DumbAwareAction {
private static final Logger LOG = Logger.getInstance(StudyRefreshTaskFileAction.class.getName());
- public void refresh(final Project project) {
- ApplicationManager.getApplication().invokeLater(new Runnable() {
+ public static void refresh(final Project project) {
+ ApplicationManager.getApplication().invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ @SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
@Override
public void run() {
- ApplicationManager.getApplication().runWriteAction(new Runnable() {
- @SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
- @Override
- public void run() {
- final Editor editor = StudyEditor.getSelectedEditor(project);
- assert editor != null;
- final Document document = editor.getDocument();
- StudyDocumentListener listener = StudyEditor.getListener(document);
- if (listener != null) {
- document.removeDocumentListener(listener);
- }
- final int lineCount = document.getLineCount();
- if (lineCount != 0) {
- CommandProcessor.getInstance().runUndoTransparentAction(new Runnable() {
- @Override
- public void run() {
- document.deleteString(0, document.getLineEndOffset(lineCount - 1));
- }
- });
- }
- StudyTaskManager taskManager = StudyTaskManager.getInstance(project);
- Course course = taskManager.getCourse();
- assert course != null;
- File resourceFile = new File(course.getResourcePath());
- File resourceRoot = resourceFile.getParentFile();
- FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance();
- VirtualFile openedFile = fileDocumentManager.getFile(document);
- assert openedFile != null;
- final TaskFile selectedTaskFile = taskManager.getTaskFile(openedFile);
- assert selectedTaskFile != null;
- Task currentTask = selectedTaskFile.getTask();
- String lessonDir = Lesson.LESSON_DIR + String.valueOf(currentTask.getLesson().getIndex() + 1);
- String taskDir = Task.TASK_DIR + String.valueOf(currentTask.getIndex() + 1);
- File pattern = new File(new File(new File(resourceRoot, lessonDir), taskDir), openedFile.getName());
- BufferedReader reader = null;
- try {
- reader = new BufferedReader(new InputStreamReader(new FileInputStream(pattern)));
- String line;
- StringBuilder patternText = new StringBuilder();
- while ((line = reader.readLine()) != null) {
- patternText.append(line);
- patternText.append("\n");
- }
- int patternLength = patternText.length();
- if (patternText.charAt(patternLength - 1) == '\n') {
- patternText.delete(patternLength - 1, patternLength);
- }
- document.setText(patternText);
- StudyStatus oldStatus = currentTask.getStatus();
- LessonInfo lessonInfo = currentTask.getLesson().getLessonInfo();
- lessonInfo.update(oldStatus, -1);
- lessonInfo.update(StudyStatus.Unchecked, +1);
- StudyUtils.updateStudyToolWindow(project);
- for (TaskWindow taskWindow : selectedTaskFile.getTaskWindows()) {
- taskWindow.reset();
- }
- ProjectView.getInstance(project).refresh();
- if (listener != null) {
- document.addDocumentListener(listener);
- }
- selectedTaskFile.drawAllWindows(editor);
- ApplicationManager.getApplication().invokeLater(new Runnable() {
- @Override
- public void run() {
- IdeFocusManager.getInstance(project).requestFocus(editor.getContentComponent(), true);
- }
- });
- selectedTaskFile.navigateToFirstTaskWindow(editor);
- BalloonBuilder balloonBuilder =
- JBPopupFactory.getInstance().createHtmlTextBalloonBuilder("You can now start again", MessageType.INFO, null);
- final Balloon balloon = balloonBuilder.createBalloon();
- StudyEditor selectedStudyEditor = StudyEditor.getSelectedStudyEditor(project);
- assert selectedStudyEditor != null;
- balloon.showInCenterOf(selectedStudyEditor.getRefreshButton());
- Disposer.register(project, balloon);
- }
- catch (FileNotFoundException e1) {
- LOG.error(e1);
- }
- catch (IOException e1) {
- LOG.error(e1);
- }
- finally {
- StudyUtils.closeSilently(reader);
- }
- }
- });
+ final Editor editor = StudyEditor.getSelectedEditor(project);
+ assert editor != null;
+ final Document document = editor.getDocument();
+ refreshFile(editor, document, project);
}
});
+ }
+ });
}
- public void actionPerformed(AnActionEvent e) {
+ public static void refreshFile(@NotNull final Editor editor, @NotNull final Document document, @NotNull final Project project) {
+ StudyTaskManager taskManager = StudyTaskManager.getInstance(project);
+ Course course = taskManager.getCourse();
+ assert course != null;
+ FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance();
+ VirtualFile openedFile = fileDocumentManager.getFile(document);
+ assert openedFile != null;
+ final TaskFile selectedTaskFile = taskManager.getTaskFile(openedFile);
+ assert selectedTaskFile != null;
+ String openedFileName = openedFile.getName();
+ Task currentTask = selectedTaskFile.getTask();
+ resetTaskFile(document, project, course, selectedTaskFile, openedFileName, currentTask);
+ selectedTaskFile.drawAllWindows(editor);
+ ApplicationManager.getApplication().invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ IdeFocusManager.getInstance(project).requestFocus(editor.getContentComponent(), true);
+ }
+ });
+ selectedTaskFile.navigateToFirstTaskWindow(editor);
+ showBaloon(project);
+ }
+
+ public static void resetTaskFile(Document document, Project project, Course course, TaskFile taskFile, String name, Task task) {
+ resetDocument(document, course, name, task);
+ updateLessonInfo(task);
+ StudyUtils.updateStudyToolWindow(project);
+ resetTaskWindows(taskFile);
+ ProjectView.getInstance(project).refresh();
+ }
+
+ private static void showBaloon(Project project) {
+ BalloonBuilder balloonBuilder =
+ JBPopupFactory.getInstance().createHtmlTextBalloonBuilder("You can now start again", MessageType.INFO, null);
+ final Balloon balloon = balloonBuilder.createBalloon();
+ StudyEditor selectedStudyEditor = StudyEditor.getSelectedStudyEditor(project);
+ assert selectedStudyEditor != null;
+ balloon.showInCenterOf(selectedStudyEditor.getRefreshButton());
+ Disposer.register(project, balloon);
+ }
+
+ private static void resetTaskWindows(TaskFile selectedTaskFile) {
+ for (TaskWindow taskWindow : selectedTaskFile.getTaskWindows()) {
+ taskWindow.reset();
+ }
+ }
+
+ private static void updateLessonInfo(Task currentTask) {
+ StudyStatus oldStatus = currentTask.getStatus();
+ LessonInfo lessonInfo = currentTask.getLesson().getLessonInfo();
+ lessonInfo.update(oldStatus, -1);
+ lessonInfo.update(StudyStatus.Unchecked, +1);
+ }
+
+ @SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
+ private static void resetDocument(Document document, Course course, String fileName, Task task) {
+ BufferedReader reader = null;
+ StudyDocumentListener listener = StudyEditor.getListener(document);
+ if (listener != null) {
+ document.removeDocumentListener(listener);
+ }
+ clearDocument(document);
+ try {
+ String lessonDir = Lesson.LESSON_DIR + String.valueOf(task.getLesson().getIndex() + 1);
+ String taskDir = Task.TASK_DIR + String.valueOf(task.getIndex() + 1);
+ File resourceFile = new File(course.getResourcePath());
+ File resourceRoot = resourceFile.getParentFile();
+ File pattern = new File(new File(new File(resourceRoot, lessonDir), taskDir), fileName);
+ reader = new BufferedReader(new InputStreamReader(new FileInputStream(pattern)));
+ String line;
+ StringBuilder patternText = new StringBuilder();
+ while ((line = reader.readLine()) != null) {
+ patternText.append(line);
+ patternText.append("\n");
+ }
+ int patternLength = patternText.length();
+ if (patternText.charAt(patternLength - 1) == '\n') {
+ patternText.delete(patternLength - 1, patternLength);
+ }
+ document.setText(patternText);
+ }
+ catch (FileNotFoundException e) {
+ LOG.error(e);
+ }
+ catch (IOException e) {
+ LOG.error(e);
+ }
+ finally {
+ StudyUtils.closeSilently(reader);
+ }
+ if (listener != null) {
+ document.addDocumentListener(listener);
+ }
+ }
+
+ private static void clearDocument(final Document document) {
+ final int lineCount = document.getLineCount();
+ if (lineCount != 0) {
+ CommandProcessor.getInstance().runUndoTransparentAction(new Runnable() {
+ @Override
+ public void run() {
+ document.deleteString(0, document.getLineEndOffset(lineCount - 1));
+ }
+ });
+ }
+ }
+
+ public void actionPerformed(@NotNull AnActionEvent e) {
refresh(e.getProject());
}
}
diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyReloadCourseAction.java b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyReloadCourseAction.java
new file mode 100644
index 000000000000..beefaaa94f7e
--- /dev/null
+++ b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyReloadCourseAction.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.edu.actions;
+
+import com.intellij.ide.projectView.ProjectView;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.Presentation;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.fileEditor.FileEditorManager;
+import com.intellij.openapi.project.DumbAwareAction;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.util.ui.tree.TreeUtil;
+import com.jetbrains.python.edu.StudyTaskManager;
+import com.jetbrains.python.edu.StudyUtils;
+import com.jetbrains.python.edu.course.Course;
+import com.jetbrains.python.edu.course.Lesson;
+import com.jetbrains.python.edu.course.Task;
+import com.jetbrains.python.edu.course.TaskFile;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+import javax.swing.tree.TreePath;
+import java.util.List;
+import java.util.Map;
+
+public class StudyReloadCourseAction extends DumbAwareAction {
+
+ public StudyReloadCourseAction() {
+ super("Reload Course", "Reload Course", null);
+ }
+
+ @Override
+ public void update(@NotNull AnActionEvent e) {
+ Presentation presentation = e.getPresentation();
+ Project project = e.getProject();
+ if (project != null) {
+ Course course = StudyTaskManager.getInstance(project).getCourse();
+ if (course != null) {
+ presentation.setVisible(true);
+ presentation.setEnabled(true);
+ }
+ }
+ presentation.setVisible(false);
+ presentation.setEnabled(false);
+ }
+
+ @Override
+ public void actionPerformed(@NotNull AnActionEvent e) {
+ Project project = e.getProject();
+ if (project == null) {
+ return;
+ }
+ reloadCourse(project);
+ }
+
+ public static void reloadCourse(@NotNull final Project project) {
+ ApplicationManager.getApplication().invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ @Override
+ public void run() {
+ Course course = StudyTaskManager.getInstance(project).getCourse();
+ if (course == null) {
+ return;
+ }
+ for (VirtualFile file : FileEditorManager.getInstance(project).getOpenFiles()) {
+ FileEditorManager.getInstance(project).closeFile(file);
+ }
+ JTree tree = ProjectView.getInstance(project).getCurrentProjectViewPane().getTree();
+ TreePath path = TreeUtil.getFirstNodePath(tree);
+ tree.collapsePath(path);
+ List<Lesson> lessons = course.getLessons();
+ for (Lesson lesson : lessons) {
+ List<Task> tasks = lesson.getTaskList();
+ VirtualFile lessonDir = project.getBaseDir().findChild(Lesson.LESSON_DIR + (lesson.getIndex() + 1));
+ if (lessonDir == null) {
+ continue;
+ }
+ for (Task task : tasks) {
+ VirtualFile taskDir = lessonDir.findChild(Task.TASK_DIR + (task.getIndex() + 1));
+ if (taskDir == null) {
+ continue;
+ }
+ Map<String, TaskFile> taskFiles = task.getTaskFiles();
+ for (Map.Entry<String, TaskFile> entry : taskFiles.entrySet()) {
+ String name = entry.getKey();
+ TaskFile taskFile = entry.getValue();
+ VirtualFile file = taskDir.findChild(name);
+ if (file == null) {
+ continue;
+ }
+ Document document = FileDocumentManager.getInstance().getDocument(file);
+ if (document == null) {
+ continue;
+ }
+ StudyRefreshTaskFileAction.resetTaskFile(document, project, course, taskFile, name, task);
+ }
+ }
+ }
+ Lesson firstLesson = StudyUtils.getFirst(lessons);
+ if (firstLesson == null) {
+ return;
+ }
+ Task firstTask = StudyUtils.getFirst(firstLesson.getTaskList());
+ VirtualFile lessonDir = project.getBaseDir().findChild(Lesson.LESSON_DIR + (firstLesson.getIndex() + 1));
+ if (lessonDir != null) {
+ VirtualFile taskDir = lessonDir.findChild(Task.TASK_DIR + (firstTask.getIndex() + 1));
+ if (taskDir != null) {
+ ProjectView.getInstance(project).select(taskDir, taskDir, true);
+ }
+ }
+ }
+ });
+ }
+ });
+ }
+}
diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyTaskNavigationAction.java b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyTaskNavigationAction.java
index 46c0981cb964..b98bbd098776 100644
--- a/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyTaskNavigationAction.java
+++ b/python/edu/learn-python/src/com/jetbrains/python/edu/actions/StudyTaskNavigationAction.java
@@ -1,5 +1,6 @@
package com.jetbrains.python.edu.actions;
+import com.intellij.ide.projectView.ProjectView;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.project.DumbAwareAction;
@@ -12,6 +13,7 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowId;
import com.intellij.openapi.wm.ToolWindowManager;
+import com.intellij.util.ui.tree.TreeUtil;
import com.jetbrains.python.edu.StudyState;
import com.jetbrains.python.edu.course.Lesson;
import com.jetbrains.python.edu.course.Task;
@@ -20,6 +22,7 @@ import com.jetbrains.python.edu.editor.StudyEditor;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
+import javax.swing.tree.TreePath;
import java.util.Map;
@@ -74,7 +77,11 @@ abstract public class StudyTaskNavigationAction extends DumbAwareAction {
}
}
}
+ JTree tree = ProjectView.getInstance(project).getCurrentProjectViewPane().getTree();
+ TreePath path = TreeUtil.getFirstNodePath(tree);
+ tree.collapsePath(path);
if (shouldBeActive != null) {
+ ProjectView.getInstance(project).select(shouldBeActive, shouldBeActive, false);
FileEditorManager.getInstance(project).openFile(shouldBeActive, true);
}
ToolWindow runToolWindow = ToolWindowManager.getInstance(project).getToolWindow(ToolWindowId.RUN);
diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/projectView/StudyDirectoryNode.java b/python/edu/learn-python/src/com/jetbrains/python/edu/projectView/StudyDirectoryNode.java
index 2f80dba12695..d8faacd23946 100644
--- a/python/edu/learn-python/src/com/jetbrains/python/edu/projectView/StudyDirectoryNode.java
+++ b/python/edu/learn-python/src/com/jetbrains/python/edu/projectView/StudyDirectoryNode.java
@@ -1,8 +1,10 @@
package com.jetbrains.python.edu.projectView;
import com.intellij.ide.projectView.PresentationData;
+import com.intellij.ide.projectView.ProjectView;
import com.intellij.ide.projectView.ViewSettings;
import com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode;
+import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDirectory;
@@ -17,6 +19,7 @@ import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.*;
+import java.util.Set;
public class StudyDirectoryNode extends PsiDirectoryNode {
private final PsiDirectory myValue;
@@ -110,4 +113,56 @@ public class StudyDirectoryNode extends PsiDirectoryNode {
data.addText(additionalName, new SimpleTextAttributes(Font.PLAIN, color));
data.setIcon(icon);
}
+
+ @Override
+ public boolean canNavigate() {
+ return true;
+ }
+
+ @Override
+ public boolean canNavigateToSource() {
+ return true;
+ }
+
+ @Override
+ public void navigate(boolean requestFocus) {
+ if (myValue.getName().contains(Task.TASK_DIR)) {
+ TaskFile taskFile = null;
+ VirtualFile virtualFile = null;
+ for (PsiElement child : myValue.getChildren()) {
+ VirtualFile childFile = child.getContainingFile().getVirtualFile();
+ taskFile = StudyTaskManager.getInstance(myProject).getTaskFile(childFile);
+ if (taskFile != null) {
+ virtualFile = childFile;
+ break;
+ }
+ }
+ if (taskFile != null) {
+ VirtualFile taskDir = virtualFile.getParent();
+ Task task = taskFile.getTask();
+ for (VirtualFile openFile : FileEditorManager.getInstance(myProject).getOpenFiles()) {
+ FileEditorManager.getInstance(myProject).closeFile(openFile);
+ }
+ VirtualFile child = null;
+ Set<String> fileNames = task.getTaskFiles().keySet();
+ for (String name : fileNames) {
+ child = taskDir.findChild(name);
+ if (child != null) {
+ FileEditorManager.getInstance(myProject).openFile(child, true);
+ }
+ }
+ if (child != null) {
+ ProjectView.getInstance(myProject).select(child, child, false);
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean expandOnDoubleClick() {
+ if (myValue.getName().contains(Task.TASK_DIR)) {
+ return false;
+ }
+ return super.expandOnDoubleClick();
+ }
}
diff --git a/python/edu/learn-python/src/com/jetbrains/python/edu/ui/StudyToolWindowFactory.java b/python/edu/learn-python/src/com/jetbrains/python/edu/ui/StudyToolWindowFactory.java
index a553978c416a..0f8c5a53511a 100644
--- a/python/edu/learn-python/src/com/jetbrains/python/edu/ui/StudyToolWindowFactory.java
+++ b/python/edu/learn-python/src/com/jetbrains/python/edu/ui/StudyToolWindowFactory.java
@@ -9,6 +9,7 @@ import com.intellij.ui.content.Content;
import com.intellij.ui.content.ContentFactory;
import com.intellij.util.ui.UIUtil;
import com.jetbrains.python.edu.StudyTaskManager;
+import com.jetbrains.python.edu.actions.StudyReloadCourseAction;
import com.jetbrains.python.edu.course.Course;
import com.jetbrains.python.edu.course.Lesson;
import com.jetbrains.python.edu.course.LessonInfo;
@@ -17,6 +18,8 @@ import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
import java.util.List;
public class StudyToolWindowFactory implements ToolWindowFactory, DumbAware {
@@ -41,7 +44,15 @@ public class StudyToolWindowFactory implements ToolWindowFactory, DumbAware {
contentPanel.add(new JLabel(authorLabel));
contentPanel.add(Box.createRigidArea(new Dimension(0, 10)));
contentPanel.add(new JLabel(description));
+ contentPanel.add(Box.createRigidArea(new Dimension(0, 10)));
+ JButton reloadCourseButton = new JButton("reload course");
+ reloadCourseButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ StudyReloadCourseAction.reloadCourse(project);
+ }
+ });
+ contentPanel.add(reloadCourseButton);
int taskNum = 0;
int taskSolved = 0;
int lessonsCompleted = 0;
diff --git a/python/edu/resources/idea/PyCharmEduApplicationInfo.xml b/python/edu/resources/idea/PyCharmEduApplicationInfo.xml
index eed232dcd3c7..939c84129455 100644
--- a/python/edu/resources/idea/PyCharmEduApplicationInfo.xml
+++ b/python/edu/resources/idea/PyCharmEduApplicationInfo.xml
@@ -19,5 +19,5 @@
<feedback eap-url="http://www.jetbrains.com/feedback/feedback.jsp?product=PyCharm&amp;build=$BUILD&amp;timezone=$TIMEZONE&amp;eval=$EVAL"
release-url="http://www.jetbrains.com/feedback/feedback.jsp?product=PyCharm&amp;build=$BUILD&amp;timezone=$TIMEZONE&amp;eval=$EVAL"/>
- <help file="pycharm-eduhelp.jar" root="pycharm"/>
+ <help file="pycharm-eduhelp.jar" root="pycharm-edu"/>
</component>
diff --git a/python/helpers/packaging_tool.py b/python/helpers/packaging_tool.py
index 9101a16be1b3..c66cbcba2fe2 100644
--- a/python/helpers/packaging_tool.py
+++ b/python/helpers/packaging_tool.py
@@ -21,7 +21,7 @@ def exit(retcode):
def usage():
- sys.stderr.write('Usage: packaging_tool.py <list|search|install|uninstall|pyvenv>\n')
+ sys.stderr.write('Usage: packaging_tool.py <list|install|uninstall|pyvenv>\n')
sys.stderr.flush()
exit(ERROR_WRONG_USAGE)
@@ -58,13 +58,6 @@ def do_install(pkgs):
error_no_pip()
return pip.main(['install'] + pkgs)
-def do_search(pkgs):
- try:
- import pip
- except ImportError:
- error_no_pip()
- return pip.main(['search'] + pkgs)
-
def do_uninstall(pkgs):
try:
@@ -122,11 +115,6 @@ def main():
if len(sys.argv) != 2:
usage()
do_list()
- elif cmd == 'search':
- if len(sys.argv) < 2:
- usage()
- pkgs = sys.argv[2:]
- do_search(pkgs)
elif cmd == 'install':
if len(sys.argv) < 2:
usage()
diff --git a/python/helpers/pycharm/_bdd_utils.py b/python/helpers/pycharm/_bdd_utils.py
index eea1bebf1654..65d0f93102b9 100644
--- a/python/helpers/pycharm/_bdd_utils.py
+++ b/python/helpers/pycharm/_bdd_utils.py
@@ -3,7 +3,7 @@
Tools for running BDD frameworks in python.
You probably need to extend BddRunner (see its doc).
-You may also need "get_path_by_args" that gets folder (current or passed as first argument)
+You may also need "get_what_to_run_by_env" that gets folder (current or passed as first argument)
"""
import os
import time
@@ -29,20 +29,33 @@ def fix_win_drive(feature_path):
os.chdir(feature_disk)
-def get_path_by_args(arguments):
+def get_what_to_run_by_env(environment):
"""
- :type arguments list
- :param arguments: arguments (sys.argv)
- :return: tuple (base_dir, what_to_run) where dir is current or first argument from argv, checking it exists
- :rtype tuple of str
+ :type environment dict
+ :param environment: os.environment (files and folders should be separated with | and passed to PY_STUFF_TO_RUN).
+ Scenarios optionally could be passed as SCENARIOS (names or order numbers, depends on runner)
+ :return: tuple (base_dir, scenarios[], what_to_run(list of feature files or folders))) where dir is current or first argument from env, checking it exists
+ :rtype tuple of (str, iterable)
"""
- what_to_run = arguments[1] if len(arguments) > 1 else "."
- base_dir = what_to_run
- assert os.path.exists(what_to_run), "{} does not exist".format(what_to_run)
+ if "PY_STUFF_TO_RUN" not in environment:
+ what_to_run = ["."]
+ else:
+ what_to_run = str(environment["PY_STUFF_TO_RUN"]).split("|")
- if os.path.isfile(what_to_run):
- base_dir = os.path.dirname(what_to_run) # User may point to the file directly
- return base_dir, what_to_run
+ scenarios = []
+ if "SCENARIOS" in environment:
+ scenarios = str(environment["SCENARIOS"]).split("|")
+
+ if not what_to_run:
+ what_to_run = ["."]
+
+ for path in what_to_run:
+ assert os.path.exists(path), "{} does not exist".format(path)
+
+ base_dir = what_to_run[0]
+ if os.path.isfile(what_to_run[0]):
+ base_dir = os.path.dirname(what_to_run[0]) # User may point to the file directly
+ return base_dir, scenarios, what_to_run
class BddRunner(object):
diff --git a/python/helpers/pycharm/behave_runner.py b/python/helpers/pycharm/behave_runner.py
index 2ec649ea7c1d..99acfdb9ffeb 100644
--- a/python/helpers/pycharm/behave_runner.py
+++ b/python/helpers/pycharm/behave_runner.py
@@ -1,13 +1,14 @@
# coding=utf-8
"""
Behave BDD runner.
-*FIRST* param now: folder to search "features" for.
-Each "features" folder should have features and "steps" subdir.
+See _bdd_utils#get_path_by_env for information how to pass list of features here.
+Each feature could be file, folder with feature files or folder with "features" subfolder
Other args are tag expressionsin format (--tags=.. --tags=..).
See https://pythonhosted.org/behave/behave.html#tag-expression
"""
import functools
+import glob
import sys
import os
import traceback
@@ -15,6 +16,7 @@ import traceback
from behave.formatter.base import Formatter
from behave.model import Step, ScenarioOutline, Feature, Scenario
from behave.tag_expression import TagExpression
+import re
import _bdd_utils
@@ -185,16 +187,19 @@ class _BehaveRunner(_bdd_utils.BddRunner):
self.__real_runner.run()
- def __filter_scenarios_by_tag(self, scenario):
+ def __filter_scenarios_by_args(self, scenario):
"""
- Filters out scenarios that should be skipped by tags
+ Filters out scenarios that should be skipped by tags or scenario names
:param scenario scenario to check
:return true if should pass
"""
assert isinstance(scenario, Scenario), scenario
expected_tags = self.__config.tags
+ scenario_name_re = self.__config.name_re
+ if scenario_name_re and not scenario_name_re.match(scenario.name):
+ return False
if not expected_tags:
- return True # No tags are required
+ return True # No tags nor names are required
return isinstance(expected_tags, TagExpression) and expected_tags.check(scenario.tags)
@@ -213,7 +218,7 @@ class _BehaveRunner(_bdd_utils.BddRunner):
scenarios.extend(scenario.scenarios)
else:
scenarios.append(scenario)
- feature.scenarios = filter(self.__filter_scenarios_by_tag, scenarios)
+ feature.scenarios = filter(self.__filter_scenarios_by_args, scenarios)
return features_to_run
@@ -230,18 +235,27 @@ if __name__ == "__main__":
command_args = list(filter(None, sys.argv[1:]))
if command_args:
_bdd_utils.fix_win_drive(command_args[0])
+ (base_dir, scenario_names, what_to_run) = _bdd_utils.get_what_to_run_by_env(os.environ)
+
+ for scenario_name in scenario_names:
+ command_args += ["-n", re.escape(scenario_name)] # TODO : rewite pythonic
+
my_config = configuration.Configuration(command_args=command_args)
formatters.register_as(_Null, "com.intellij.python.null")
my_config.format = ["com.intellij.python.null"] # To prevent output to stdout
my_config.reporters = [] # To prevent summary to stdout
my_config.stdout_capture = False # For test output
my_config.stderr_capture = False # For test output
- (base_dir, what_to_run) = _bdd_utils.get_path_by_args(sys.argv)
- if not my_config.paths: # No path provided, trying to load dit manually
- if os.path.isfile(what_to_run): # File is provided, load it
- my_config.paths = [what_to_run]
- else: # Dir is provided, find subdirs ro run
- my_config.paths = _get_dirs_to_run(base_dir)
+ features = set()
+ for feature in what_to_run:
+ if os.path.isfile(feature) or glob.glob(
+ os.path.join(feature, "*.feature")): # File of folder with "features" provided, load it
+ features.add(feature)
+ elif os.path.isdir(feature):
+ features |= set(_get_dirs_to_run(feature)) # Find "features" subfolder
+ my_config.paths = list(features)
+ if what_to_run and not my_config.paths:
+ raise Exception("Nothing to run in {}".format(what_to_run))
_BehaveRunner(my_config, base_dir).run()
diff --git a/python/helpers/pycharm/lettuce_runner.py b/python/helpers/pycharm/lettuce_runner.py
index f0a4b5dbb873..2f64afc956d9 100644
--- a/python/helpers/pycharm/lettuce_runner.py
+++ b/python/helpers/pycharm/lettuce_runner.py
@@ -2,13 +2,14 @@
"""
BDD lettuce framework runner
TODO: Support other params (like tags) as well.
-Supports only 1 param now: folder to search "features" for.
+Supports only 2 params now: folder to search "features" for or file and "-s scenario_index"
"""
+import argparse
+import os
import _bdd_utils
__author__ = 'Ilya.Kazakevich'
from lettuce.exceptions import ReasonToFail
-import sys
import lettuce
from lettuce import core
@@ -18,31 +19,43 @@ class _LettuceRunner(_bdd_utils.BddRunner):
Lettuce runner (BddRunner for lettuce)
"""
- def __init__(self, base_dir, what_to_run):
+ def __init__(self, base_dir, what_to_run, scenarios):
"""
+ :param scenarios scenario numbers to run
+ :type scenarios list
:param base_dir base directory to run tests in
:type base_dir: str
:param what_to_run folder or file to run
:type what_to_run str
+
"""
super(_LettuceRunner, self).__init__(base_dir)
- self.__runner = lettuce.Runner(what_to_run)
+ self.__runner = lettuce.Runner(what_to_run, ",".join(scenarios))
def _get_features_to_run(self):
super(_LettuceRunner, self)._get_features_to_run()
- if self.__runner.single_feature: # We need to run one and only one feature
- return [core.Feature.from_file(self.__runner.single_feature)]
-
- # Find all features in dir
features = []
- for feature_file in self.__runner.loader.find_feature_files():
- feature = core.Feature.from_file(feature_file)
- assert isinstance(feature, core.Feature), feature
- # TODO: cut out due to https://github.com/gabrielfalcao/lettuce/issues/451 Fix when this issue fixed
- feature.scenarios = filter(lambda s: not s.outlines, feature.scenarios)
- if feature.scenarios:
- features.append(feature)
+ if self.__runner.single_feature: # We need to run one and only one feature
+ features = [core.Feature.from_file(self.__runner.single_feature)]
+ else:
+ # Find all features in dir
+ for feature_file in self.__runner.loader.find_feature_files():
+ feature = core.Feature.from_file(feature_file)
+ assert isinstance(feature, core.Feature), feature
+ # TODO: cut out due to https://github.com/gabrielfalcao/lettuce/issues/451 Fix when this issue fixed
+ feature.scenarios = filter(lambda s: not s.outlines, feature.scenarios)
+ if feature.scenarios:
+ features.append(feature)
+
+ # Choose only selected scenarios
+ if self.__runner.scenarios:
+ for feature in features:
+ filtered_feature_scenarios = []
+ for index in [i - 1 for i in self.__runner.scenarios]: # decrease index by 1
+ if index < len(feature.scenarios):
+ filtered_feature_scenarios.append(feature.scenarios[index])
+ feature.scenarios = filtered_feature_scenarios
return features
def _run_tests(self):
@@ -108,6 +121,8 @@ class _LettuceRunner(_bdd_utils.BddRunner):
if __name__ == "__main__":
- (base_dir, what_to_run) = _bdd_utils.get_path_by_args(sys.argv)
- _bdd_utils.fix_win_drive(what_to_run)
- _LettuceRunner(base_dir, what_to_run).run() \ No newline at end of file
+ (base_dir, scenarios, what_to_run) = _bdd_utils.get_what_to_run_by_env(os.environ)
+ if len(what_to_run) > 1:
+ raise Exception("Lettuce can't run more than one file now")
+ _bdd_utils.fix_win_drive(what_to_run[0])
+ _LettuceRunner(base_dir, what_to_run[0], scenarios).run() \ No newline at end of file
diff --git a/python/helpers/pycharm_generator_utils/clr_tools.py b/python/helpers/pycharm_generator_utils/clr_tools.py
index 4c273ae7d4d5..f4c3cfbf90f0 100644
--- a/python/helpers/pycharm_generator_utils/clr_tools.py
+++ b/python/helpers/pycharm_generator_utils/clr_tools.py
@@ -18,10 +18,14 @@ def get_namespace_by_name(object_name):
first_part = parts[0]
remain_part = parts[2]
- while remain_part and type(_get_attr_by_name(imported_object, remain_part)) is type: # While we are in class
+ while remain_part and type(_get_attr_by_name(imported_object, remain_part)) is type: # While we are in class
remain_part = remain_part.rpartition(".")[0]
- return first_part + "." + remain_part if remain_part else first_part
+ if remain_part:
+ return first_part + "." + remain_part
+ else:
+ return first_part
+
def _import_first(object_name):
"""
@@ -33,13 +37,12 @@ def _import_first(object_name):
"""
while object_name:
try:
- return (__import__(object_name), object_name)
+ return (__import__(object_name, globals=[], locals=[], fromlist=[]), object_name)
except ImportError:
- object_name = object_name.rpartition(".")[0] # Remove rightest part
+ object_name = object_name.rpartition(".")[0] # Remove rightest part
raise Exception("No module name found in name " + object_name)
-
def _get_attr_by_name(obj, name):
"""
Accepts chain of attributes in dot notation like "some.property.name" and gets them on object
diff --git a/python/helpers/pydev/django_debug.py b/python/helpers/pydev/django_debug.py
deleted file mode 100644
index 2b17864db47e..000000000000
--- a/python/helpers/pydev/django_debug.py
+++ /dev/null
@@ -1,124 +0,0 @@
-import inspect
-from django_frame import DjangoTemplateFrame
-from pydevd_comm import CMD_SET_BREAK
-from pydevd_constants import DJANGO_SUSPEND, GetThreadId, DictContains
-from pydevd_file_utils import NormFileToServer
-from pydevd_breakpoints import LineBreakpoint
-import pydevd_vars
-import traceback
-
-class DjangoLineBreakpoint(LineBreakpoint):
-
- def __init__(self, file, line, condition, func_name, expression):
- self.file = file
- LineBreakpoint.__init__(self, line, condition, func_name, expression)
-
- def is_triggered(self, template_frame_file, template_frame_line):
- return self.file == template_frame_file and self.line == template_frame_line
-
- def __str__(self):
- return "DjangoLineBreakpoint: %s-%d" %(self.file, self.line)
-
-
-def inherits(cls, *names):
- if cls.__name__ in names:
- return True
- inherits_node = False
- for base in inspect.getmro(cls):
- if base.__name__ in names:
- inherits_node = True
- break
- return inherits_node
-
-
-def is_django_render_call(frame):
- try:
- name = frame.f_code.co_name
- if name != 'render':
- return False
-
- if not DictContains(frame.f_locals, 'self'):
- return False
-
- cls = frame.f_locals['self'].__class__
-
- inherits_node = inherits(cls, 'Node')
-
- if not inherits_node:
- return False
-
- clsname = cls.__name__
- return clsname != 'TextNode' and clsname != 'NodeList'
- except:
- traceback.print_exc()
- return False
-
-
-def is_django_context_get_call(frame):
- try:
- if not DictContains(frame.f_locals, 'self'):
- return False
-
- cls = frame.f_locals['self'].__class__
-
- return inherits(cls, 'BaseContext')
- except:
- traceback.print_exc()
- return False
-
-
-def is_django_resolve_call(frame):
- try:
- name = frame.f_code.co_name
- if name != '_resolve_lookup':
- return False
-
- if not DictContains(frame.f_locals, 'self'):
- return False
-
- cls = frame.f_locals['self'].__class__
-
- clsname = cls.__name__
- return clsname == 'Variable'
- except:
- traceback.print_exc()
- return False
-
-
-def is_django_suspended(thread):
- return thread.additionalInfo.suspend_type == DJANGO_SUSPEND
-
-
-def suspend_django(py_db_frame, mainDebugger, thread, frame, cmd=CMD_SET_BREAK):
- frame = DjangoTemplateFrame(frame)
-
- if frame.f_lineno is None:
- return None
-
- #try:
- # if thread.additionalInfo.filename == frame.f_code.co_filename and thread.additionalInfo.line == frame.f_lineno:
- # return None # don't stay twice on the same line
- #except AttributeError:
- # pass
-
- pydevd_vars.addAdditionalFrameById(GetThreadId(thread), {id(frame): frame})
-
- py_db_frame.setSuspend(thread, cmd)
- thread.additionalInfo.suspend_type = DJANGO_SUSPEND
-
- thread.additionalInfo.filename = frame.f_code.co_filename
- thread.additionalInfo.line = frame.f_lineno
-
- return frame
-
-
-def find_django_render_frame(frame):
- while frame is not None and not is_django_render_call(frame):
- frame = frame.f_back
-
- return frame
-
-
-
-
-
diff --git a/python/helpers/pydev/django_frame.py b/python/helpers/pydev/django_frame.py
deleted file mode 100644
index 4181572aed3c..000000000000
--- a/python/helpers/pydev/django_frame.py
+++ /dev/null
@@ -1,132 +0,0 @@
-from pydevd_file_utils import GetFileNameAndBaseFromFile
-import pydev_log
-import traceback
-from pydevd_constants import DictContains
-
-def read_file(filename):
- f = open(filename, "r")
- try:
- s = f.read()
- finally:
- f.close()
- return s
-
-
-def offset_to_line_number(text, offset):
- curLine = 1
- curOffset = 0
- while curOffset < offset:
- if curOffset == len(text):
- return -1
- c = text[curOffset]
- if c == '\n':
- curLine += 1
- elif c == '\r':
- curLine += 1
- if curOffset < len(text) and text[curOffset + 1] == '\n':
- curOffset += 1
-
- curOffset += 1
-
- return curLine
-
-
-def get_source(frame):
- try:
- node = frame.f_locals['self']
- if hasattr(node, 'source'):
- return node.source
- else:
- pydev_log.error_once(
- "WARNING: Template path is not available. Please set TEMPLATE_DEBUG=True "
- "in your settings.py to make django template breakpoints working")
- return None
-
- except:
- pydev_log.debug(traceback.format_exc())
- return None
-
-
-def get_template_file_name(frame):
- try:
- source = get_source(frame)
- if source is None:
- pydev_log.debug("Source is None\n")
- return None
- fname = source[0].name
-
- if fname == '<unknown source>':
- pydev_log.debug("Source name is %s\n" % fname)
- return None
- else:
- filename, base = GetFileNameAndBaseFromFile(fname)
- return filename
- except:
- pydev_log.debug(traceback.format_exc())
- return None
-
-
-def get_template_line(frame, template_frame_file):
- source = get_source(frame)
- try:
- return offset_to_line_number(read_file(template_frame_file), source[1][0])
- except:
- return None
-
-
-class DjangoTemplateFrame:
- def __init__(
- self,
- frame,
- template_frame_file=None,
- template_frame_line=None):
-
- if template_frame_file is None:
- template_frame_file = get_template_file_name(frame)
-
- self.back_context = frame.f_locals['context']
- self.f_code = FCode('Django Template', template_frame_file)
-
- if template_frame_line is None:
- template_frame_line = get_template_line(frame, template_frame_file)
- self.f_lineno = template_frame_line
-
- self.f_back = frame
- self.f_globals = {}
- self.f_locals = self.collect_context()
- self.f_trace = None
-
- def collect_context(self):
- res = {}
- try:
- for d in self.back_context.dicts:
- res.update(d)
- except AttributeError:
- pass
- return res
-
- def changeVariable(self, name, value):
- for d in self.back_context.dicts:
- if DictContains(d, name):
- d[name] = value
- self.f_locals[name] = value
-
-
-class FCode:
- def __init__(self, name, filename):
- self.co_name = name
- self.co_filename = filename
-
-
-def is_django_exception_break_context(frame):
- try:
- return frame.f_code.co_name in ['_resolve_lookup', 'find_template']
- except:
- return False
-
-
-def just_raised(trace):
- if trace is None:
- return False
- return trace.tb_next is None
-
diff --git a/python/helpers/pydev/pydev_log.py b/python/helpers/pydev/pydev_log.py
index 229784b76a91..b5e65b3102e6 100644
--- a/python/helpers/pydev/pydev_log.py
+++ b/python/helpers/pydev/pydev_log.py
@@ -2,6 +2,8 @@ import sys
from pydevd_constants import DebugInfoHolder
from pydevd_constants import DictContains
+import traceback
+
WARN_ONCE_MAP = {}
def stderr_write(message):
@@ -18,11 +20,16 @@ def warn(message):
if DebugInfoHolder.DEBUG_TRACE_LEVEL>1:
stderr_write(message)
+
def info(message):
stderr_write(message)
-def error(message):
+
+def error(message, tb=False):
stderr_write(message)
+ if tb:
+ traceback.print_exc()
+
def error_once(message):
if not DictContains(WARN_ONCE_MAP, message):
diff --git a/python/helpers/pydev/pydev_monkey_qt.py b/python/helpers/pydev/pydev_monkey_qt.py
index 9c62686173dd..2675e9e55708 100644
--- a/python/helpers/pydev/pydev_monkey_qt.py
+++ b/python/helpers/pydev/pydev_monkey_qt.py
@@ -11,7 +11,7 @@ def set_trace_in_qt():
_patched_qt = False
def patch_qt():
'''
- This method patches qt (PySide or PyQt4) so that we have hooks to set the tracing for QThread.
+ This method patches qt (PySide, PyQt4, PyQt5) so that we have hooks to set the tracing for QThread.
'''
# Avoid patching more than once
@@ -27,7 +27,10 @@ def patch_qt():
try:
from PyQt4 import QtCore
except:
- return
+ try:
+ from PyQt5 import QtCore
+ except:
+ return
_original_thread_init = QtCore.QThread.__init__
_original_runnable_init = QtCore.QRunnable.__init__
diff --git a/python/helpers/pydev/pydev_run_in_console.py b/python/helpers/pydev/pydev_run_in_console.py
index 1b8e1d230175..731ead67115e 100644
--- a/python/helpers/pydev/pydev_run_in_console.py
+++ b/python/helpers/pydev/pydev_run_in_console.py
@@ -2,6 +2,7 @@
from pydevconsole import *
import pydev_imports
+from pydevd_utils import save_main_module
def run_file(file, globals=None, locals=None):
@@ -11,22 +12,8 @@ def run_file(file, globals=None, locals=None):
file = new_target
if globals is None:
- # patch provided by: Scott Schlesier - when script is run, it does not
- # use globals from pydevd:
- # This will prevent the pydevd script from contaminating the namespace for the script to be debugged
-
- # pretend pydevd is not the main module, and
- # convince the file to be debugged that it was loaded as main
- sys.modules['pydevd'] = sys.modules['__main__']
- sys.modules['pydevd'].__name__ = 'pydevd'
-
- from imp import new_module
- m = new_module('__main__')
- sys.modules['__main__'] = m
- if hasattr(sys.modules['pydevd'], '__loader__'):
- setattr(m, '__loader__', getattr(sys.modules['pydevd'], '__loader__'))
-
- m.__file__ = file
+ m = save_main_module(file, 'pydev_run_in_console')
+
globals = m.__dict__
try:
globals['__builtins__'] = __builtins__
diff --git a/python/helpers/pydev/pydevconsole.py b/python/helpers/pydev/pydevconsole.py
index 8d4375f5a5aa..444aa2d1c48b 100644
--- a/python/helpers/pydev/pydevconsole.py
+++ b/python/helpers/pydev/pydevconsole.py
@@ -80,10 +80,18 @@ try:
from pydev_imports import execfile
__builtin__.execfile = execfile
-
except:
pass
+# Pull in runfile, the interface to UMD that wraps execfile
+from pydev_umd import runfile, _set_globals_function
+try:
+ import builtins
+ builtins.runfile = runfile
+except:
+ import __builtin__
+ __builtin__.runfile = runfile
+
#=======================================================================================================================
# InterpreterInterface
@@ -264,6 +272,9 @@ def start_server(host, port, interpreter):
sys.stderr.write('Error starting server with host: %s, port: %s, client_port: %s\n' % (host, port, client_port))
raise
+ # Tell UMD the proper default namespace
+ _set_globals_function(interpreter.getNamespace)
+
server.register_function(interpreter.execLine)
server.register_function(interpreter.execMultipleLines)
server.register_function(interpreter.getCompletions)
diff --git a/python/helpers/pydev/pydevd.py b/python/helpers/pydev/pydevd.py
index 9d0da096c07d..8d68cea9876c 100644
--- a/python/helpers/pydev/pydevd.py
+++ b/python/helpers/pydev/pydevd.py
@@ -3,12 +3,15 @@ from __future__ import nested_scopes # Jython 2.1 support
from pydevd_constants import * # @UnusedWildImport
import pydev_monkey_qt
+from pydevd_utils import save_main_module
+
pydev_monkey_qt.patch_qt()
import traceback
-from django_debug import DjangoLineBreakpoint
-from pydevd_frame import add_exception_to_frame
+from pydevd_plugin_utils import PluginManager
+
+from pydevd_frame_utils import add_exception_to_frame
import pydev_imports
from pydevd_breakpoints import * #@UnusedWildImport
import fix_getpass
@@ -110,13 +113,18 @@ DONT_TRACE = {
'linecache.py':1,
'threading.py':1,
+ # thirs party libs that we don't want to trace
+ 'pluginbase.py':1,
+ 'pkgutil_old.py':1,
+ 'uuid_old.py':1,
+
#things from pydev that we don't want to trace
'_pydev_execfile.py':1,
'_pydev_jython_execfile.py':1,
'_pydev_threading':1,
'_pydev_Queue':1,
'django_debug.py':1,
- 'django_frame.py':1,
+ 'jinja2_debug.py':1,
'pydev_log.py':1,
'pydev_monkey.py':1 ,
'pydevd.py':1 ,
@@ -301,17 +309,15 @@ class PyDB:
self._cmd_queue = {} # the hash of Queues. Key is thread id, value is thread
self.breakpoints = {}
- self.django_breakpoints = {}
self.file_to_id_to_line_breakpoint = {}
- self.file_to_id_to_django_breakpoint = {}
+ self.file_to_id_to_plugin_breakpoint = {}
# Note: breakpoints dict should not be mutated: a copy should be created
# and later it should be assigned back (to prevent concurrency issues).
self.break_on_uncaught_exceptions = {}
self.break_on_caught_exceptions = {}
- self.django_exception_break = {}
self.readyToRun = False
self._main_lock = _pydev_thread.allocate_lock()
self._lock_running_thread_ids = _pydev_thread.allocate_lock()
@@ -344,6 +350,8 @@ class PyDB:
# This attribute holds the file-> lines which have an @IgnoreException.
self.filename_to_lines_where_exceptions_are_ignored = {}
+ #working with plugins
+ self.plugin = PluginManager(self)
def haveAliveThreads(self):
for t in threadingEnumerate():
@@ -568,12 +576,16 @@ class PyDB:
notify_on_terminate,
notify_on_first_raise_only,
):
- eb = ExceptionBreakpoint(
- exception,
- notify_always,
- notify_on_terminate,
- notify_on_first_raise_only,
- )
+ try:
+ eb = ExceptionBreakpoint(
+ exception,
+ notify_always,
+ notify_on_terminate,
+ notify_on_first_raise_only,
+ )
+ except ImportError:
+ pydev_log.error("Error unable to add break on exception for: %s (exception could not be imported)\n" % (exception,))
+ return None
if eb.notify_on_terminate:
cp = self.break_on_uncaught_exceptions.copy()
@@ -839,15 +851,22 @@ class PyDB:
if len(expression) <= 0 or expression is None or expression == "None":
expression = None
+ supported_type = False
if type == 'python-line':
breakpoint = LineBreakpoint(line, condition, func_name, expression)
breakpoints = self.breakpoints
file_to_id_to_breakpoint = self.file_to_id_to_line_breakpoint
- elif type == 'django-line':
- breakpoint = DjangoLineBreakpoint(file, line, condition, func_name, expression)
- breakpoints = self.django_breakpoints
- file_to_id_to_breakpoint = self.file_to_id_to_django_breakpoint
+ supported_type = True
else:
+ result = self.plugin.add_breakpoint('add_line_breakpoint', self, type, file, line, condition, expression, func_name)
+ if result is not None:
+ supported_type = True
+ breakpoint, breakpoints = result
+ file_to_id_to_breakpoint = self.file_to_id_to_plugin_breakpoint
+ else:
+ supported_type = False
+
+ if not supported_type:
raise NameError(type)
if DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS > 0:
@@ -880,27 +899,31 @@ class PyDB:
pydev_log.error('Error removing breakpoint. Expected breakpoint_id to be an int. Found: %s' % (breakpoint_id,))
else:
+ file_to_id_to_breakpoint = None
if breakpoint_type == 'python-line':
breakpoints = self.breakpoints
file_to_id_to_breakpoint = self.file_to_id_to_line_breakpoint
- elif breakpoint_type == 'django-line':
- breakpoints = self.django_breakpoints
- file_to_id_to_breakpoint = self.file_to_id_to_django_breakpoint
else:
- raise NameError(breakpoint_type)
+ result = self.plugin.get_breakpoints(self, breakpoint_type)
+ if result is not None:
+ file_to_id_to_breakpoint = self.file_to_id_to_plugin_breakpoint
+ breakpoints = result
- try:
- id_to_pybreakpoint = file_to_id_to_breakpoint.get(file, {})
- if DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS > 0:
- existing = id_to_pybreakpoint[breakpoint_id]
- sys.stderr.write('Removed breakpoint:%s - line:%s - func_name:%s (id: %s)\n' % (
- file, existing.line, existing.func_name.encode('utf-8'), breakpoint_id))
+ if file_to_id_to_breakpoint is None:
+ pydev_log.error('Error removing breakpoint. Cant handle breakpoint of type %s' % breakpoint_type)
+ else:
+ try:
+ id_to_pybreakpoint = file_to_id_to_breakpoint.get(file, {})
+ if DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS > 0:
+ existing = id_to_pybreakpoint[breakpoint_id]
+ sys.stderr.write('Removed breakpoint:%s - line:%s - func_name:%s (id: %s)\n' % (
+ file, existing.line, existing.func_name.encode('utf-8'), breakpoint_id))
- del id_to_pybreakpoint[breakpoint_id]
- self.consolidate_breakpoints(file, id_to_pybreakpoint, breakpoints)
- except KeyError:
- pydev_log.error("Error removing breakpoint: Breakpoint id not found: %s id: %s. Available ids: %s\n" % (
- file, breakpoint_id, DictKeys(id_to_pybreakpoint)))
+ del id_to_pybreakpoint[breakpoint_id]
+ self.consolidate_breakpoints(file, id_to_pybreakpoint, breakpoints)
+ except KeyError:
+ pydev_log.error("Error removing breakpoint: Breakpoint id not found: %s id: %s. Available ids: %s\n" % (
+ file, breakpoint_id, DictKeys(id_to_pybreakpoint)))
elif cmd_id == CMD_EVALUATE_EXPRESSION or cmd_id == CMD_EXEC_EXPRESSION:
@@ -963,6 +986,8 @@ class PyDB:
notify_on_terminate=break_on_uncaught,
notify_on_first_raise_only=False,
)
+ if exception_breakpoint is None:
+ continue
added.append(exception_breakpoint)
self.update_after_exceptions_added(added)
@@ -1013,28 +1038,58 @@ class PyDB:
pass
elif cmd_id == CMD_ADD_EXCEPTION_BREAK:
- exception, notify_always, notify_on_terminate = text.split('\t', 2)
- exception_breakpoint = self.add_break_on_exception(
- exception,
- notify_always=int(notify_always) > 0,
- notify_on_terminate = int(notify_on_terminate) == 1,
- notify_on_first_raise_only=int(notify_always) == 2
- )
- self.update_after_exceptions_added([exception_breakpoint])
+ if text.find('\t') != -1:
+ exception, notify_always, notify_on_terminate = text.split('\t', 2)
+ else:
+ exception, notify_always, notify_on_terminate = text, 0, 0
+
+ if exception.find('-') != -1:
+ type, exception = exception.split('-')
+ else:
+ type = 'python'
+
+ if type == 'python':
+ exception_breakpoint = self.add_break_on_exception(
+ exception,
+ notify_always=int(notify_always) > 0,
+ notify_on_terminate = int(notify_on_terminate) == 1,
+ notify_on_first_raise_only=int(notify_always) == 2
+ )
+
+ if exception_breakpoint is not None:
+ self.update_after_exceptions_added([exception_breakpoint])
+ else:
+ supported_type = self.plugin.add_breakpoint('add_exception_breakpoint', self, type, exception)
+
+ if not supported_type:
+ raise NameError(type)
+
+
elif cmd_id == CMD_REMOVE_EXCEPTION_BREAK:
exception = text
- try:
- cp = self.break_on_uncaught_exceptions.copy()
- DictPop(cp, exception, None)
- self.break_on_uncaught_exceptions = cp
+ if exception.find('-') != -1:
+ type, exception = exception.split('-')
+ else:
+ type = 'python'
- cp = self.break_on_caught_exceptions.copy()
- DictPop(cp, exception, None)
- self.break_on_caught_exceptions = cp
- except:
- pydev_log.debug("Error while removing exception %s"%sys.exc_info()[0]);
- update_exception_hook(self)
+ if type == 'python':
+ try:
+ cp = self.break_on_uncaught_exceptions.copy()
+ DictPop(cp, exception, None)
+ self.break_on_uncaught_exceptions = cp
+
+ cp = self.break_on_caught_exceptions.copy()
+ DictPop(cp, exception, None)
+ self.break_on_caught_exceptions = cp
+ except:
+ pydev_log.debug("Error while removing exception %s"%sys.exc_info()[0])
+ update_exception_hook(self)
+ else:
+ supported_type = self.plugin.remove_exception_breakpoint(self, type, exception)
+
+ if not supported_type:
+ raise NameError(type)
elif cmd_id == CMD_LOAD_SOURCE:
path = text
@@ -1048,16 +1103,13 @@ class PyDB:
elif cmd_id == CMD_ADD_DJANGO_EXCEPTION_BREAK:
exception = text
- self.django_exception_break[exception] = True
- self.setTracingForUntracedContexts()
+ self.plugin.add_breakpoint('add_exception_breakpoint', self, 'django', exception)
+
elif cmd_id == CMD_REMOVE_DJANGO_EXCEPTION_BREAK:
exception = text
- try:
- del self.django_exception_break[exception]
- except :
- pass
+ self.plugin.remove_exception_breakpoint(self, 'django', exception)
elif cmd_id == CMD_EVALUATE_CONSOLE_EXPRESSION:
# Command which takes care for the debug console communication
@@ -1492,22 +1544,7 @@ class PyDB:
file = new_target
if globals is None:
- # patch provided by: Scott Schlesier - when script is run, it does not
- # use globals from pydevd:
- # This will prevent the pydevd script from contaminating the namespace for the script to be debugged
-
- # pretend pydevd is not the main module, and
- # convince the file to be debugged that it was loaded as main
- sys.modules['pydevd'] = sys.modules['__main__']
- sys.modules['pydevd'].__name__ = 'pydevd'
-
- from imp import new_module
- m = new_module('__main__')
- sys.modules['__main__'] = m
- if hasattr(sys.modules['pydevd'], '__loader__'):
- setattr(m, '__loader__', getattr(sys.modules['pydevd'], '__loader__'))
-
- m.__file__ = file
+ m = save_main_module(file, 'pydevd')
globals = m.__dict__
try:
globals['__builtins__'] = __builtins__
@@ -1546,8 +1583,6 @@ class PyDB:
pydev_imports.execfile(file, globals, locals) # execute the script
- return globals
-
def exiting(self):
sys.stdout.flush()
sys.stderr.flush()
@@ -2061,10 +2096,6 @@ if __name__ == '__main__':
debugger = PyDB()
- if setup['cmd-line']:
- debugger.cmd_line = True
-
-
if fix_app_engine_debug:
sys.stderr.write("pydev debugger: google app engine integration enabled\n")
curr_dir = os.path.dirname(__file__)
diff --git a/python/helpers/pydev/pydevd_breakpoints.py b/python/helpers/pydev/pydevd_breakpoints.py
index 1171157257e9..693823917a2f 100644
--- a/python/helpers/pydev/pydevd_breakpoints.py
+++ b/python/helpers/pydev/pydevd_breakpoints.py
@@ -40,8 +40,8 @@ class ExceptionBreakpoint:
def __str__(self):
return self.qname
-class LineBreakpoint:
+class LineBreakpoint(object):
def __init__(self, line, condition, func_name, expression):
self.line = line
self.condition = condition
diff --git a/python/helpers/pydev/pydevd_constants.py b/python/helpers/pydev/pydevd_constants.py
index e878d3b48ead..5e7a7a926bfb 100644
--- a/python/helpers/pydev/pydevd_constants.py
+++ b/python/helpers/pydev/pydevd_constants.py
@@ -5,7 +5,6 @@ STATE_RUN = 1
STATE_SUSPEND = 2
PYTHON_SUSPEND = 1
-DJANGO_SUSPEND = 2
try:
__setFalse = False
diff --git a/python/helpers/pydev/pydevd_frame.py b/python/helpers/pydev/pydevd_frame.py
index 5d1e78458391..922133ba1512 100644
--- a/python/helpers/pydev/pydevd_frame.py
+++ b/python/helpers/pydev/pydevd_frame.py
@@ -3,18 +3,15 @@ import os.path
import re
import traceback # @Reimport
-from django_debug import find_django_render_frame
-from django_debug import is_django_render_call, is_django_suspended, suspend_django, is_django_resolve_call, is_django_context_get_call
-from django_frame import DjangoTemplateFrame
-from django_frame import is_django_exception_break_context
-from django_frame import just_raised, get_template_file_name, get_template_line
import pydev_log
from pydevd_breakpoints import get_exception_breakpoint, get_exception_name
-from pydevd_comm import CMD_ADD_DJANGO_EXCEPTION_BREAK, \
- CMD_STEP_CAUGHT_EXCEPTION, CMD_STEP_RETURN, CMD_STEP_OVER, CMD_SET_BREAK, \
+from pydevd_comm import CMD_STEP_CAUGHT_EXCEPTION, CMD_STEP_RETURN, CMD_STEP_OVER, CMD_SET_BREAK, \
CMD_STEP_INTO, CMD_SMART_STEP_INTO, CMD_RUN_TO_LINE, CMD_SET_NEXT_STATEMENT
from pydevd_constants import * # @UnusedWildImport
from pydevd_file_utils import GetFilenameAndBase
+
+from pydevd_frame_utils import add_exception_to_frame, just_raised
+
try:
from pydevd_signature import sendSignatureCallTrace
except ImportError:
@@ -55,17 +52,6 @@ class PyDBFrame:
def doWaitSuspend(self, *args, **kwargs):
self._args[0].doWaitSuspend(*args, **kwargs)
- def _is_django_render_call(self, frame):
- try:
- return self._cached_is_django_render_call
- except:
- # Calculate lazily: note that a PyDBFrame always deals with the same
- # frame over and over, so, we can cache this.
- # -- although we can't cache things which change over time (such as
- # the breakpoints for the file).
- ret = self._cached_is_django_render_call = is_django_render_call(frame)
- return ret
-
def trace_exception(self, frame, event, arg):
if event == 'exception':
flag, frame = self.should_stop_on_exception(frame, event, arg)
@@ -97,22 +83,11 @@ class PyDBFrame:
flag = False
else:
try:
- if mainDebugger.django_exception_break and get_exception_name(exception) in [
- 'VariableDoesNotExist', 'TemplateDoesNotExist', 'TemplateSyntaxError'] \
- and just_raised(trace) and is_django_exception_break_context(frame):
-
- render_frame = find_django_render_frame(frame)
- if render_frame:
- suspend_frame = suspend_django(
- self, mainDebugger, thread, render_frame, CMD_ADD_DJANGO_EXCEPTION_BREAK)
-
- if suspend_frame:
- add_exception_to_frame(suspend_frame, (exception, value, trace))
- flag = True
- thread.additionalInfo.message = 'VariableDoesNotExist'
- suspend_frame.f_back = frame
- frame = suspend_frame
- except :
+ result = mainDebugger.plugin.exception_break(mainDebugger, self, frame, self._args, arg)
+ if result:
+ (flag, frame) = result
+
+ except:
flag = False
return flag, frame
@@ -253,7 +228,8 @@ class PyDBFrame:
sendSignatureCallTrace(main_debugger, frame, filename)
is_exception_event = event == 'exception'
- has_exception_breakpoints = main_debugger.break_on_caught_exceptions or main_debugger.django_exception_break
+ has_exception_breakpoints = main_debugger.break_on_caught_exceptions \
+ or main_debugger.plugin.has_exception_breaks(main_debugger)
if is_exception_event:
if has_exception_breakpoints:
@@ -293,9 +269,8 @@ class PyDBFrame:
can_skip = (step_cmd is None and stop_frame is None)\
or (step_cmd in (CMD_STEP_RETURN, CMD_STEP_OVER) and stop_frame is not frame)
- check_stop_on_django_render_call = main_debugger.django_breakpoints and self._is_django_render_call(frame)
- if check_stop_on_django_render_call:
- can_skip = False
+ if can_skip:
+ can_skip = not main_debugger.plugin.can_not_skip(main_debugger, self, frame)
# Let's check to see if we are in a function that has a breakpoint. If we don't have a breakpoint,
# we will return nothing for the next trace
@@ -334,29 +309,35 @@ class PyDBFrame:
try:
line = frame.f_lineno
-
-
flag = False
- if event == 'call' and info.pydev_state != STATE_SUSPEND and check_stop_on_django_render_call:
- flag, frame = self.should_stop_on_django_breakpoint(frame, event, arg)
-
#return is not taken into account for breakpoint hit because we'd have a double-hit in this case
#(one for the line and the other for the return).
- if not flag and event != 'return' and info.pydev_state != STATE_SUSPEND and breakpoints_for_file is not None\
- and DictContains(breakpoints_for_file, line):
- #ok, hit breakpoint, now, we have to discover if it is a conditional breakpoint
- # lets do the conditional stuff here
+ stop_info = {}
+ breakpoint = None
+ exist_result = False
+ stop_info['stop'] = False
+ if not flag and event != 'return' and info.pydev_state != STATE_SUSPEND and breakpoints_for_file is not None \
+ and DictContains(breakpoints_for_file, line):
breakpoint = breakpoints_for_file[line]
-
- stop = True
+ new_frame = frame
+ stop_info['stop'] = True
if step_cmd == CMD_STEP_OVER and stop_frame is frame and event in ('line', 'return'):
- stop = False #we don't stop on breakpoint if we have to stop by step-over (it will be processed later)
- else:
+ stop_info['stop'] = False #we don't stop on breakpoint if we have to stop by step-over (it will be processed later)
+ else:
+ result = main_debugger.plugin.get_breakpoint(main_debugger, self, frame, event, self._args)
+ if result:
+ exist_result = True
+ (flag, breakpoint, new_frame) = result
+
+ if breakpoint:
+ #ok, hit breakpoint, now, we have to discover if it is a conditional breakpoint
+ # lets do the conditional stuff here
+ if stop_info['stop'] or exist_result:
condition = breakpoint.condition
if condition is not None:
try:
- val = eval(condition, frame.f_globals, frame.f_locals)
+ val = eval(condition, new_frame.f_globals, new_frame.f_locals)
if not val:
return self.trace_dispatch
@@ -371,7 +352,7 @@ class PyDBFrame:
if not main_debugger.suspend_on_breakpoint_exception:
return self.trace_dispatch
else:
- stop = True
+ stop_info['stop'] = True
try:
additional_info = None
try:
@@ -395,18 +376,21 @@ class PyDBFrame:
except:
traceback.print_exc()
- if breakpoint.expression is not None:
- try:
+ if breakpoint.expression is not None:
try:
- val = eval(breakpoint.expression, frame.f_globals, frame.f_locals)
- except:
- val = sys.exc_info()[1]
- finally:
- if val is not None:
- thread.additionalInfo.message = val
-
- if stop:
- self.setSuspend(thread, CMD_SET_BREAK)
+ try:
+ val = eval(breakpoint.expression, new_frame.f_globals, new_frame.f_locals)
+ except:
+ val = sys.exc_info()[1]
+ finally:
+ if val is not None:
+ thread.additionalInfo.message = val
+ if stop_info['stop']:
+ self.setSuspend(thread, CMD_SET_BREAK)
+ elif flag:
+ result = main_debugger.plugin.suspend(main_debugger, thread, frame)
+ if result:
+ frame = result
# if thread has a suspend flag, we suspend with a busy wait
if info.pydev_state == STATE_SUSPEND:
@@ -419,8 +403,6 @@ class PyDBFrame:
#step handling. We stop when we hit the right frame
try:
- django_stop = False
-
should_skip = False
if pydevd_dont_trace.should_trace_hook is not None:
if not hasattr(self, 'should_skip'):
@@ -432,34 +414,18 @@ class PyDBFrame:
should_skip = self.should_skip
if should_skip:
- stop = False
+ stop_info['stop'] = False
elif step_cmd == CMD_STEP_INTO:
- stop = event in ('line', 'return')
-
- if is_django_suspended(thread):
- #django_stop = event == 'call' and is_django_render_call(frame)
- stop = stop and is_django_resolve_call(frame.f_back) and not is_django_context_get_call(frame)
- if stop:
- info.pydev_django_resolve_frame = 1 #we remember that we've go into python code from django rendering frame
+ stop_info['stop'] = event in ('line', 'return')
+ main_debugger.plugin.cmd_step_into(main_debugger, frame, event, self._args, stop_info)
elif step_cmd == CMD_STEP_OVER:
- if is_django_suspended(thread):
- django_stop = event == 'call' and self._is_django_render_call(frame)
-
- stop = False
- else:
- if event == 'return' and info.pydev_django_resolve_frame is not None and is_django_resolve_call(frame.f_back):
- #we return to Django suspend mode and should not stop before django rendering frame
- stop_frame = info.pydev_step_stop = info.pydev_django_resolve_frame
- info.pydev_django_resolve_frame = None
- thread.additionalInfo.suspend_type = DJANGO_SUSPEND
-
-
- stop = stop_frame is frame and event in ('line', 'return')
+ stop_info['stop'] = stop_frame is frame and event in ('line', 'return')
+ main_debugger.plugin.cmd_step_over(main_debugger, frame, event, self._args, stop_info)
elif step_cmd == CMD_SMART_STEP_INTO:
- stop = False
+ stop_info['stop'] = False
if info.pydev_smart_step_stop is frame:
info.pydev_func_name = None
info.pydev_smart_step_stop = None
@@ -472,13 +438,13 @@ class PyDBFrame:
curr_func_name = ''
if curr_func_name == info.pydev_func_name:
- stop = True
+ stop_info['stop'] = True
elif step_cmd == CMD_STEP_RETURN:
- stop = event == 'return' and stop_frame is frame
+ stop_info['stop'] = event == 'return' and stop_frame is frame
elif step_cmd == CMD_RUN_TO_LINE or step_cmd == CMD_SET_NEXT_STATEMENT:
- stop = False
+ stop_info['stop'] = False
if event == 'line' or event == 'exception':
#Yes, we can only act on line events (weird hum?)
@@ -493,50 +459,47 @@ class PyDBFrame:
if curr_func_name == info.pydev_func_name:
line = info.pydev_next_line
if frame.f_lineno == line:
- stop = True
+ stop_info['stop'] = True
else:
if frame.f_trace is None:
frame.f_trace = self.trace_dispatch
frame.f_lineno = line
frame.f_trace = None
- stop = True
+ stop_info['stop'] = True
else:
- stop = False
-
- if django_stop:
- frame = suspend_django(self, main_debugger, thread, frame)
- if frame:
- self.doWaitSuspend(thread, frame, event, arg)
- elif stop:
- #event is always == line or return at this point
- if event == 'line':
- self.setSuspend(thread, step_cmd)
- self.doWaitSuspend(thread, frame, event, arg)
- else: #return event
- back = frame.f_back
- if back is not None:
- #When we get to the pydevd run function, the debugging has actually finished for the main thread
- #(note that it can still go on for other threads, but for this one, we just make it finish)
- #So, just setting it to None should be OK
- base = basename(back.f_code.co_filename)
- if base == 'pydevd.py' and back.f_code.co_name == 'run':
- back = None
-
- elif base == 'pydevd_traceproperty.py':
- # We dont want to trace the return event of pydevd_traceproperty (custom property for debugging)
- #if we're in a return, we want it to appear to the user in the previous frame!
- return None
+ stop_info['stop'] = False
- if back is not None:
- #if we're in a return, we want it to appear to the user in the previous frame!
+ if True in DictIterValues(stop_info):
+ stopped_on_plugin = main_debugger.plugin.stop(main_debugger, frame, event, self._args, stop_info, arg, step_cmd)
+ if DictContains(stop_info, 'stop') and stop_info['stop'] and not stopped_on_plugin:
+ if event == 'line':
self.setSuspend(thread, step_cmd)
- self.doWaitSuspend(thread, back, event, arg)
- else:
- #in jython we may not have a back frame
- info.pydev_step_stop = None
- info.pydev_step_cmd = None
- info.pydev_state = STATE_RUN
+ self.doWaitSuspend(thread, frame, event, arg)
+ else: #return event
+ back = frame.f_back
+ if back is not None:
+ #When we get to the pydevd run function, the debugging has actually finished for the main thread
+ #(note that it can still go on for other threads, but for this one, we just make it finish)
+ #So, just setting it to None should be OK
+ base = basename(back.f_code.co_filename)
+ if base == 'pydevd.py' and back.f_code.co_name == 'run':
+ back = None
+
+ elif base == 'pydevd_traceproperty.py':
+ # We dont want to trace the return event of pydevd_traceproperty (custom property for debugging)
+ #if we're in a return, we want it to appear to the user in the previous frame!
+ return None
+
+ if back is not None:
+ #if we're in a return, we want it to appear to the user in the previous frame!
+ self.setSuspend(thread, step_cmd)
+ self.doWaitSuspend(thread, back, event, arg)
+ else:
+ #in jython we may not have a back frame
+ info.pydev_step_stop = None
+ info.pydev_step_cmd = None
+ info.pydev_state = STATE_RUN
except:
@@ -562,61 +525,4 @@ class PyDBFrame:
except ImportError:
if hasattr(sys, 'exc_clear'): #jython does not have it
sys.exc_clear() #don't keep the traceback
- pass #ok, psyco not available
-
- def should_stop_on_django_breakpoint(self, frame, event, arg):
- mainDebugger = self._args[0]
- thread = self._args[3]
- flag = False
- template_frame_file = get_template_file_name(frame)
-
- #pydev_log.debug("Django is rendering a template: %s\n" % template_frame_file)
-
- django_breakpoints_for_file = mainDebugger.django_breakpoints.get(template_frame_file)
- if django_breakpoints_for_file:
-
- #pydev_log.debug("Breakpoints for that file: %s\n" % django_breakpoints_for_file)
-
- template_frame_line = get_template_line(frame, template_frame_file)
-
- #pydev_log.debug("Tracing template line: %d\n" % template_frame_line)
-
- if DictContains(django_breakpoints_for_file, template_frame_line):
- django_breakpoint = django_breakpoints_for_file[template_frame_line]
-
- if django_breakpoint.is_triggered(template_frame_file, template_frame_line):
-
- #pydev_log.debug("Breakpoint is triggered.\n")
-
- flag = True
- new_frame = DjangoTemplateFrame(
- frame,
- template_frame_file=template_frame_file,
- template_frame_line=template_frame_line,
- )
-
- if django_breakpoint.condition is not None:
- try:
- val = eval(django_breakpoint.condition, new_frame.f_globals, new_frame.f_locals)
- if not val:
- flag = False
- pydev_log.debug("Condition '%s' is evaluated to %s. Not suspending.\n" % (django_breakpoint.condition, val))
- except:
- pydev_log.info(
- 'Error while evaluating condition \'%s\': %s\n' % (django_breakpoint.condition, sys.exc_info()[1]))
-
- if django_breakpoint.expression is not None:
- try:
- try:
- val = eval(django_breakpoint.expression, new_frame.f_globals, new_frame.f_locals)
- except:
- val = sys.exc_info()[1]
- finally:
- if val is not None:
- thread.additionalInfo.message = val
- if flag:
- frame = suspend_django(self, mainDebugger, thread, frame)
- return flag, frame
-
-def add_exception_to_frame(frame, exception_info):
- frame.f_locals['__exception__'] = exception_info \ No newline at end of file
+ pass #ok, psyco not available \ No newline at end of file
diff --git a/python/helpers/pydev/pydevd_frame_utils.py b/python/helpers/pydev/pydevd_frame_utils.py
index 23becca0570d..0c9e8446d19c 100644
--- a/python/helpers/pydev/pydevd_frame_utils.py
+++ b/python/helpers/pydev/pydevd_frame_utils.py
@@ -1,11 +1,11 @@
-class Frame:
+class Frame(object):
def __init__(
self,
f_back,
f_fileno,
f_code,
f_locals,
- f_globals={},
+ f_globals=None,
f_trace=None):
self.f_back = f_back
self.f_lineno = f_fileno
@@ -14,8 +14,31 @@ class Frame:
self.f_globals = f_globals
self.f_trace = f_trace
+ if self.f_globals is None:
+ self.f_globals = {}
-class FCode:
+
+class FCode(object):
def __init__(self, name, filename):
self.co_name = name
- self.co_filename = filename \ No newline at end of file
+ self.co_filename = filename
+
+
+def add_exception_to_frame(frame, exception_info):
+ frame.f_locals['__exception__'] = exception_info
+
+
+def just_raised(trace):
+ if trace is None:
+ return False
+ return trace.tb_next is None
+
+
+def cached_call(obj, func, *args):
+ cached_name = '_cached_' + func.__name__
+ if not hasattr(obj, cached_name):
+ setattr(obj, cached_name, func(*args))
+
+ return getattr(obj, cached_name)
+
+
diff --git a/python/helpers/pydev/pydevd_plugin_utils.py b/python/helpers/pydev/pydevd_plugin_utils.py
new file mode 100644
index 000000000000..5b106b8234db
--- /dev/null
+++ b/python/helpers/pydev/pydevd_plugin_utils.py
@@ -0,0 +1,85 @@
+import os
+import types
+
+import pydev_log
+import pydevd_trace_api
+from third_party.pluginbase import PluginBase
+
+def load_plugins(package):
+ plugin_base = PluginBase(package=package)
+ plugin_source = plugin_base.make_plugin_source(searchpath=[os.path.dirname(os.path.realpath(__file__)) + '/' + package], persist=True)
+ plugins = []
+ for plugin in plugin_source.list_plugins():
+ loaded_plugin = None
+ try:
+ loaded_plugin = plugin_source.load_plugin(plugin)
+ except:
+ pydev_log.error("Failed to load plugin %s" % plugin, True)
+ if loaded_plugin:
+ plugins.append(loaded_plugin)
+
+ return plugins
+
+
+def bind_func_to_method(func, obj, method_name):
+ foo = types.MethodType(func, obj)
+
+ setattr(obj, method_name, foo)
+ return foo
+
+
+class PluginManager(object):
+ def __init__(self, main_debugger):
+ self.plugins = load_plugins('pydevd_plugins')
+ self.active_plugins = []
+ self.main_debugger = main_debugger
+ self.rebind_methods()
+
+ def add_breakpoint(self, func_name, *args, **kwargs):
+ # add breakpoint for plugin and remember which plugin to use in tracing
+ for plugin in self.plugins:
+ if hasattr(plugin, func_name):
+ func = getattr(plugin, func_name)
+ result = func(self, *args, **kwargs)
+ if result:
+ self.activate(plugin)
+
+ return result
+ return None
+
+ def activate(self, plugin):
+ self.active_plugins.append(plugin)
+ self.rebind_methods()
+
+ def rebind_methods(self):
+ if len(self.active_plugins) == 0:
+ self.bind_functions(pydevd_trace_api, getattr, pydevd_trace_api)
+ elif len(self.active_plugins) == 1:
+ self.bind_functions(pydevd_trace_api, getattr, self.active_plugins[0])
+ else:
+ self.bind_functions(pydevd_trace_api, create_dispatch, self.active_plugins)
+
+ def bind_functions(self, interface, function_factory, arg):
+ for name in dir(interface):
+ func = function_factory(arg, name)
+ if type(func) == types.FunctionType:
+ bind_func_to_method(func, self, name)
+
+
+def create_dispatch(obj, name):
+ def dispatch(self, *args, **kwargs):
+ result = None
+ for p in self.active_plugins:
+ r = getattr(p, name)(self, *args, **kwargs)
+ if not result:
+ result = r
+ return result
+ return dispatch
+
+
+
+
+
+
+
+
diff --git a/python/helpers/pydev/pydevd_plugins/__init__.py b/python/helpers/pydev/pydevd_plugins/__init__.py
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/python/helpers/pydev/pydevd_plugins/__init__.py
diff --git a/python/helpers/pydev/pydevd_plugins/django_debug.py b/python/helpers/pydev/pydevd_plugins/django_debug.py
new file mode 100644
index 000000000000..ac23d40bd381
--- /dev/null
+++ b/python/helpers/pydev/pydevd_plugins/django_debug.py
@@ -0,0 +1,357 @@
+from pydevd_comm import CMD_SET_BREAK, CMD_ADD_EXCEPTION_BREAK
+import inspect
+from pydevd_constants import STATE_SUSPEND, GetThreadId, DictContains
+from pydevd_file_utils import NormFileToServer, GetFileNameAndBaseFromFile
+from pydevd_breakpoints import LineBreakpoint, get_exception_name
+import pydevd_vars
+import traceback
+import pydev_log
+from pydevd_frame_utils import add_exception_to_frame, FCode, cached_call, just_raised
+
+DJANGO_SUSPEND = 2
+
+class DjangoLineBreakpoint(LineBreakpoint):
+ def __init__(self, file, line, condition, func_name, expression):
+ self.file = file
+ LineBreakpoint.__init__(self, line, condition, func_name, expression)
+
+ def is_triggered(self, template_frame_file, template_frame_line):
+ return self.file == template_frame_file and self.line == template_frame_line
+
+ def __str__(self):
+ return "DjangoLineBreakpoint: %s-%d" %(self.file, self.line)
+
+
+def add_line_breakpoint(plugin, pydb, type, file, line, condition, expression, func_name):
+ if type == 'django-line':
+ breakpoint = DjangoLineBreakpoint(file, line, condition, func_name, expression)
+ if not hasattr(pydb, 'django_breakpoints'):
+ pydb.django_breakpoints = {}
+ return breakpoint, pydb.django_breakpoints
+ return None
+
+def add_exception_breakpoint(plugin, pydb, type, exception):
+ if type == 'django':
+ if not hasattr(pydb, 'django_exception_break'):
+ pydb.django_exception_break = {}
+ pydb.django_exception_break[exception] = True
+ pydb.setTracingForUntracedContexts()
+ return True
+ return False
+
+
+def remove_exception_breakpoint(plugin, pydb, type, exception):
+ if type == 'django':
+ try:
+ del pydb.django_exception_break[exception]
+ return True
+ except:
+ pass
+ return False
+
+def get_breakpoints(plugin, pydb, type):
+ if type == 'django-line':
+ return pydb.django_breakpoints
+ return None
+
+def _inherits(cls, *names):
+ if cls.__name__ in names:
+ return True
+ inherits_node = False
+ for base in inspect.getmro(cls):
+ if base.__name__ in names:
+ inherits_node = True
+ break
+ return inherits_node
+
+
+def _is_django_render_call(frame):
+ try:
+ name = frame.f_code.co_name
+ if name != 'render':
+ return False
+
+ if not DictContains(frame.f_locals, 'self'):
+ return False
+
+ cls = frame.f_locals['self'].__class__
+
+ inherits_node = _inherits(cls, 'Node')
+
+ if not inherits_node:
+ return False
+
+ clsname = cls.__name__
+ return clsname != 'TextNode' and clsname != 'NodeList'
+ except:
+ traceback.print_exc()
+ return False
+
+
+def _is_django_context_get_call(frame):
+ try:
+ if not DictContains(frame.f_locals, 'self'):
+ return False
+
+ cls = frame.f_locals['self'].__class__
+
+ return _inherits(cls, 'BaseContext')
+ except:
+ traceback.print_exc()
+ return False
+
+
+def _is_django_resolve_call(frame):
+ try:
+ name = frame.f_code.co_name
+ if name != '_resolve_lookup':
+ return False
+
+ if not DictContains(frame.f_locals, 'self'):
+ return False
+
+ cls = frame.f_locals['self'].__class__
+
+ clsname = cls.__name__
+ return clsname == 'Variable'
+ except:
+ traceback.print_exc()
+ return False
+
+
+def _is_django_suspended(thread):
+ return thread.additionalInfo.suspend_type == DJANGO_SUSPEND
+
+
+def suspend_django(mainDebugger, thread, frame, cmd=CMD_SET_BREAK):
+ frame = DjangoTemplateFrame(frame)
+
+ if frame.f_lineno is None:
+ return None
+
+ #try:
+ # if thread.additionalInfo.filename == frame.f_code.co_filename and thread.additionalInfo.line == frame.f_lineno:
+ # return None # don't stay twice on the same line
+ #except AttributeError:
+ # pass
+
+ pydevd_vars.addAdditionalFrameById(GetThreadId(thread), {id(frame): frame})
+
+ mainDebugger.setSuspend(thread, cmd)
+ thread.additionalInfo.suspend_type = DJANGO_SUSPEND
+
+ thread.additionalInfo.filename = frame.f_code.co_filename
+ thread.additionalInfo.line = frame.f_lineno
+
+ return frame
+
+
+def _find_django_render_frame(frame):
+ while frame is not None and not _is_django_render_call(frame):
+ frame = frame.f_back
+
+ return frame
+
+#=======================================================================================================================
+# Django Frame
+#=======================================================================================================================
+
+def _read_file(filename):
+ f = open(filename, "r")
+ s = f.read()
+ f.close()
+ return s
+
+
+def _offset_to_line_number(text, offset):
+ curLine = 1
+ curOffset = 0
+ while curOffset < offset:
+ if curOffset == len(text):
+ return -1
+ c = text[curOffset]
+ if c == '\n':
+ curLine += 1
+ elif c == '\r':
+ curLine += 1
+ if curOffset < len(text) and text[curOffset + 1] == '\n':
+ curOffset += 1
+
+ curOffset += 1
+
+ return curLine
+
+
+def _get_source(frame):
+ try:
+ node = frame.f_locals['self']
+ if hasattr(node, 'source'):
+ return node.source
+ else:
+ pydev_log.error_once("WARNING: Template path is not available. Please set TEMPLATE_DEBUG=True in your settings.py to make "
+ " django template breakpoints working")
+ return None
+
+ except:
+ pydev_log.debug(traceback.format_exc())
+ return None
+
+
+def _get_template_file_name(frame):
+ try:
+ source = _get_source(frame)
+ if source is None:
+ pydev_log.debug("Source is None\n")
+ return None
+ fname = source[0].name
+
+ if fname == '<unknown source>':
+ pydev_log.debug("Source name is %s\n" % fname)
+ return None
+ else:
+ filename, base = GetFileNameAndBaseFromFile(fname)
+ return filename
+ except:
+ pydev_log.debug(traceback.format_exc())
+ return None
+
+
+def _get_template_line(frame):
+ source = _get_source(frame)
+ file_name = _get_template_file_name(frame)
+ try:
+ return _offset_to_line_number(_read_file(file_name), source[1][0])
+ except:
+ return None
+
+
+class DjangoTemplateFrame:
+ def __init__(self, frame):
+ file_name = _get_template_file_name(frame)
+ self.back_context = frame.f_locals['context']
+ self.f_code = FCode('Django Template', file_name)
+ self.f_lineno = _get_template_line(frame)
+ self.f_back = frame
+ self.f_globals = {}
+ self.f_locals = self.collect_context(self.back_context)
+ self.f_trace = None
+
+ def collect_context(self, context):
+ res = {}
+ try:
+ for d in context.dicts:
+ for k, v in d.items():
+ res[k] = v
+ except AttributeError:
+ pass
+ return res
+
+ def changeVariable(self, name, value):
+ for d in self.back_context.dicts:
+ for k, v in d.items():
+ if k == name:
+ d[k] = value
+
+def _is_django_exception_break_context(frame):
+ try:
+ name = frame.f_code.co_name
+ except:
+ name = None
+ return name in ['_resolve_lookup', 'find_template']
+
+
+#=======================================================================================================================
+# Django Step Commands
+#=======================================================================================================================
+
+def can_not_skip(plugin, mainDebugger, pydb_frame, frame):
+ if hasattr(mainDebugger, 'django_breakpoints') and mainDebugger.django_breakpoints and cached_call(pydb_frame, _is_django_render_call, frame):
+ filename = _get_template_file_name(frame)
+ django_breakpoints_for_file = mainDebugger.django_breakpoints.get(filename)
+ if django_breakpoints_for_file:
+ return True
+ return False
+
+def has_exception_breaks(plugin, mainDebugger):
+ return hasattr(mainDebugger, 'django_exception_break') and mainDebugger.django_exception_break
+
+
+def cmd_step_into(plugin, mainDebugger, frame, event, args, stop_info):
+ mainDebugger, filename, info, thread = args
+ if _is_django_suspended(thread):
+ #stop_info['django_stop'] = event == 'call' and cached_call(frame, is_django_render_call)
+ stop_info['stop'] = stop_info['stop'] and _is_django_resolve_call(frame.f_back) and not _is_django_context_get_call(frame)
+ if stop_info['stop']:
+ info.pydev_django_resolve_frame = 1 #we remember that we've go into python code from django rendering frame
+
+
+def cmd_step_over(plugin, mainDebugger, frame, event, args, stop_info):
+ mainDebugger, filename, info, thread = args
+ if _is_django_suspended(thread):
+ stop_info['django_stop'] = event == 'call' and _is_django_render_call(frame)
+ stop_info['stop'] = False
+ return True
+ else:
+ if event == 'return' and info.pydev_django_resolve_frame is not None and _is_django_resolve_call(frame.f_back):
+ #we return to Django suspend mode and should not stop before django rendering frame
+ info.pydev_step_stop = info.pydev_django_resolve_frame
+ info.pydev_django_resolve_frame = None
+ thread.additionalInfo.suspend_type = DJANGO_SUSPEND
+ stop_info['stop'] = info.pydev_step_stop is frame and event in ('line', 'return')
+
+ return False
+
+
+def stop(plugin, mainDebugger, frame, event, args, stop_info, arg, step_cmd):
+ mainDebugger, filename, info, thread = args
+ if DictContains(stop_info, 'django_stop') and stop_info['django_stop']:
+ frame = suspend_django(mainDebugger, thread, frame, step_cmd)
+ if frame:
+ mainDebugger.doWaitSuspend(thread, frame, event, arg)
+ return True
+ return False
+
+
+def get_breakpoint(plugin, mainDebugger, pydb_frame, frame, event, args):
+ mainDebugger, filename, info, thread = args
+ flag = False
+ django_breakpoint = None
+ new_frame = None
+
+ if event == 'call' and info.pydev_state != STATE_SUSPEND and hasattr(mainDebugger, 'django_breakpoints') and \
+ mainDebugger.django_breakpoints and cached_call(pydb_frame, _is_django_render_call, frame):
+ filename = _get_template_file_name(frame)
+ pydev_log.debug("Django is rendering a template: %s\n" % filename)
+ django_breakpoints_for_file = mainDebugger.django_breakpoints.get(filename)
+ if django_breakpoints_for_file:
+ pydev_log.debug("Breakpoints for that file: %s\n" % django_breakpoints_for_file)
+ template_line = _get_template_line(frame)
+ pydev_log.debug("Tracing template line: %d\n" % template_line)
+
+ if DictContains(django_breakpoints_for_file, template_line):
+ django_breakpoint = django_breakpoints_for_file[template_line]
+ flag = True
+ new_frame = DjangoTemplateFrame(frame)
+ return flag, django_breakpoint, new_frame
+
+
+def suspend(plugin, mainDebugger, thread, frame):
+ return suspend_django(mainDebugger, thread, frame)
+
+def exception_break(plugin, mainDebugger, pydb_frame, frame, args, arg):
+ mainDebugger, filename, info, thread = args
+ exception, value, trace = arg
+ if hasattr(mainDebugger, 'django_exception_break') and mainDebugger.django_exception_break and \
+ get_exception_name(exception) in ['VariableDoesNotExist', 'TemplateDoesNotExist', 'TemplateSyntaxError'] and \
+ just_raised(trace) and _is_django_exception_break_context(frame):
+ render_frame = _find_django_render_frame(frame)
+ if render_frame:
+ suspend_frame = suspend_django(mainDebugger, thread, render_frame, CMD_ADD_EXCEPTION_BREAK)
+ if suspend_frame:
+ add_exception_to_frame(suspend_frame, (exception, value, trace))
+ flag = True
+ thread.additionalInfo.message = 'VariableDoesNotExist'
+ suspend_frame.f_back = frame
+ frame = suspend_frame
+ return (flag, frame)
+ return None \ No newline at end of file
diff --git a/python/helpers/pydev/pydevd_plugins/jinja2_debug.py b/python/helpers/pydev/pydevd_plugins/jinja2_debug.py
new file mode 100644
index 000000000000..9968a81d0043
--- /dev/null
+++ b/python/helpers/pydev/pydevd_plugins/jinja2_debug.py
@@ -0,0 +1,341 @@
+import traceback
+from pydevd_breakpoints import LineBreakpoint, get_exception_name
+from pydevd_constants import GetThreadId, STATE_SUSPEND, DictContains
+from pydevd_comm import CMD_SET_BREAK, CMD_STEP_OVER, CMD_ADD_EXCEPTION_BREAK
+import pydevd_vars
+from pydevd_file_utils import GetFileNameAndBaseFromFile
+from pydevd_frame_utils import add_exception_to_frame, FCode, cached_call
+
+JINJA2_SUSPEND = 3
+
+class Jinja2LineBreakpoint(LineBreakpoint):
+
+ def __init__(self, file, line, condition, func_name, expression):
+ self.file = file
+ LineBreakpoint.__init__(self, line, condition, func_name, expression)
+
+ def is_triggered(self, template_frame_file, template_frame_line):
+ return self.file == template_frame_file and self.line == template_frame_line
+
+ def __str__(self):
+ return "Jinja2LineBreakpoint: %s-%d" %(self.file, self.line)
+
+
+def add_line_breakpoint(plugin, pydb, type, file, line, condition, func_name, expression):
+ result = None
+ if type == 'jinja2-line':
+ breakpoint = Jinja2LineBreakpoint(file, line, condition, func_name, expression)
+ if not hasattr(pydb, 'jinja2_breakpoints'):
+ pydb.jinja2_breakpoints = {}
+ result = breakpoint, pydb.jinja2_breakpoints
+ return result
+ return result
+
+def add_exception_breakpoint(plugin, pydb, type, exception):
+ if type == 'jinja2':
+ if not hasattr(pydb, 'jinja2_exception_break'):
+ pydb.jinja2_exception_break = {}
+ pydb.jinja2_exception_break[exception] = True
+ pydb.setTracingForUntracedContexts()
+ return True
+ return False
+
+def remove_exception_breakpoint(plugin, pydb, type, exception):
+ if type == 'jinja2':
+ try:
+ del pydb.jinja2_exception_break[exception]
+ return True
+ except:
+ pass
+ return False
+
+def get_breakpoints(plugin, pydb, type):
+ if type == 'jinja2-line':
+ return pydb.jinja2_breakpoints
+ return None
+
+
+def is_jinja2_render_call(frame):
+ try:
+ name = frame.f_code.co_name
+ if DictContains(frame.f_globals, "__jinja_template__") and name in ("root", "loop", "macro") or name.startswith("block_"):
+ return True
+ return False
+ except:
+ traceback.print_exc()
+ return False
+
+
+def suspend_jinja2(pydb, thread, frame, cmd=CMD_SET_BREAK):
+ frame = Jinja2TemplateFrame(frame)
+
+ if frame.f_lineno is None:
+ return None
+
+ pydevd_vars.addAdditionalFrameById(GetThreadId(thread), {id(frame): frame})
+ pydb.setSuspend(thread, cmd)
+
+ thread.additionalInfo.suspend_type = JINJA2_SUSPEND
+ thread.additionalInfo.filename = frame.f_code.co_filename
+ thread.additionalInfo.line = frame.f_lineno
+
+ return frame
+
+def is_jinja2_suspended(thread):
+ return thread.additionalInfo.suspend_type == JINJA2_SUSPEND
+
+def is_jinja2_context_call(frame):
+ return DictContains(frame.f_locals, "_Context__obj")
+
+def is_jinja2_internal_function(frame):
+ return DictContains(frame.f_locals, 'self') and frame.f_locals['self'].__class__.__name__ in \
+ ('LoopContext', 'TemplateReference', 'Macro', 'BlockReference')
+
+def find_jinja2_render_frame(frame):
+ while frame is not None and not is_jinja2_render_call(frame):
+ frame = frame.f_back
+
+ return frame
+
+def change_variable(plugin, pydb, frame, attr, expression):
+ if isinstance(frame, Jinja2TemplateFrame):
+ result = eval(expression, frame.f_globals, frame.f_locals)
+ frame.changeVariable(attr, result)
+
+
+#=======================================================================================================================
+# Jinja2 Frame
+#=======================================================================================================================
+
+class Jinja2TemplateFrame:
+
+ def __init__(self, frame):
+ file_name = get_jinja2_template_filename(frame)
+ self.back_context = None
+ if 'context' in frame.f_locals:
+ #sometimes we don't have 'context', e.g. in macros
+ self.back_context = frame.f_locals['context']
+ self.f_code = FCode('template', file_name)
+ self.f_lineno = get_jinja2_template_line(frame)
+ self.f_back = find_render_function_frame(frame)
+ self.f_globals = {}
+ self.f_locals = self.collect_context(frame)
+ self.f_trace = None
+
+ def collect_context(self, frame):
+ res = {}
+ if self.back_context is not None:
+ for k, v in self.back_context.items():
+ res[k] = v
+ for k, v in frame.f_locals.items():
+ if not k.startswith('l_'):
+ if not k in res:
+ #local variables should shadow globals from context
+ res[k] = v
+ elif v and not is_missing(v):
+ res[k[2:]] = v
+ return res
+
+ def changeVariable(self, name, value):
+ for k, v in self.back_context.items():
+ if k == name:
+ self.back_context.vars[k] = value
+
+def is_missing(item):
+ if item.__class__.__name__ == 'MissingType':
+ return True
+ return False
+
+def find_render_function_frame(frame):
+ #in order to hide internal rendering functions
+ old_frame = frame
+ try:
+ while not (DictContains(frame.f_locals, 'self') and frame.f_locals['self'].__class__.__name__ == 'Template' and \
+ frame.f_code.co_name == 'render'):
+ frame = frame.f_back
+ if frame is None:
+ return old_frame
+ return frame
+ except:
+ return old_frame
+
+def get_jinja2_template_line(frame):
+ debug_info = None
+ if DictContains(frame.f_globals,'__jinja_template__'):
+ _debug_info = frame.f_globals['__jinja_template__']._debug_info
+ if _debug_info != '':
+ #sometimes template contains only plain text
+ debug_info = frame.f_globals['__jinja_template__'].debug_info
+
+ if debug_info is None:
+ return None
+
+ lineno = frame.f_lineno
+
+ for pair in debug_info:
+ if pair[1] == lineno:
+ return pair[0]
+
+ return None
+
+def get_jinja2_template_filename(frame):
+ if DictContains(frame.f_globals, '__jinja_template__'):
+ fname = frame.f_globals['__jinja_template__'].filename
+ filename, base = GetFileNameAndBaseFromFile(fname)
+ return filename
+ return None
+
+
+#=======================================================================================================================
+# Jinja2 Step Commands
+#=======================================================================================================================
+
+
+def has_exception_breaks(plugin, pydb):
+ return hasattr(pydb, 'jinja2_exception_break') and pydb.jinja2_exception_break
+
+def can_not_skip(plugin, pydb, pydb_frame, frame):
+ if hasattr(pydb, 'jinja2_breakpoints') and pydb.jinja2_breakpoints and cached_call(pydb_frame, is_jinja2_render_call, frame):
+ filename = get_jinja2_template_filename(frame)
+ jinja2_breakpoints_for_file = pydb.jinja2_breakpoints.get(filename)
+ if jinja2_breakpoints_for_file:
+ return True
+ return False
+
+
+def cmd_step_into(plugin, pydb, frame, event, args, stop_info):
+ pydb, filename, info, thread = args
+ if not hasattr(info, 'pydev_call_from_jinja2'):
+ info.pydev_call_from_jinja2 = None
+ if not hasattr(info, 'pydev_call_inside_jinja2'):
+ info.pydev_call_inside_jinja2 = None
+ if is_jinja2_suspended(thread):
+ stop_info['jinja2_stop'] = event in ('call', 'line') and is_jinja2_render_call(frame)
+ stop_info['stop'] = False
+ if info.pydev_call_from_jinja2 is not None:
+ if is_jinja2_internal_function(frame):
+ #if internal Jinja2 function was called, we sould continue debugging inside template
+ info.pydev_call_from_jinja2 = None
+ else:
+ #we go into python code from Jinja2 rendering frame
+ stop_info['stop'] = True
+
+ if event == 'call' and is_jinja2_context_call(frame.f_back):
+ #we called function from context, the next step will be in function
+ info.pydev_call_from_jinja2 = 1
+
+ if event == 'return' and is_jinja2_context_call(frame.f_back):
+ #we return from python code to Jinja2 rendering frame
+ info.pydev_step_stop = info.pydev_call_from_jinja2
+ info.pydev_call_from_jinja2 = None
+ thread.additionalInfo.suspend_type = JINJA2_SUSPEND
+ stop_info['stop'] = False
+
+ #print "info.pydev_call_from_jinja2", info.pydev_call_from_jinja2, "stop_info", stop_info, \
+ # "thread.additionalInfo.suspend_type", thread.additionalInfo.suspend_type
+ #print "event", event, "farme.locals", frame.f_locals
+
+
+def cmd_step_over(plugin, pydb, frame, event, args, stop_info):
+ pydb, filename, info, thread = args
+ if not hasattr(info, 'pydev_call_from_jinja2'):
+ info.pydev_call_from_jinja2 = None
+ if not hasattr(info, 'pydev_call_inside_jinja2'):
+ info.pydev_call_inside_jinja2 = None
+ if is_jinja2_suspended(thread):
+ stop_info['stop'] = False
+
+ if info.pydev_call_inside_jinja2 is None:
+ if is_jinja2_render_call(frame):
+ if event == 'call':
+ info.pydev_call_inside_jinja2 = frame.f_back
+ if event in ('line', 'return'):
+ info.pydev_call_inside_jinja2 = frame
+ else:
+ if event == 'line':
+ if is_jinja2_render_call(frame) and info.pydev_call_inside_jinja2 is frame:
+ stop_info['jinja2_stop'] = True
+ if event == 'return':
+ if frame is info.pydev_call_inside_jinja2 and not DictContains(frame.f_back.f_locals,'event'):
+ info.pydev_call_inside_jinja2 = find_jinja2_render_frame(frame.f_back)
+ return True
+ else:
+ if event == 'return' and is_jinja2_context_call(frame.f_back):
+ #we return from python code to Jinja2 rendering frame
+ info.pydev_call_from_jinja2 = None
+ info.pydev_call_inside_jinja2 = find_jinja2_render_frame(frame)
+ thread.additionalInfo.suspend_type = JINJA2_SUSPEND
+ stop_info['stop'] = False
+ return True
+ #print "info.pydev_call_from_jinja2", info.pydev_call_from_jinja2, "stop", stop, "jinja_stop", jinja2_stop, \
+ # "thread.additionalInfo.suspend_type", thread.additionalInfo.suspend_type
+ #print "event", event, "info.pydev_call_inside_jinja2", info.pydev_call_inside_jinja2
+ #print "frame", frame, "frame.f_back", frame.f_back, "step_stop", info.pydev_step_stop
+ #print "is_context_call", is_jinja2_context_call(frame)
+ #print "render", is_jinja2_render_call(frame)
+ #print "-------------"
+ return False
+
+
+def stop(plugin, pydb, frame, event, args, stop_info, arg, step_cmd):
+ pydb, filename, info, thread = args
+ if DictContains(stop_info, 'jinja2_stop') and stop_info['jinja2_stop']:
+ frame = suspend_jinja2(pydb, thread, frame, step_cmd)
+ if frame:
+ pydb.doWaitSuspend(thread, frame, event, arg)
+ return True
+ return False
+
+
+def get_breakpoint(plugin, pydb, pydb_frame, frame, event, args):
+ pydb, filename, info, thread = args
+ new_frame = None
+ jinja2_breakpoint = None
+ flag = False
+ if event in ('line', 'call') and info.pydev_state != STATE_SUSPEND and hasattr(pydb, 'jinja2_breakpoints') and \
+ pydb.jinja2_breakpoints and cached_call(pydb_frame, is_jinja2_render_call, frame):
+ filename = get_jinja2_template_filename(frame)
+ jinja2_breakpoints_for_file = pydb.jinja2_breakpoints.get(filename)
+ new_frame = Jinja2TemplateFrame(frame)
+
+ if jinja2_breakpoints_for_file:
+ lineno = frame.f_lineno
+ template_lineno = get_jinja2_template_line(frame)
+ if template_lineno is not None and DictContains(jinja2_breakpoints_for_file, template_lineno):
+ jinja2_breakpoint = jinja2_breakpoints_for_file[template_lineno]
+ flag = True
+ new_frame = Jinja2TemplateFrame(frame)
+
+ return flag, jinja2_breakpoint, new_frame
+
+
+def suspend(plugin, pydb, thread, frame):
+ return suspend_jinja2(pydb, thread, frame)
+
+
+def exception_break(plugin, pydb, pydb_frame, frame, args, arg):
+ pydb, filename, info, thread = args
+ exception, value, trace = arg
+ if hasattr(pydb, 'jinja2_exception_break') and pydb.jinja2_exception_break:
+ if get_exception_name(exception) in ('UndefinedError', 'TemplateNotFound', 'TemplatesNotFound'):
+ #errors in rendering
+ render_frame = find_jinja2_render_frame(frame)
+ if render_frame:
+ suspend_frame = suspend_jinja2(pydb, thread, render_frame, CMD_ADD_EXCEPTION_BREAK)
+ if suspend_frame:
+ add_exception_to_frame(suspend_frame, (exception, value, trace))
+ flag = True
+ suspend_frame.f_back = frame
+ frame = suspend_frame
+ return flag, frame
+ elif get_exception_name(exception) in ('TemplateSyntaxError', 'TemplateAssertionError'):
+ #errors in compile time
+ name = frame.f_code.co_name
+ if name in ('template', 'top-level template code') or name.startswith('block '):
+ #Jinja2 translates exception info and creates fake frame on his own
+ pydb_frame.setSuspend(thread, CMD_ADD_EXCEPTION_BREAK)
+ add_exception_to_frame(frame, (exception, value, trace))
+ thread.additionalInfo.suspend_type = JINJA2_SUSPEND
+ flag = True
+ return flag, frame
+ return None \ No newline at end of file
diff --git a/python/helpers/pydev/pydevd_resolver.py b/python/helpers/pydev/pydevd_resolver.py
index ad49bd881ba0..444dead4cce7 100644
--- a/python/helpers/pydev/pydevd_resolver.py
+++ b/python/helpers/pydev/pydevd_resolver.py
@@ -409,6 +409,17 @@ class NdArrayResolver:
return obj.dtype
if attribute == 'size':
return obj.size
+ if attribute.startswith('['):
+ container = NdArrayItemsContainer()
+ i = 0
+ format_str = '%0' + str(int(len(str(len(obj))))) + 'd'
+ for item in obj:
+ setattr(container, format_str % i, item)
+ i += 1
+ if i > MAX_ITEMS_TO_HANDLE:
+ setattr(container, TOO_LARGE_ATTR, TOO_LARGE_MSG)
+ break
+ return container
return None
def getDictionary(self, obj):
@@ -427,9 +438,10 @@ class NdArrayResolver:
ret['shape'] = obj.shape
ret['dtype'] = obj.dtype
ret['size'] = obj.size
+ ret['[0:%s]' % (len(obj))] = list(obj)
return ret
-
+class NdArrayItemsContainer: pass
#=======================================================================================================================
# FrameResolver
#=======================================================================================================================
diff --git a/python/helpers/pydev/pydevd_trace_api.py b/python/helpers/pydev/pydevd_trace_api.py
new file mode 100644
index 000000000000..5d2f30e98a3a
--- /dev/null
+++ b/python/helpers/pydev/pydevd_trace_api.py
@@ -0,0 +1,35 @@
+def add_line_breakpoint(plugin, pydb, type, file, line, condition, expression, func_name):
+ return None
+
+def add_exception_breakpoint(plugin, pydb, type, exception):
+ return False
+
+def remove_exception_breakpoint(plugin, pydb, type, exception):
+ return False
+
+def get_breakpoints(plugin, pydb):
+ return None
+
+def can_not_skip(plugin, pydb, pydb_frame, frame):
+ return False
+
+def has_exception_breaks(plugin, pydb):
+ return False
+
+def cmd_step_into(plugin, pydb, frame, event, args, stop_info):
+ return False
+
+def cmd_step_over(plugin, pydb, frame, event, args, stop_info):
+ return False
+
+def stop(plugin, pydb, frame, event, args, stop_info, arg, step_cmd):
+ return False
+
+def get_breakpoint(plugin, pydb, pydb_frame, frame, event, args):
+ return None
+
+def suspend(plugin, pydb, thread, frame):
+ return None
+
+def exception_break(plugin, pydb, pydb_frame, frame, args, arg):
+ return None \ No newline at end of file
diff --git a/python/helpers/pydev/pydevd_utils.py b/python/helpers/pydev/pydevd_utils.py
index 134b190881ac..753263ba4f31 100644
--- a/python/helpers/pydev/pydevd_utils.py
+++ b/python/helpers/pydev/pydevd_utils.py
@@ -6,7 +6,28 @@ except:
from urllib.parse import quote
import pydevd_constants
-import pydev_log
+import sys
+
+
+def save_main_module(file, module_name):
+ # patch provided by: Scott Schlesier - when script is run, it does not
+ # use globals from pydevd:
+ # This will prevent the pydevd script from contaminating the namespace for the script to be debugged
+ # pretend pydevd is not the main module, and
+ # convince the file to be debugged that it was loaded as main
+ sys.modules[module_name] = sys.modules['__main__']
+ sys.modules[module_name].__name__ = module_name
+ from imp import new_module
+
+ m = new_module('__main__')
+ sys.modules['__main__'] = m
+ if hasattr(sys.modules[module_name], '__loader__'):
+ setattr(m, '__loader__',
+ getattr(sys.modules[module_name], '__loader__'))
+ m.__file__ = file
+
+ return m
+
def to_number(x):
if is_string(x):
diff --git a/python/helpers/pydev/pydevd_vars.py b/python/helpers/pydev/pydevd_vars.py
index 3baea5b61b99..e1aa436b8946 100644
--- a/python/helpers/pydev/pydevd_vars.py
+++ b/python/helpers/pydev/pydevd_vars.py
@@ -2,7 +2,6 @@
resolution/conversion to XML.
"""
import pickle
-from django_frame import DjangoTemplateFrame
from pydevd_constants import * #@UnusedWildImport
from types import * #@UnusedWildImport
@@ -360,10 +359,10 @@ def changeAttrExpression(thread_id, frame_id, attr, expression):
try:
expression = expression.replace('@LINE@', '\n')
- if isinstance(frame, DjangoTemplateFrame):
- result = eval(expression, frame.f_globals, frame.f_locals)
- frame.changeVariable(attr, result)
- return
+ # if isinstance(frame, DjangoTemplateFrame): # TODO: implemente for plugins
+ # result = eval(expression, frame.f_globals, frame.f_locals)
+ # frame.changeVariable(attr, result)
+ # return result
if attr[:7] == "Globals":
attr = attr[8:]
@@ -374,7 +373,7 @@ def changeAttrExpression(thread_id, frame_id, attr, expression):
if pydevd_save_locals.is_save_locals_available():
frame.f_locals[attr] = eval(expression, frame.f_globals, frame.f_locals)
pydevd_save_locals.save_locals(frame)
- return
+ return frame.f_locals[attr]
#default way (only works for changing it in the topmost frame)
result = eval(expression, frame.f_globals, frame.f_locals)
diff --git a/python/helpers/pydev/test_debug.py b/python/helpers/pydev/test_debug.py
index 2196ca6f9540..27da09b5593d 100644
--- a/python/helpers/pydev/test_debug.py
+++ b/python/helpers/pydev/test_debug.py
@@ -5,16 +5,18 @@ import os
test_data_path = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', '..', 'testData', 'debug'))
+
class PyDevTestCase(unittest.TestCase):
def testZipFileExits(self):
from pydevd_file_utils import exists
- self.assertTrue(exists(test_data_path +'/zipped_lib.zip/zipped_module.py'))
+ self.assertTrue(exists(test_data_path + '/zipped_lib.zip/zipped_module.py'))
self.assertFalse(exists(test_data_path + '/zipped_lib.zip/zipped_module2.py'))
self.assertFalse(exists(test_data_path + '/zipped_lib2.zip/zipped_module.py'))
def testEggFileExits(self):
from pydevd_file_utils import exists
+
self.assertTrue(exists(test_data_path + '/pycharm-debug.egg/pydev/pydevd.py'))
self.assertFalse(exists(test_data_path + '/pycharm-debug.egg/pydev/pydevd2.py'))
diff --git a/python/helpers/pydev/tests/check_pydevconsole.py b/python/helpers/pydev/tests/check_pydevconsole.py
new file mode 100644
index 000000000000..0ff1a8618a24
--- /dev/null
+++ b/python/helpers/pydev/tests/check_pydevconsole.py
@@ -0,0 +1,110 @@
+import sys
+import os
+
+# Put pydevconsole in the path.
+sys.argv[0] = os.path.dirname(sys.argv[0])
+sys.path.insert(1, os.path.join(os.path.dirname(sys.argv[0])))
+
+print('Running tests with:', sys.executable)
+print('PYTHONPATH:')
+print('\n'.join(sorted(sys.path)))
+
+import threading
+import unittest
+
+import pydevconsole
+from pydev_imports import xmlrpclib, SimpleXMLRPCServer
+
+try:
+ raw_input
+ raw_input_name = 'raw_input'
+except NameError:
+ raw_input_name = 'input'
+
+#=======================================================================================================================
+# Test
+#=======================================================================================================================
+class Test(unittest.TestCase):
+ def startClientThread(self, client_port):
+ class ClientThread(threading.Thread):
+ def __init__(self, client_port):
+ threading.Thread.__init__(self)
+ self.client_port = client_port
+
+ def run(self):
+ class HandleRequestInput:
+ def RequestInput(self):
+ return 'RequestInput: OK'
+
+ handle_request_input = HandleRequestInput()
+
+ import pydev_localhost
+
+ print('Starting client with:', pydev_localhost.get_localhost(), self.client_port)
+ client_server = SimpleXMLRPCServer((pydev_localhost.get_localhost(), self.client_port), logRequests=False)
+ client_server.register_function(handle_request_input.RequestInput)
+ client_server.serve_forever()
+
+ client_thread = ClientThread(client_port)
+ client_thread.setDaemon(True)
+ client_thread.start()
+ return client_thread
+
+
+ def getFreeAddresses(self):
+ import socket
+
+ s = socket.socket()
+ s.bind(('', 0))
+ port0 = s.getsockname()[1]
+
+ s1 = socket.socket()
+ s1.bind(('', 0))
+ port1 = s1.getsockname()[1]
+ s.close()
+ s1.close()
+ return port0, port1
+
+
+ def testServer(self):
+ client_port, server_port = self.getFreeAddresses()
+
+ class ServerThread(threading.Thread):
+ def __init__(self, client_port, server_port):
+ threading.Thread.__init__(self)
+ self.client_port = client_port
+ self.server_port = server_port
+
+ def run(self):
+ import pydev_localhost
+
+ print('Starting server with:', pydev_localhost.get_localhost(), self.server_port, self.client_port)
+ pydevconsole.StartServer(pydev_localhost.get_localhost(), self.server_port, self.client_port)
+
+ server_thread = ServerThread(client_port, server_port)
+ server_thread.setDaemon(True)
+ server_thread.start()
+
+ client_thread = self.startClientThread(client_port) #@UnusedVariable
+
+ import time
+
+ time.sleep(.3) #let's give it some time to start the threads
+
+ import pydev_localhost
+
+ server = xmlrpclib.Server('http://%s:%s' % (pydev_localhost.get_localhost(), server_port))
+ server.addExec("import sys; print('Running with: %s %s' % (sys.executable or sys.platform, sys.version))")
+ server.addExec('class Foo:')
+ server.addExec(' pass')
+ server.addExec('')
+ server.addExec('foo = Foo()')
+ server.addExec('a = %s()' % raw_input_name)
+ server.addExec('print (a)')
+
+#=======================================================================================================================
+# main
+#=======================================================================================================================
+if __name__ == '__main__':
+ unittest.main()
+
diff --git a/python/helpers/pydev/tests/test_pydev_ipython_010.py b/python/helpers/pydev/tests/test_pydev_ipython_010.py
new file mode 100644
index 000000000000..1822763d4b29
--- /dev/null
+++ b/python/helpers/pydev/tests/test_pydev_ipython_010.py
@@ -0,0 +1,80 @@
+# TODO: This test no longer works (check if it should be fixed or removed altogether).
+
+#import unittest
+#import sys
+#import os
+##make it as if we were executing from the directory above this one
+#sys.argv[0] = os.path.dirname(sys.argv[0])
+##twice the dirname to get the previous level from this file.
+#sys.path.insert(1, os.path.join(os.path.dirname(sys.argv[0])))
+#
+#from pydev_localhost import get_localhost
+#
+#
+#IS_JYTHON = sys.platform.find('java') != -1
+#
+##=======================================================================================================================
+## TestCase
+##=======================================================================================================================
+#class TestCase(unittest.TestCase):
+#
+# def setUp(self):
+# unittest.TestCase.setUp(self)
+#
+# def tearDown(self):
+# unittest.TestCase.tearDown(self)
+#
+# def testIPython(self):
+# try:
+# from pydev_ipython_console import PyDevFrontEnd
+# except:
+# if IS_JYTHON:
+# return
+# front_end = PyDevFrontEnd(get_localhost(), 0)
+#
+# front_end.input_buffer = 'if True:'
+# self.assert_(not front_end._on_enter())
+#
+# front_end.input_buffer = 'if True:\n' + \
+# front_end.continuation_prompt() + ' a = 10\n'
+# self.assert_(not front_end._on_enter())
+#
+#
+# front_end.input_buffer = 'if True:\n' + \
+# front_end.continuation_prompt() + ' a = 10\n\n'
+# self.assert_(front_end._on_enter())
+#
+#
+## front_end.input_buffer = ' print a'
+## self.assert_(not front_end._on_enter())
+## front_end.input_buffer = ''
+## self.assert_(front_end._on_enter())
+#
+#
+## front_end.input_buffer = 'a.'
+## front_end.complete_current_input()
+## front_end.input_buffer = 'if True:'
+## front_end._on_enter()
+# front_end.input_buffer = 'a = 30'
+# front_end._on_enter()
+# front_end.input_buffer = 'print a'
+# front_end._on_enter()
+# front_end.input_buffer = 'a?'
+# front_end._on_enter()
+# print front_end.complete('%')
+# print front_end.complete('%e')
+# print front_end.complete('cd c:/t')
+# print front_end.complete('cd c:/temp/')
+## front_end.input_buffer = 'print raw_input("press enter\\n")'
+## front_end._on_enter()
+##
+#
+##=======================================================================================================================
+## main
+##=======================================================================================================================
+#if __name__ == '__main__':
+# if sys.platform.find('java') == -1:
+# #IPython not available for Jython
+# unittest.main()
+# else:
+# print('not supported on Jython')
diff --git a/python/helpers/pydev/tests_python/_debugger_case_qthread3.py b/python/helpers/pydev/tests_python/_debugger_case_qthread3.py
index 22b0c91d7f13..9b326db7ccde 100644
--- a/python/helpers/pydev/tests_python/_debugger_case_qthread3.py
+++ b/python/helpers/pydev/tests_python/_debugger_case_qthread3.py
@@ -26,4 +26,5 @@ app = QtCore.QCoreApplication([])
runnable = Runnable()
QtCore.QThreadPool.globalInstance().start(runnable)
app.exec_()
+QtCore.QThreadPool.globalInstance().waitForDone()
print('TEST SUCEEDED!') \ No newline at end of file
diff --git a/python/helpers/pydev/third_party/pkgutil_old.py b/python/helpers/pydev/third_party/pkgutil_old.py
new file mode 100644
index 000000000000..ce072ec9ef75
--- /dev/null
+++ b/python/helpers/pydev/third_party/pkgutil_old.py
@@ -0,0 +1,591 @@
+"""Utilities to support packages."""
+
+# NOTE: This module must remain compatible with Python 2.3, as it is shared
+# by setuptools for distribution with Python 2.3 and up.
+
+import os
+import sys
+import imp
+import os.path
+from types import ModuleType
+
+__all__ = [
+ 'get_importer', 'iter_importers', 'get_loader', 'find_loader',
+ 'walk_packages', 'iter_modules', 'get_data',
+ 'ImpImporter', 'ImpLoader', 'read_code', 'extend_path',
+]
+
+def read_code(stream):
+ # This helper is needed in order for the PEP 302 emulation to
+ # correctly handle compiled files
+ import marshal
+
+ magic = stream.read(4)
+ if magic != imp.get_magic():
+ return None
+
+ stream.read(4) # Skip timestamp
+ return marshal.load(stream)
+
+
+def simplegeneric(func):
+ """Make a trivial single-dispatch generic function"""
+ registry = {}
+ def wrapper(*args, **kw):
+ ob = args[0]
+ try:
+ cls = ob.__class__
+ except AttributeError:
+ cls = type(ob)
+ try:
+ mro = cls.__mro__
+ except AttributeError:
+ try:
+ class cls(cls, object):
+ pass
+ mro = cls.__mro__[1:]
+ except TypeError:
+ mro = object, # must be an ExtensionClass or some such :(
+ for t in mro:
+ if t in registry:
+ return registry[t](*args, **kw)
+ else:
+ return func(*args, **kw)
+ try:
+ wrapper.__name__ = func.__name__
+ except (TypeError, AttributeError):
+ pass # Python 2.3 doesn't allow functions to be renamed
+
+ def register(typ, func=None):
+ if func is None:
+ return lambda f: register(typ, f)
+ registry[typ] = func
+ return func
+
+ wrapper.__dict__ = func.__dict__
+ wrapper.__doc__ = func.__doc__
+ wrapper.register = register
+ return wrapper
+
+
+def walk_packages(path=None, prefix='', onerror=None):
+ """Yields (module_loader, name, ispkg) for all modules recursively
+ on path, or, if path is None, all accessible modules.
+
+ 'path' should be either None or a list of paths to look for
+ modules in.
+
+ 'prefix' is a string to output on the front of every module name
+ on output.
+
+ Note that this function must import all *packages* (NOT all
+ modules!) on the given path, in order to access the __path__
+ attribute to find submodules.
+
+ 'onerror' is a function which gets called with one argument (the
+ name of the package which was being imported) if any exception
+ occurs while trying to import a package. If no onerror function is
+ supplied, ImportErrors are caught and ignored, while all other
+ exceptions are propagated, terminating the search.
+
+ Examples:
+
+ # list all modules python can access
+ walk_packages()
+
+ # list all submodules of ctypes
+ walk_packages(ctypes.__path__, ctypes.__name__+'.')
+ """
+
+ def seen(p, m={}):
+ if p in m:
+ return True
+ m[p] = True
+
+ for importer, name, ispkg in iter_modules(path, prefix):
+ yield importer, name, ispkg
+
+ if ispkg:
+ try:
+ __import__(name)
+ except ImportError:
+ if onerror is not None:
+ onerror(name)
+ except Exception:
+ if onerror is not None:
+ onerror(name)
+ else:
+ raise
+ else:
+ path = getattr(sys.modules[name], '__path__', None) or []
+
+ # don't traverse path items we've seen before
+ path = [p for p in path if not seen(p)]
+
+ for item in walk_packages(path, name+'.', onerror):
+ yield item
+
+
+def iter_modules(path=None, prefix=''):
+ """Yields (module_loader, name, ispkg) for all submodules on path,
+ or, if path is None, all top-level modules on sys.path.
+
+ 'path' should be either None or a list of paths to look for
+ modules in.
+
+ 'prefix' is a string to output on the front of every module name
+ on output.
+ """
+
+ if path is None:
+ importers = iter_importers()
+ else:
+ importers = map(get_importer, path)
+
+ yielded = {}
+ for i in importers:
+ for name, ispkg in iter_importer_modules(i, prefix):
+ if name not in yielded:
+ yielded[name] = 1
+ yield i, name, ispkg
+
+
+#@simplegeneric
+def iter_importer_modules(importer, prefix=''):
+ if not hasattr(importer, 'iter_modules'):
+ return []
+ return importer.iter_modules(prefix)
+
+iter_importer_modules = simplegeneric(iter_importer_modules)
+
+
+class ImpImporter:
+ """PEP 302 Importer that wraps Python's "classic" import algorithm
+
+ ImpImporter(dirname) produces a PEP 302 importer that searches that
+ directory. ImpImporter(None) produces a PEP 302 importer that searches
+ the current sys.path, plus any modules that are frozen or built-in.
+
+ Note that ImpImporter does not currently support being used by placement
+ on sys.meta_path.
+ """
+
+ def __init__(self, path=None):
+ self.path = path
+
+ def find_module(self, fullname, path=None):
+ # Note: we ignore 'path' argument since it is only used via meta_path
+ subname = fullname.split(".")[-1]
+ if subname != fullname and self.path is None:
+ return None
+ if self.path is None:
+ path = None
+ else:
+ path = [os.path.realpath(self.path)]
+ try:
+ file, filename, etc = imp.find_module(subname, path)
+ except ImportError:
+ return None
+ return ImpLoader(fullname, file, filename, etc)
+
+ def iter_modules(self, prefix=''):
+ if self.path is None or not os.path.isdir(self.path):
+ return
+
+ yielded = {}
+ import inspect
+ try:
+ filenames = os.listdir(self.path)
+ except OSError:
+ # ignore unreadable directories like import does
+ filenames = []
+ filenames.sort() # handle packages before same-named modules
+
+ for fn in filenames:
+ modname = inspect.getmodulename(fn)
+ if modname=='__init__' or modname in yielded:
+ continue
+
+ path = os.path.join(self.path, fn)
+ ispkg = False
+
+ if not modname and os.path.isdir(path) and '.' not in fn:
+ modname = fn
+ try:
+ dircontents = os.listdir(path)
+ except OSError:
+ # ignore unreadable directories like import does
+ dircontents = []
+ for fn in dircontents:
+ subname = inspect.getmodulename(fn)
+ if subname=='__init__':
+ ispkg = True
+ break
+ else:
+ continue # not a package
+
+ if modname and '.' not in modname:
+ yielded[modname] = 1
+ yield prefix + modname, ispkg
+
+
+class ImpLoader:
+ """PEP 302 Loader that wraps Python's "classic" import algorithm
+ """
+ code = source = None
+
+ def __init__(self, fullname, file, filename, etc):
+ self.file = file
+ self.filename = filename
+ self.fullname = fullname
+ self.etc = etc
+
+ def load_module(self, fullname):
+ self._reopen()
+ try:
+ mod = imp.load_module(fullname, self.file, self.filename, self.etc)
+ finally:
+ if self.file:
+ self.file.close()
+ # Note: we don't set __loader__ because we want the module to look
+ # normal; i.e. this is just a wrapper for standard import machinery
+ return mod
+
+ def get_data(self, pathname):
+ return open(pathname, "rb").read()
+
+ def _reopen(self):
+ if self.file and self.file.closed:
+ mod_type = self.etc[2]
+ if mod_type==imp.PY_SOURCE:
+ self.file = open(self.filename, 'rU')
+ elif mod_type in (imp.PY_COMPILED, imp.C_EXTENSION):
+ self.file = open(self.filename, 'rb')
+
+ def _fix_name(self, fullname):
+ if fullname is None:
+ fullname = self.fullname
+ elif fullname != self.fullname:
+ raise ImportError("Loader for module %s cannot handle "
+ "module %s" % (self.fullname, fullname))
+ return fullname
+
+ def is_package(self, fullname):
+ fullname = self._fix_name(fullname)
+ return self.etc[2]==imp.PKG_DIRECTORY
+
+ def get_code(self, fullname=None):
+ fullname = self._fix_name(fullname)
+ if self.code is None:
+ mod_type = self.etc[2]
+ if mod_type==imp.PY_SOURCE:
+ source = self.get_source(fullname)
+ self.code = compile(source, self.filename, 'exec')
+ elif mod_type==imp.PY_COMPILED:
+ self._reopen()
+ try:
+ self.code = read_code(self.file)
+ finally:
+ self.file.close()
+ elif mod_type==imp.PKG_DIRECTORY:
+ self.code = self._get_delegate().get_code()
+ return self.code
+
+ def get_source(self, fullname=None):
+ fullname = self._fix_name(fullname)
+ if self.source is None:
+ mod_type = self.etc[2]
+ if mod_type==imp.PY_SOURCE:
+ self._reopen()
+ try:
+ self.source = self.file.read()
+ finally:
+ self.file.close()
+ elif mod_type==imp.PY_COMPILED:
+ if os.path.exists(self.filename[:-1]):
+ f = open(self.filename[:-1], 'rU')
+ self.source = f.read()
+ f.close()
+ elif mod_type==imp.PKG_DIRECTORY:
+ self.source = self._get_delegate().get_source()
+ return self.source
+
+
+ def _get_delegate(self):
+ return ImpImporter(self.filename).find_module('__init__')
+
+ def get_filename(self, fullname=None):
+ fullname = self._fix_name(fullname)
+ mod_type = self.etc[2]
+ if self.etc[2]==imp.PKG_DIRECTORY:
+ return self._get_delegate().get_filename()
+ elif self.etc[2] in (imp.PY_SOURCE, imp.PY_COMPILED, imp.C_EXTENSION):
+ return self.filename
+ return None
+
+
+try:
+ import zipimport
+ from zipimport import zipimporter
+
+ def iter_zipimport_modules(importer, prefix=''):
+ dirlist = zipimport._zip_directory_cache[importer.archive].keys()
+ dirlist.sort()
+ _prefix = importer.prefix
+ plen = len(_prefix)
+ yielded = {}
+ import inspect
+ for fn in dirlist:
+ if not fn.startswith(_prefix):
+ continue
+
+ fn = fn[plen:].split(os.sep)
+
+ if len(fn)==2 and fn[1].startswith('__init__.py'):
+ if fn[0] not in yielded:
+ yielded[fn[0]] = 1
+ yield fn[0], True
+
+ if len(fn)!=1:
+ continue
+
+ modname = inspect.getmodulename(fn[0])
+ if modname=='__init__':
+ continue
+
+ if modname and '.' not in modname and modname not in yielded:
+ yielded[modname] = 1
+ yield prefix + modname, False
+
+ iter_importer_modules.register(zipimporter, iter_zipimport_modules)
+
+except ImportError:
+ pass
+
+
+def get_importer(path_item):
+ """Retrieve a PEP 302 importer for the given path item
+
+ The returned importer is cached in sys.path_importer_cache
+ if it was newly created by a path hook.
+
+ If there is no importer, a wrapper around the basic import
+ machinery is returned. This wrapper is never inserted into
+ the importer cache (None is inserted instead).
+
+ The cache (or part of it) can be cleared manually if a
+ rescan of sys.path_hooks is necessary.
+ """
+ try:
+ importer = sys.path_importer_cache[path_item]
+ except KeyError:
+ for path_hook in sys.path_hooks:
+ try:
+ importer = path_hook(path_item)
+ break
+ except ImportError:
+ pass
+ else:
+ importer = None
+ sys.path_importer_cache.setdefault(path_item, importer)
+
+ if importer is None:
+ try:
+ importer = ImpImporter(path_item)
+ except ImportError:
+ importer = None
+ return importer
+
+
+def iter_importers(fullname=""):
+ """Yield PEP 302 importers for the given module name
+
+ If fullname contains a '.', the importers will be for the package
+ containing fullname, otherwise they will be importers for sys.meta_path,
+ sys.path, and Python's "classic" import machinery, in that order. If
+ the named module is in a package, that package is imported as a side
+ effect of invoking this function.
+
+ Non PEP 302 mechanisms (e.g. the Windows registry) used by the
+ standard import machinery to find files in alternative locations
+ are partially supported, but are searched AFTER sys.path. Normally,
+ these locations are searched BEFORE sys.path, preventing sys.path
+ entries from shadowing them.
+
+ For this to cause a visible difference in behaviour, there must
+ be a module or package name that is accessible via both sys.path
+ and one of the non PEP 302 file system mechanisms. In this case,
+ the emulation will find the former version, while the builtin
+ import mechanism will find the latter.
+
+ Items of the following types can be affected by this discrepancy:
+ imp.C_EXTENSION, imp.PY_SOURCE, imp.PY_COMPILED, imp.PKG_DIRECTORY
+ """
+ if fullname.startswith('.'):
+ raise ImportError("Relative module names not supported")
+ if '.' in fullname:
+ # Get the containing package's __path__
+ pkg = '.'.join(fullname.split('.')[:-1])
+ if pkg not in sys.modules:
+ __import__(pkg)
+ path = getattr(sys.modules[pkg], '__path__', None) or []
+ else:
+ for importer in sys.meta_path:
+ yield importer
+ path = sys.path
+ for item in path:
+ yield get_importer(item)
+ if '.' not in fullname:
+ yield ImpImporter()
+
+def get_loader(module_or_name):
+ """Get a PEP 302 "loader" object for module_or_name
+
+ If the module or package is accessible via the normal import
+ mechanism, a wrapper around the relevant part of that machinery
+ is returned. Returns None if the module cannot be found or imported.
+ If the named module is not already imported, its containing package
+ (if any) is imported, in order to establish the package __path__.
+
+ This function uses iter_importers(), and is thus subject to the same
+ limitations regarding platform-specific special import locations such
+ as the Windows registry.
+ """
+ if module_or_name in sys.modules:
+ module_or_name = sys.modules[module_or_name]
+ if isinstance(module_or_name, ModuleType):
+ module = module_or_name
+ loader = getattr(module, '__loader__', None)
+ if loader is not None:
+ return loader
+ fullname = module.__name__
+ else:
+ fullname = module_or_name
+ return find_loader(fullname)
+
+def find_loader(fullname):
+ """Find a PEP 302 "loader" object for fullname
+
+ If fullname contains dots, path must be the containing package's __path__.
+ Returns None if the module cannot be found or imported. This function uses
+ iter_importers(), and is thus subject to the same limitations regarding
+ platform-specific special import locations such as the Windows registry.
+ """
+ for importer in iter_importers(fullname):
+ loader = importer.find_module(fullname)
+ if loader is not None:
+ return loader
+
+ return None
+
+
+def extend_path(path, name):
+ """Extend a package's path.
+
+ Intended use is to place the following code in a package's __init__.py:
+
+ from pkgutil import extend_path
+ __path__ = extend_path(__path__, __name__)
+
+ This will add to the package's __path__ all subdirectories of
+ directories on sys.path named after the package. This is useful
+ if one wants to distribute different parts of a single logical
+ package as multiple directories.
+
+ It also looks for *.pkg files beginning where * matches the name
+ argument. This feature is similar to *.pth files (see site.py),
+ except that it doesn't special-case lines starting with 'import'.
+ A *.pkg file is trusted at face value: apart from checking for
+ duplicates, all entries found in a *.pkg file are added to the
+ path, regardless of whether they are exist the filesystem. (This
+ is a feature.)
+
+ If the input path is not a list (as is the case for frozen
+ packages) it is returned unchanged. The input path is not
+ modified; an extended copy is returned. Items are only appended
+ to the copy at the end.
+
+ It is assumed that sys.path is a sequence. Items of sys.path that
+ are not (unicode or 8-bit) strings referring to existing
+ directories are ignored. Unicode items of sys.path that cause
+ errors when used as filenames may cause this function to raise an
+ exception (in line with os.path.isdir() behavior).
+ """
+
+ if not isinstance(path, list):
+ # This could happen e.g. when this is called from inside a
+ # frozen package. Return the path unchanged in that case.
+ return path
+
+ pname = os.path.join(*name.split('.')) # Reconstitute as relative path
+ # Just in case os.extsep != '.'
+ sname = os.extsep.join(name.split('.'))
+ sname_pkg = sname + os.extsep + "pkg"
+ init_py = "__init__" + os.extsep + "py"
+
+ path = path[:] # Start with a copy of the existing path
+
+ for dir in sys.path:
+ if not isinstance(dir, basestring) or not os.path.isdir(dir):
+ continue
+ subdir = os.path.join(dir, pname)
+ # XXX This may still add duplicate entries to path on
+ # case-insensitive filesystems
+ initfile = os.path.join(subdir, init_py)
+ if subdir not in path and os.path.isfile(initfile):
+ path.append(subdir)
+ # XXX Is this the right thing for subpackages like zope.app?
+ # It looks for a file named "zope.app.pkg"
+ pkgfile = os.path.join(dir, sname_pkg)
+ if os.path.isfile(pkgfile):
+ try:
+ f = open(pkgfile)
+ except IOError, msg:
+ sys.stderr.write("Can't open %s: %s\n" %
+ (pkgfile, msg))
+ else:
+ for line in f:
+ line = line.rstrip('\n')
+ if not line or line.startswith('#'):
+ continue
+ path.append(line) # Don't check for existence!
+ f.close()
+
+ return path
+
+def get_data(package, resource):
+ """Get a resource from a package.
+
+ This is a wrapper round the PEP 302 loader get_data API. The package
+ argument should be the name of a package, in standard module format
+ (foo.bar). The resource argument should be in the form of a relative
+ filename, using '/' as the path separator. The parent directory name '..'
+ is not allowed, and nor is a rooted name (starting with a '/').
+
+ The function returns a binary string, which is the contents of the
+ specified resource.
+
+ For packages located in the filesystem, which have already been imported,
+ this is the rough equivalent of
+
+ d = os.path.dirname(sys.modules[package].__file__)
+ data = open(os.path.join(d, resource), 'rb').read()
+
+ If the package cannot be located or loaded, or it uses a PEP 302 loader
+ which does not support get_data(), then None is returned.
+ """
+
+ loader = get_loader(package)
+ if loader is None or not hasattr(loader, 'get_data'):
+ return None
+ mod = sys.modules.get(package) or loader.load_module(package)
+ if mod is None or not hasattr(mod, '__file__'):
+ return None
+
+ # Modify the resource name to be compatible with the loader.get_data
+ # signature - an os.path format "filename" starting with the dirname of
+ # the package's __file__
+ parts = resource.split('/')
+ parts.insert(0, os.path.dirname(mod.__file__))
+ resource_name = os.path.join(*parts)
+ return loader.get_data(resource_name)
diff --git a/python/helpers/pydev/third_party/pluginbase.py b/python/helpers/pydev/third_party/pluginbase.py
new file mode 100644
index 000000000000..0ad6404eee00
--- /dev/null
+++ b/python/helpers/pydev/third_party/pluginbase.py
@@ -0,0 +1,454 @@
+# -*- coding: utf-8 -*-
+"""
+ pluginbase
+ ~~~~~~~~~~
+
+ Pluginbase is a module for Python that provides a system for building
+ plugin based applications.
+
+ :copyright: (c) Copyright 2014 by Armin Ronacher.
+ :license: BSD, see LICENSE for more details.
+"""
+import os
+import sys
+
+from pydevd_constants import IS_PY24, IS_PY3K
+
+
+if IS_PY24:
+ from third_party.uuid_old import uuid4
+else:
+ from uuid import uuid4
+
+if IS_PY3K:
+ import pkgutil
+else:
+ import pkgutil_old as pkgutil
+
+import errno
+try:
+ from hashlib import md5
+except ImportError:
+ from md5 import md5
+import threading
+
+from types import ModuleType
+from weakref import ref as weakref
+
+
+PY2 = sys.version_info[0] == 2
+if PY2:
+ text_type = unicode
+ string_types = (unicode, str)
+ from cStringIO import StringIO as NativeBytesIO
+else:
+ text_type = str
+ string_types = (str,)
+ from io import BytesIO as NativeBytesIO
+
+
+_local = threading.local()
+
+_internalspace = ModuleType(__name__ + '._internalspace')
+_internalspace.__path__ = []
+sys.modules[_internalspace.__name__] = _internalspace
+
+
+def get_plugin_source(module=None, stacklevel=None):
+ """Returns the :class:`PluginSource` for the current module or the given
+ module. The module can be provided by name (in which case an import
+ will be attempted) or as a module object.
+
+ If no plugin source can be discovered, the return value from this method
+ is `None`.
+
+ This function can be very useful if additional data has been attached
+ to the plugin source. For instance this could allow plugins to get
+ access to a back reference to the application that created them.
+
+ :param module: optionally the module to locate the plugin source of.
+ :param stacklevel: defines how many levels up the module should search
+ for before it discovers the plugin frame. The
+ default is 0. This can be useful for writing wrappers
+ around this function.
+ """
+ if module is None:
+ frm = sys._getframe((stacklevel or 0) + 1)
+ name = frm.f_globals['__name__']
+ glob = frm.f_globals
+ elif isinstance(module, string_types):
+ frm = sys._getframe(1)
+ name = module
+ glob = __import__(module, frm.f_globals,
+ frm.f_locals, ['__dict__']).__dict__
+ else:
+ name = module.__name__
+ glob = module.__dict__
+ return _discover_space(name, glob)
+
+
+def _discover_space(name, globals):
+ try:
+ return _local.space_stack[-1]
+ except (AttributeError, IndexError):
+ pass
+
+ if '__pluginbase_state__' in globals:
+ return globals['__pluginbase_state__'].source
+
+ mod_name = globals.get('__name__')
+ if mod_name is not None and \
+ mod_name.startswith(_internalspace.__name__ + '.'):
+ end = mod_name.find('.', len(_internalspace.__name__) + 1)
+ space = sys.modules.get(mod_name[:end])
+ if space is not None:
+ return space.__pluginbase_state__.source
+
+
+def _shutdown_module(mod):
+ members = list(mod.__dict__.items())
+ for key, value in members:
+ if key[:1] != '_':
+ setattr(mod, key, None)
+ for key, value in members:
+ setattr(mod, key, None)
+
+
+def _to_bytes(s):
+ if isinstance(s, text_type):
+ return s.encode('utf-8')
+ return s
+
+
+class _IntentionallyEmptyModule(ModuleType):
+
+ def __getattr__(self, name):
+ try:
+ return ModuleType.__getattr__(self, name)
+ except AttributeError:
+ if name[:2] == '__':
+ raise
+ raise RuntimeError(
+ 'Attempted to import from a plugin base module (%s) without '
+ 'having a plugin source activated. To solve this error '
+ 'you have to move the import into a "with" block of the '
+ 'associated plugin source.' % self.__name__)
+
+
+class _PluginSourceModule(ModuleType):
+
+ def __init__(self, source):
+ modname = '%s.%s' % (_internalspace.__name__, source.spaceid)
+ ModuleType.__init__(self, modname)
+ self.__pluginbase_state__ = PluginBaseState(source)
+
+ @property
+ def __path__(self):
+ try:
+ ps = self.__pluginbase_state__.source
+ except AttributeError:
+ return []
+ return ps.searchpath + ps.base.searchpath
+
+
+def _setup_base_package(module_name):
+ try:
+ mod = __import__(module_name, None, None, ['__name__'])
+ except ImportError:
+ mod = None
+ if '.' in module_name:
+ parent_mod = __import__(module_name.rsplit('.', 1)[0],
+ None, None, ['__name__'])
+ else:
+ parent_mod = None
+
+ if mod is None:
+ mod = _IntentionallyEmptyModule(module_name)
+ if parent_mod is not None:
+ setattr(parent_mod, module_name.rsplit('.', 1)[-1], mod)
+ sys.modules[module_name] = mod
+
+
+class PluginBase(object):
+ """The plugin base acts as a control object around a dummy Python
+ package that acts as a container for plugins. Usually each
+ application creates exactly one base object for all plugins.
+
+ :param package: the name of the package that acts as the plugin base.
+ Usually this module does not exist. Unless you know
+ what you are doing you should not create this module
+ on the file system.
+ :param searchpath: optionally a shared search path for modules that
+ will be used by all plugin sources registered.
+ """
+
+ def __init__(self, package, searchpath=None):
+ #: the name of the dummy package.
+ self.package = package
+ if searchpath is None:
+ searchpath = []
+ #: the default search path shared by all plugins as list.
+ self.searchpath = searchpath
+ _setup_base_package(package)
+
+ def make_plugin_source(self, *args, **kwargs):
+ """Creats a plugin source for this plugin base and returns it.
+ All parameters are forwarded to :class:`PluginSource`.
+ """
+ return PluginSource(self, *args, **kwargs)
+
+
+class PluginSource(object):
+ """The plugin source is what ultimately decides where plugins are
+ loaded from. Plugin bases can have multiple plugin sources which act
+ as isolation layer. While this is not a security system it generally
+ is not possible for plugins from different sources to accidentally
+ cross talk.
+
+ Once a plugin source has been created it can be used in a ``with``
+ statement to change the behavior of the ``import`` statement in the
+ block to define which source to load the plugins from::
+
+ plugin_source = plugin_base.make_plugin_source(
+ searchpath=['./path/to/plugins', './path/to/more/plugins'])
+
+ with plugin_source:
+ from myapplication.plugins import my_plugin
+
+ :param base: the base this plugin source belongs to.
+ :param identifier: optionally a stable identifier. If it's not defined
+ a random identifier is picked. It's useful to set this
+ to a stable value to have consistent tracebacks
+ between restarts and to support pickle.
+ :param searchpath: a list of paths where plugins are looked for.
+ :param persist: optionally this can be set to `True` and the plugins
+ will not be cleaned up when the plugin source gets
+ garbage collected.
+ """
+ # Set these here to false by default so that a completely failing
+ # constructor does not fuck up the destructor.
+ persist = False
+ mod = None
+
+ def __init__(self, base, identifier=None, searchpath=None,
+ persist=False):
+ #: indicates if this plugin source persists or not.
+ self.persist = persist
+ if identifier is None:
+ identifier = str(uuid4())
+ #: the identifier for this source.
+ self.identifier = identifier
+ #: A reference to the plugin base that created this source.
+ self.base = base
+ #: a list of paths where plugins are searched in.
+ self.searchpath = searchpath
+ #: The internal module name of the plugin source as it appears
+ #: in the :mod:`pluginsource._internalspace`.
+ div = None
+ self.spaceid = '_sp' + md5(
+ _to_bytes(self.base.package) + _to_bytes('|') +
+ _to_bytes(self.identifier)
+ ).hexdigest()
+ #: a reference to the module on the internal
+ #: :mod:`pluginsource._internalspace`.
+ self.mod = _PluginSourceModule(self)
+
+ if hasattr(_internalspace, self.spaceid):
+ raise RuntimeError('This plugin source already exists.')
+ sys.modules[self.mod.__name__] = self.mod
+ setattr(_internalspace, self.spaceid, self.mod)
+
+ def __del__(self):
+ if not self.persist:
+ self.cleanup()
+
+ def list_plugins(self):
+ """Returns a sorted list of all plugins that are available in this
+ plugin source. This can be useful to automatically discover plugins
+ that are available and is usually used together with
+ :meth:`load_plugin`.
+ """
+ rv = []
+ for _, modname, ispkg in pkgutil.iter_modules(self.mod.__path__):
+ rv.append(modname)
+ return sorted(rv)
+
+ def load_plugin(self, name):
+ """This automatically loads a plugin by the given name from the
+ current source and returns the module. This is a convenient
+ alternative to the import statement and saves you from invoking
+ ``__import__`` or a similar function yourself.
+
+ :param name: the name of the plugin to load.
+ """
+ if '.' in name:
+ raise ImportError('Plugin names cannot contain dots.')
+
+ #with self:
+ # return __import__(self.base.package + '.' + name,
+ # globals(), {}, ['__name__'])
+
+ self.__assert_not_cleaned_up()
+ _local.__dict__.setdefault('space_stack', []).append(self)
+ try:
+ res = __import__(self.base.package + '.' + name,
+ globals(), {}, ['__name__'])
+ return res
+ finally:
+ try:
+ _local.space_stack.pop()
+ except (AttributeError, IndexError):
+ pass
+
+ def open_resource(self, plugin, filename):
+ """This function locates a resource inside the plugin and returns
+ a byte stream to the contents of it. If the resource cannot be
+ loaded an :exc:`IOError` will be raised. Only plugins that are
+ real Python packages can contain resources. Plain old Python
+ modules do not allow this for obvious reasons.
+
+ .. versionadded:: 0.3
+
+ :param plugin: the name of the plugin to open the resource of.
+ :param filename: the name of the file within the plugin to open.
+ """
+ mod = self.load_plugin(plugin)
+ fn = getattr(mod, '__file__', None)
+ if fn is not None:
+ if fn.endswith(('.pyc', '.pyo')):
+ fn = fn[:-1]
+ if os.path.isfile(fn):
+ return open(os.path.join(os.path.dirname(fn), filename), 'rb')
+ buf = pkgutil.get_data(self.mod.__name__ + '.' + plugin, filename)
+ if buf is None:
+ raise IOError(errno.ENOEXITS, 'Could not find resource')
+ return NativeBytesIO(buf)
+
+ def cleanup(self):
+ """Cleans up all loaded plugins manually. This is necessary to
+ call only if :attr:`persist` is enabled. Otherwise this happens
+ automatically when the source gets garbage collected.
+ """
+ self.__cleanup()
+
+ def __cleanup(self, _sys=sys, _shutdown_module=_shutdown_module):
+ # The default parameters are necessary because this can be fired
+ # from the destructor and so late when the interpreter shuts down
+ # that these functions and modules might be gone.
+ if self.mod is None:
+ return
+ modname = self.mod.__name__
+ self.mod.__pluginbase_state__ = None
+ self.mod = None
+ try:
+ delattr(_internalspace, self.spaceid)
+ except AttributeError:
+ pass
+ prefix = modname + '.'
+ _sys.modules.pop(modname)
+ for key, value in list(_sys.modules.items()):
+ if not key.startswith(prefix):
+ continue
+ mod = _sys.modules.pop(key, None)
+ if mod is None:
+ continue
+ _shutdown_module(mod)
+
+ def __assert_not_cleaned_up(self):
+ if self.mod is None:
+ raise RuntimeError('The plugin source was already cleaned up.')
+
+ def __enter__(self):
+ self.__assert_not_cleaned_up()
+ _local.__dict__.setdefault('space_stack', []).append(self)
+ return self
+
+ def __exit__(self, exc_type, exc_value, tb):
+ try:
+ _local.space_stack.pop()
+ except (AttributeError, IndexError):
+ pass
+
+ def _rewrite_module_path(self, modname):
+ self.__assert_not_cleaned_up()
+ if modname == self.base.package:
+ return self.mod.__name__
+ elif modname.startswith(self.base.package + '.'):
+ pieces = modname.split('.')
+ return self.mod.__name__ + '.' + '.'.join(
+ pieces[self.base.package.count('.') + 1:])
+
+
+class PluginBaseState(object):
+ __slots__ = ('_source',)
+
+ def __init__(self, source):
+ if source.persist:
+ self._source = lambda: source
+ else:
+ self._source = weakref(source)
+
+ @property
+ def source(self):
+ rv = self._source()
+ if rv is None:
+ raise AttributeError('Plugin source went away')
+ return rv
+
+
+class _ImportHook(ModuleType):
+
+ def __init__(self, name, system_import):
+ ModuleType.__init__(self, name)
+ self._system_import = system_import
+ self.enabled = True
+
+ def enable(self):
+ """Enables the import hook which drives the plugin base system.
+ This is the default.
+ """
+ self.enabled = True
+
+ def disable(self):
+ """Disables the import hook and restores the default import system
+ behavior. This effectively breaks pluginbase but can be useful
+ for testing purposes.
+ """
+ self.enabled = False
+
+ def plugin_import(self, name, globals=None, locals=None,
+ fromlist=None, level=-2):
+ import_name = name
+ if self.enabled:
+ ref_globals = globals
+ if ref_globals is None:
+ ref_globals = sys._getframe(1).f_globals
+ space = _discover_space(name, ref_globals)
+ if space is not None:
+ actual_name = space._rewrite_module_path(name)
+ if actual_name is not None:
+ import_name = actual_name
+ if level == -2:
+ # fake impossible value; default value depends on version
+ if IS_PY24:
+ # the level parameter was added in version 2.5
+ return self._system_import(import_name, globals, locals, fromlist)
+ elif IS_PY3K:
+ # default value for level parameter in python 3
+ level = 0
+ else:
+ # default value for level parameter in other versions
+ level = -1
+ return self._system_import(import_name, globals, locals,
+ fromlist, level)
+
+
+try:
+ import __builtin__ as builtins
+except ImportError:
+ import builtins
+
+import_hook = _ImportHook(__name__ + '.import_hook', builtins.__import__)
+builtins.__import__ = import_hook.plugin_import
+sys.modules[import_hook.__name__] = import_hook
+del builtins
diff --git a/python/helpers/pydev/third_party/uuid_old.py b/python/helpers/pydev/third_party/uuid_old.py
new file mode 100644
index 000000000000..ae3da25ca557
--- /dev/null
+++ b/python/helpers/pydev/third_party/uuid_old.py
@@ -0,0 +1,541 @@
+r"""UUID objects (universally unique identifiers) according to RFC 4122.
+
+This module provides immutable UUID objects (class UUID) and the functions
+uuid1(), uuid3(), uuid4(), uuid5() for generating version 1, 3, 4, and 5
+UUIDs as specified in RFC 4122.
+
+If all you want is a unique ID, you should probably call uuid1() or uuid4().
+Note that uuid1() may compromise privacy since it creates a UUID containing
+the computer's network address. uuid4() creates a random UUID.
+
+Typical usage:
+
+ >>> import uuid
+
+ # make a UUID based on the host ID and current time
+ >>> uuid.uuid1()
+ UUID('a8098c1a-f86e-11da-bd1a-00112444be1e')
+
+ # make a UUID using an MD5 hash of a namespace UUID and a name
+ >>> uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org')
+ UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e')
+
+ # make a random UUID
+ >>> uuid.uuid4()
+ UUID('16fd2706-8baf-433b-82eb-8c7fada847da')
+
+ # make a UUID using a SHA-1 hash of a namespace UUID and a name
+ >>> uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org')
+ UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d')
+
+ # make a UUID from a string of hex digits (braces and hyphens ignored)
+ >>> x = uuid.UUID('{00010203-0405-0607-0809-0a0b0c0d0e0f}')
+
+ # convert a UUID to a string of hex digits in standard form
+ >>> str(x)
+ '00010203-0405-0607-0809-0a0b0c0d0e0f'
+
+ # get the raw 16 bytes of the UUID
+ >>> x.bytes
+ '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f'
+
+ # make a UUID from a 16-byte string
+ >>> uuid.UUID(bytes=x.bytes)
+ UUID('00010203-0405-0607-0809-0a0b0c0d0e0f')
+"""
+
+__author__ = 'Ka-Ping Yee <ping@zesty.ca>'
+
+RESERVED_NCS, RFC_4122, RESERVED_MICROSOFT, RESERVED_FUTURE = [
+ 'reserved for NCS compatibility', 'specified in RFC 4122',
+ 'reserved for Microsoft compatibility', 'reserved for future definition']
+
+class UUID(object):
+ """Instances of the UUID class represent UUIDs as specified in RFC 4122.
+ UUID objects are immutable, hashable, and usable as dictionary keys.
+ Converting a UUID to a string with str() yields something in the form
+ '12345678-1234-1234-1234-123456789abc'. The UUID constructor accepts
+ five possible forms: a similar string of hexadecimal digits, or a tuple
+ of six integer fields (with 32-bit, 16-bit, 16-bit, 8-bit, 8-bit, and
+ 48-bit values respectively) as an argument named 'fields', or a string
+ of 16 bytes (with all the integer fields in big-endian order) as an
+ argument named 'bytes', or a string of 16 bytes (with the first three
+ fields in little-endian order) as an argument named 'bytes_le', or a
+ single 128-bit integer as an argument named 'int'.
+
+ UUIDs have these read-only attributes:
+
+ bytes the UUID as a 16-byte string (containing the six
+ integer fields in big-endian byte order)
+
+ bytes_le the UUID as a 16-byte string (with time_low, time_mid,
+ and time_hi_version in little-endian byte order)
+
+ fields a tuple of the six integer fields of the UUID,
+ which are also available as six individual attributes
+ and two derived attributes:
+
+ time_low the first 32 bits of the UUID
+ time_mid the next 16 bits of the UUID
+ time_hi_version the next 16 bits of the UUID
+ clock_seq_hi_variant the next 8 bits of the UUID
+ clock_seq_low the next 8 bits of the UUID
+ node the last 48 bits of the UUID
+
+ time the 60-bit timestamp
+ clock_seq the 14-bit sequence number
+
+ hex the UUID as a 32-character hexadecimal string
+
+ int the UUID as a 128-bit integer
+
+ urn the UUID as a URN as specified in RFC 4122
+
+ variant the UUID variant (one of the constants RESERVED_NCS,
+ RFC_4122, RESERVED_MICROSOFT, or RESERVED_FUTURE)
+
+ version the UUID version number (1 through 5, meaningful only
+ when the variant is RFC_4122)
+ """
+
+ def __init__(self, hex=None, bytes=None, bytes_le=None, fields=None,
+ int=None, version=None):
+ r"""Create a UUID from either a string of 32 hexadecimal digits,
+ a string of 16 bytes as the 'bytes' argument, a string of 16 bytes
+ in little-endian order as the 'bytes_le' argument, a tuple of six
+ integers (32-bit time_low, 16-bit time_mid, 16-bit time_hi_version,
+ 8-bit clock_seq_hi_variant, 8-bit clock_seq_low, 48-bit node) as
+ the 'fields' argument, or a single 128-bit integer as the 'int'
+ argument. When a string of hex digits is given, curly braces,
+ hyphens, and a URN prefix are all optional. For example, these
+ expressions all yield the same UUID:
+
+ UUID('{12345678-1234-5678-1234-567812345678}')
+ UUID('12345678123456781234567812345678')
+ UUID('urn:uuid:12345678-1234-5678-1234-567812345678')
+ UUID(bytes='\x12\x34\x56\x78'*4)
+ UUID(bytes_le='\x78\x56\x34\x12\x34\x12\x78\x56' +
+ '\x12\x34\x56\x78\x12\x34\x56\x78')
+ UUID(fields=(0x12345678, 0x1234, 0x5678, 0x12, 0x34, 0x567812345678))
+ UUID(int=0x12345678123456781234567812345678)
+
+ Exactly one of 'hex', 'bytes', 'bytes_le', 'fields', or 'int' must
+ be given. The 'version' argument is optional; if given, the resulting
+ UUID will have its variant and version set according to RFC 4122,
+ overriding the given 'hex', 'bytes', 'bytes_le', 'fields', or 'int'.
+ """
+
+ if [hex, bytes, bytes_le, fields, int].count(None) != 4:
+ raise TypeError('need one of hex, bytes, bytes_le, fields, or int')
+ if hex is not None:
+ hex = hex.replace('urn:', '').replace('uuid:', '')
+ hex = hex.strip('{}').replace('-', '')
+ if len(hex) != 32:
+ raise ValueError('badly formed hexadecimal UUID string')
+ int = long(hex, 16)
+ if bytes_le is not None:
+ if len(bytes_le) != 16:
+ raise ValueError('bytes_le is not a 16-char string')
+ bytes = (bytes_le[3] + bytes_le[2] + bytes_le[1] + bytes_le[0] +
+ bytes_le[5] + bytes_le[4] + bytes_le[7] + bytes_le[6] +
+ bytes_le[8:])
+ if bytes is not None:
+ if len(bytes) != 16:
+ raise ValueError('bytes is not a 16-char string')
+ int = long(('%02x'*16) % tuple(map(ord, bytes)), 16)
+ if fields is not None:
+ if len(fields) != 6:
+ raise ValueError('fields is not a 6-tuple')
+ (time_low, time_mid, time_hi_version,
+ clock_seq_hi_variant, clock_seq_low, node) = fields
+ if not 0 <= time_low < 1<<32L:
+ raise ValueError('field 1 out of range (need a 32-bit value)')
+ if not 0 <= time_mid < 1<<16L:
+ raise ValueError('field 2 out of range (need a 16-bit value)')
+ if not 0 <= time_hi_version < 1<<16L:
+ raise ValueError('field 3 out of range (need a 16-bit value)')
+ if not 0 <= clock_seq_hi_variant < 1<<8L:
+ raise ValueError('field 4 out of range (need an 8-bit value)')
+ if not 0 <= clock_seq_low < 1<<8L:
+ raise ValueError('field 5 out of range (need an 8-bit value)')
+ if not 0 <= node < 1<<48L:
+ raise ValueError('field 6 out of range (need a 48-bit value)')
+ clock_seq = (clock_seq_hi_variant << 8L) | clock_seq_low
+ int = ((time_low << 96L) | (time_mid << 80L) |
+ (time_hi_version << 64L) | (clock_seq << 48L) | node)
+ if int is not None:
+ if not 0 <= int < 1<<128L:
+ raise ValueError('int is out of range (need a 128-bit value)')
+ if version is not None:
+ if not 1 <= version <= 5:
+ raise ValueError('illegal version number')
+ # Set the variant to RFC 4122.
+ int &= ~(0xc000 << 48L)
+ int |= 0x8000 << 48L
+ # Set the version number.
+ int &= ~(0xf000 << 64L)
+ int |= version << 76L
+ self.__dict__['int'] = int
+
+ def __cmp__(self, other):
+ if isinstance(other, UUID):
+ return cmp(self.int, other.int)
+ return NotImplemented
+
+ def __hash__(self):
+ return hash(self.int)
+
+ def __int__(self):
+ return self.int
+
+ def __repr__(self):
+ return 'UUID(%r)' % str(self)
+
+ def __setattr__(self, name, value):
+ raise TypeError('UUID objects are immutable')
+
+ def __str__(self):
+ hex = '%032x' % self.int
+ return '%s-%s-%s-%s-%s' % (
+ hex[:8], hex[8:12], hex[12:16], hex[16:20], hex[20:])
+
+ def get_bytes(self):
+ bytes = ''
+ for shift in range(0, 128, 8):
+ bytes = chr((self.int >> shift) & 0xff) + bytes
+ return bytes
+
+ bytes = property(get_bytes)
+
+ def get_bytes_le(self):
+ bytes = self.bytes
+ return (bytes[3] + bytes[2] + bytes[1] + bytes[0] +
+ bytes[5] + bytes[4] + bytes[7] + bytes[6] + bytes[8:])
+
+ bytes_le = property(get_bytes_le)
+
+ def get_fields(self):
+ return (self.time_low, self.time_mid, self.time_hi_version,
+ self.clock_seq_hi_variant, self.clock_seq_low, self.node)
+
+ fields = property(get_fields)
+
+ def get_time_low(self):
+ return self.int >> 96L
+
+ time_low = property(get_time_low)
+
+ def get_time_mid(self):
+ return (self.int >> 80L) & 0xffff
+
+ time_mid = property(get_time_mid)
+
+ def get_time_hi_version(self):
+ return (self.int >> 64L) & 0xffff
+
+ time_hi_version = property(get_time_hi_version)
+
+ def get_clock_seq_hi_variant(self):
+ return (self.int >> 56L) & 0xff
+
+ clock_seq_hi_variant = property(get_clock_seq_hi_variant)
+
+ def get_clock_seq_low(self):
+ return (self.int >> 48L) & 0xff
+
+ clock_seq_low = property(get_clock_seq_low)
+
+ def get_time(self):
+ return (((self.time_hi_version & 0x0fffL) << 48L) |
+ (self.time_mid << 32L) | self.time_low)
+
+ time = property(get_time)
+
+ def get_clock_seq(self):
+ return (((self.clock_seq_hi_variant & 0x3fL) << 8L) |
+ self.clock_seq_low)
+
+ clock_seq = property(get_clock_seq)
+
+ def get_node(self):
+ return self.int & 0xffffffffffff
+
+ node = property(get_node)
+
+ def get_hex(self):
+ return '%032x' % self.int
+
+ hex = property(get_hex)
+
+ def get_urn(self):
+ return 'urn:uuid:' + str(self)
+
+ urn = property(get_urn)
+
+ def get_variant(self):
+ if not self.int & (0x8000 << 48L):
+ return RESERVED_NCS
+ elif not self.int & (0x4000 << 48L):
+ return RFC_4122
+ elif not self.int & (0x2000 << 48L):
+ return RESERVED_MICROSOFT
+ else:
+ return RESERVED_FUTURE
+
+ variant = property(get_variant)
+
+ def get_version(self):
+ # The version bits are only meaningful for RFC 4122 UUIDs.
+ if self.variant == RFC_4122:
+ return int((self.int >> 76L) & 0xf)
+
+ version = property(get_version)
+
+def _find_mac(command, args, hw_identifiers, get_index):
+ import os
+ for dir in ['', '/sbin/', '/usr/sbin']:
+ executable = os.path.join(dir, command)
+ if not os.path.exists(executable):
+ continue
+
+ try:
+ # LC_ALL to get English output, 2>/dev/null to
+ # prevent output on stderr
+ cmd = 'LC_ALL=C %s %s 2>/dev/null' % (executable, args)
+ pipe = os.popen(cmd)
+ except IOError:
+ continue
+
+ for line in pipe:
+ words = line.lower().split()
+ for i in range(len(words)):
+ if words[i] in hw_identifiers:
+ return int(words[get_index(i)].replace(':', ''), 16)
+ return None
+
+def _ifconfig_getnode():
+ """Get the hardware address on Unix by running ifconfig."""
+
+ # This works on Linux ('' or '-a'), Tru64 ('-av'), but not all Unixes.
+ for args in ('', '-a', '-av'):
+ mac = _find_mac('ifconfig', args, ['hwaddr', 'ether'], lambda i: i+1)
+ if mac:
+ return mac
+
+ import socket
+ ip_addr = socket.gethostbyname(socket.gethostname())
+
+ # Try getting the MAC addr from arp based on our IP address (Solaris).
+ mac = _find_mac('arp', '-an', [ip_addr], lambda i: -1)
+ if mac:
+ return mac
+
+ # This might work on HP-UX.
+ mac = _find_mac('lanscan', '-ai', ['lan0'], lambda i: 0)
+ if mac:
+ return mac
+
+ return None
+
+def _ipconfig_getnode():
+ """Get the hardware address on Windows by running ipconfig.exe."""
+ import os, re
+ dirs = ['', r'c:\windows\system32', r'c:\winnt\system32']
+ try:
+ import ctypes
+ buffer = ctypes.create_string_buffer(300)
+ ctypes.windll.kernel32.GetSystemDirectoryA(buffer, 300)
+ dirs.insert(0, buffer.value.decode('mbcs'))
+ except:
+ pass
+ for dir in dirs:
+ try:
+ pipe = os.popen(os.path.join(dir, 'ipconfig') + ' /all')
+ except IOError:
+ continue
+ for line in pipe:
+ value = line.split(':')[-1].strip().lower()
+ if re.match('([0-9a-f][0-9a-f]-){5}[0-9a-f][0-9a-f]', value):
+ return int(value.replace('-', ''), 16)
+
+def _netbios_getnode():
+ """Get the hardware address on Windows using NetBIOS calls.
+ See http://support.microsoft.com/kb/118623 for details."""
+ import win32wnet, netbios
+ ncb = netbios.NCB()
+ ncb.Command = netbios.NCBENUM
+ ncb.Buffer = adapters = netbios.LANA_ENUM()
+ adapters._pack()
+ if win32wnet.Netbios(ncb) != 0:
+ return
+ adapters._unpack()
+ for i in range(adapters.length):
+ ncb.Reset()
+ ncb.Command = netbios.NCBRESET
+ ncb.Lana_num = ord(adapters.lana[i])
+ if win32wnet.Netbios(ncb) != 0:
+ continue
+ ncb.Reset()
+ ncb.Command = netbios.NCBASTAT
+ ncb.Lana_num = ord(adapters.lana[i])
+ ncb.Callname = '*'.ljust(16)
+ ncb.Buffer = status = netbios.ADAPTER_STATUS()
+ if win32wnet.Netbios(ncb) != 0:
+ continue
+ status._unpack()
+ bytes = map(ord, status.adapter_address)
+ return ((bytes[0]<<40L) + (bytes[1]<<32L) + (bytes[2]<<24L) +
+ (bytes[3]<<16L) + (bytes[4]<<8L) + bytes[5])
+
+# Thanks to Thomas Heller for ctypes and for his help with its use here.
+
+# If ctypes is available, use it to find system routines for UUID generation.
+_uuid_generate_random = _uuid_generate_time = _UuidCreate = None
+try:
+ import ctypes, ctypes.util
+ _buffer = ctypes.create_string_buffer(16)
+
+ # The uuid_generate_* routines are provided by libuuid on at least
+ # Linux and FreeBSD, and provided by libc on Mac OS X.
+ for libname in ['uuid', 'c']:
+ try:
+ lib = ctypes.CDLL(ctypes.util.find_library(libname))
+ except:
+ continue
+ if hasattr(lib, 'uuid_generate_random'):
+ _uuid_generate_random = lib.uuid_generate_random
+ if hasattr(lib, 'uuid_generate_time'):
+ _uuid_generate_time = lib.uuid_generate_time
+
+ # On Windows prior to 2000, UuidCreate gives a UUID containing the
+ # hardware address. On Windows 2000 and later, UuidCreate makes a
+ # random UUID and UuidCreateSequential gives a UUID containing the
+ # hardware address. These routines are provided by the RPC runtime.
+ # NOTE: at least on Tim's WinXP Pro SP2 desktop box, while the last
+ # 6 bytes returned by UuidCreateSequential are fixed, they don't appear
+ # to bear any relationship to the MAC address of any network device
+ # on the box.
+ try:
+ lib = ctypes.windll.rpcrt4
+ except:
+ lib = None
+ _UuidCreate = getattr(lib, 'UuidCreateSequential',
+ getattr(lib, 'UuidCreate', None))
+except:
+ pass
+
+def _unixdll_getnode():
+ """Get the hardware address on Unix using ctypes."""
+ _uuid_generate_time(_buffer)
+ return UUID(bytes=_buffer.raw).node
+
+def _windll_getnode():
+ """Get the hardware address on Windows using ctypes."""
+ if _UuidCreate(_buffer) == 0:
+ return UUID(bytes=_buffer.raw).node
+
+def _random_getnode():
+ """Get a random node ID, with eighth bit set as suggested by RFC 4122."""
+ import random
+ return random.randrange(0, 1<<48L) | 0x010000000000L
+
+_node = None
+
+def getnode():
+ """Get the hardware address as a 48-bit positive integer.
+
+ The first time this runs, it may launch a separate program, which could
+ be quite slow. If all attempts to obtain the hardware address fail, we
+ choose a random 48-bit number with its eighth bit set to 1 as recommended
+ in RFC 4122.
+ """
+
+ global _node
+ if _node is not None:
+ return _node
+
+ import sys
+ if sys.platform == 'win32':
+ getters = [_windll_getnode, _netbios_getnode, _ipconfig_getnode]
+ else:
+ getters = [_unixdll_getnode, _ifconfig_getnode]
+
+ for getter in getters + [_random_getnode]:
+ try:
+ _node = getter()
+ except:
+ continue
+ if _node is not None:
+ return _node
+
+_last_timestamp = None
+
+def uuid1(node=None, clock_seq=None):
+ """Generate a UUID from a host ID, sequence number, and the current time.
+ If 'node' is not given, getnode() is used to obtain the hardware
+ address. If 'clock_seq' is given, it is used as the sequence number;
+ otherwise a random 14-bit sequence number is chosen."""
+
+ # When the system provides a version-1 UUID generator, use it (but don't
+ # use UuidCreate here because its UUIDs don't conform to RFC 4122).
+ if _uuid_generate_time and node is clock_seq is None:
+ _uuid_generate_time(_buffer)
+ return UUID(bytes=_buffer.raw)
+
+ global _last_timestamp
+ import time
+ nanoseconds = int(time.time() * 1e9)
+ # 0x01b21dd213814000 is the number of 100-ns intervals between the
+ # UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00.
+ timestamp = int(nanoseconds/100) + 0x01b21dd213814000L
+ if timestamp <= _last_timestamp:
+ timestamp = _last_timestamp + 1
+ _last_timestamp = timestamp
+ if clock_seq is None:
+ import random
+ clock_seq = random.randrange(1<<14L) # instead of stable storage
+ time_low = timestamp & 0xffffffffL
+ time_mid = (timestamp >> 32L) & 0xffffL
+ time_hi_version = (timestamp >> 48L) & 0x0fffL
+ clock_seq_low = clock_seq & 0xffL
+ clock_seq_hi_variant = (clock_seq >> 8L) & 0x3fL
+ if node is None:
+ node = getnode()
+ return UUID(fields=(time_low, time_mid, time_hi_version,
+ clock_seq_hi_variant, clock_seq_low, node), version=1)
+
+def uuid3(namespace, name):
+ """Generate a UUID from the MD5 hash of a namespace UUID and a name."""
+ import md5
+ hash = md5.md5(namespace.bytes + name).digest()
+ return UUID(bytes=hash[:16], version=3)
+
+def uuid4():
+ """Generate a random UUID."""
+
+ # When the system provides a version-4 UUID generator, use it.
+ if _uuid_generate_random:
+ _uuid_generate_random(_buffer)
+ return UUID(bytes=_buffer.raw)
+
+ # Otherwise, get randomness from urandom or the 'random' module.
+ try:
+ import os
+ return UUID(bytes=os.urandom(16), version=4)
+ except:
+ import random
+ bytes = [chr(random.randrange(256)) for i in range(16)]
+ return UUID(bytes=bytes, version=4)
+
+def uuid5(namespace, name):
+ """Generate a UUID from the SHA-1 hash of a namespace UUID and a name."""
+ import sha
+ hash = sha.sha(namespace.bytes + name).digest()
+ return UUID(bytes=hash[:16], version=5)
+
+# The following standard UUIDs are for use with uuid3() or uuid5().
+
+NAMESPACE_DNS = UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
+NAMESPACE_URL = UUID('6ba7b811-9dad-11d1-80b4-00c04fd430c8')
+NAMESPACE_OID = UUID('6ba7b812-9dad-11d1-80b4-00c04fd430c8')
+NAMESPACE_X500 = UUID('6ba7b814-9dad-11d1-80b4-00c04fd430c8')
diff --git a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java
index fc165b8893f6..38195d1380b9 100644
--- a/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java
+++ b/python/ide/src/com/jetbrains/python/configuration/PyActiveSdkConfigurable.java
@@ -298,14 +298,14 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable {
}
final Sdk prevSdk = ProjectRootManager.getInstance(myProject).getProjectSdk();
- final Sdk selectedSdk = setSdk(newSdk);
+ setSdk(newSdk);
// update string literals if different LanguageLevel was selected
- if (prevSdk != null && selectedSdk != null) {
- final PythonSdkFlavor flavor1 = PythonSdkFlavor.getFlavor(selectedSdk);
+ if (prevSdk != null && newSdk != null) {
+ final PythonSdkFlavor flavor1 = PythonSdkFlavor.getFlavor(newSdk);
final PythonSdkFlavor flavor2 = PythonSdkFlavor.getFlavor(prevSdk);
if (flavor1 != null && flavor2 != null) {
- final LanguageLevel languageLevel1 = flavor1.getLanguageLevel(selectedSdk);
+ final LanguageLevel languageLevel1 = flavor1.getLanguageLevel(newSdk);
final LanguageLevel languageLevel2 = flavor2.getLanguageLevel(prevSdk);
if ((languageLevel1.isPy3K() && languageLevel2.isPy3K()) ||
(!languageLevel1.isPy3K()) && !languageLevel2.isPy3K()) {
@@ -316,22 +316,20 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable {
rehighlightStrings(myProject);
}
- private Sdk setSdk(Sdk item) {
+ private void setSdk(final Sdk item) {
myAddedSdks.clear();
- final Sdk selectedSdk = myProjectSdksModel.findSdk(item);
if (myModule == null) {
final ProjectRootManager rootManager = ProjectRootManager.getInstance(myProject);
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
- rootManager.setProjectSdk(selectedSdk);
+ rootManager.setProjectSdk(item);
}
});
}
else {
- ModuleRootModificationUtil.setModuleSdk(myModule, selectedSdk);
+ ModuleRootModificationUtil.setModuleSdk(myModule, item);
}
- return selectedSdk;
}
public static void rehighlightStrings(final @NotNull Project project) {
@@ -429,8 +427,6 @@ public class PyActiveSdkConfigurable implements UnnamedConfigurable {
public void sdkAdded(Sdk sdk) {
final Object item = myConfigurable.mySdkCombo.getSelectedItem();
- myConfigurable.resetSdkList();
-
if (item instanceof PyDetectedSdk) {
final String path = ((PyDetectedSdk)item).getHomePath();
if (path != null && path.equals(sdk.getHomePath()))
diff --git a/python/ide/src/com/jetbrains/python/newProject/actions/AbstractProjectSettingsStep.java b/python/ide/src/com/jetbrains/python/newProject/actions/AbstractProjectSettingsStep.java
index 1ad9cf7ececc..6514741fda45 100644
--- a/python/ide/src/com/jetbrains/python/newProject/actions/AbstractProjectSettingsStep.java
+++ b/python/ide/src/com/jetbrains/python/newProject/actions/AbstractProjectSettingsStep.java
@@ -33,15 +33,11 @@ import com.jetbrains.python.configuration.PyConfigurableInterpreterList;
import com.jetbrains.python.configuration.VirtualEnvProjectFilter;
import com.jetbrains.python.newProject.PyFrameworkProjectGenerator;
import com.jetbrains.python.newProject.PythonProjectGenerator;
-import com.jetbrains.python.packaging.PyExternalProcessException;
-import com.jetbrains.python.packaging.PyPackage;
import com.jetbrains.python.packaging.PyPackageManager;
-import com.jetbrains.python.packaging.PyPackageManagerImpl;
+import com.jetbrains.python.sdk.PySdkUtil;
import com.jetbrains.python.sdk.PythonSdkType;
-import com.jetbrains.python.sdk.flavors.JythonSdkFlavor;
-import com.jetbrains.python.sdk.flavors.PyPySdkFlavor;
-import com.jetbrains.python.sdk.flavors.PythonSdkFlavor;
import icons.PythonIcons;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
@@ -79,22 +75,6 @@ abstract public class AbstractProjectSettingsStep extends AbstractActionWithPane
myCallback = callback;
myIsWelcomeScreen = isWelcomeScreen;
myProjectDirectory = FileUtil.findSequentNonexistentFile(new File(ProjectUtil.getBaseDir()), "untitled", "");
- if (myProjectGenerator instanceof WebProjectTemplate) {
- ((WebProjectTemplate)myProjectGenerator).getPeer().addSettingsStateListener(new WebProjectGenerator.SettingsStateListener() {
- @Override
- public void stateChanged(boolean validSettings) {
- checkValid();
- }
- });
- }
- else if (myProjectGenerator instanceof PythonProjectGenerator) {
- ((PythonProjectGenerator)myProjectGenerator).addSettingsStateListener(new PythonProjectGenerator.SettingsListener() {
- @Override
- public void stateChanged() {
- checkValid();
- }
- });
- }
myCreateAction = new AnAction("Create", "Create Project", getIcon()) {
@Override
@@ -112,6 +92,7 @@ abstract public class AbstractProjectSettingsStep extends AbstractActionWithPane
@Override
public JPanel createPanel() {
+ initGeneratorListeners();
final JPanel basePanel = createBasePanel();
final JPanel mainPanel = new JPanel(new BorderLayout());
@@ -142,6 +123,25 @@ abstract public class AbstractProjectSettingsStep extends AbstractActionWithPane
return mainPanel;
}
+ private void initGeneratorListeners() {
+ if (myProjectGenerator instanceof WebProjectTemplate) {
+ ((WebProjectTemplate)myProjectGenerator).getPeer().addSettingsStateListener(new WebProjectGenerator.SettingsStateListener() {
+ @Override
+ public void stateChanged(boolean validSettings) {
+ checkValid();
+ }
+ });
+ }
+ else if (myProjectGenerator instanceof PythonProjectGenerator) {
+ ((PythonProjectGenerator)myProjectGenerator).addSettingsStateListener(new PythonProjectGenerator.SettingsListener() {
+ @Override
+ public void stateChanged() {
+ checkValid();
+ }
+ });
+ }
+ }
+
protected Icon getIcon() {
return myProjectGenerator.getLogo();
}
@@ -319,29 +319,13 @@ abstract public class AbstractProjectSettingsStep extends AbstractActionWithPane
PyFrameworkProjectGenerator frameworkProjectGenerator = (PyFrameworkProjectGenerator)myProjectGenerator;
String frameworkName = frameworkProjectGenerator.getFrameworkTitle();
if (sdk != null && !isFrameworkInstalled(sdk)) {
- final PyPackageManagerImpl packageManager = (PyPackageManagerImpl)PyPackageManager.getInstance(sdk);
- final boolean onlyWithCache =
- PythonSdkFlavor.getFlavor(sdk) instanceof JythonSdkFlavor || PythonSdkFlavor.getFlavor(sdk) instanceof PyPySdkFlavor;
String warningText = frameworkName + " will be installed on selected interpreter";
- try {
- if (onlyWithCache && packageManager.cacheIsNotNull() || !onlyWithCache) {
- final PyPackage pip = packageManager.findInstalledPackage("pip");
- myInstallFramework = true;
- if (pip == null) {
- warningText = "pip and " + warningText;
- }
- setWarningText(warningText);
- }
- }
- catch (PyExternalProcessException ignored) {
- myInstallFramework = true;
- warningText = "pip and " + warningText;
- setWarningText(warningText);
- }
- if (!myInstallFramework) {
- setErrorText("No " + frameworkName + " support installed in selected interpreter");
- return false;
+ myInstallFramework = true;
+ final PyPackageManager packageManager = PyPackageManager.getInstance(sdk);
+ if (!packageManager.hasManagement(PySdkUtil.isRemote(sdk))) {
+ warningText = "Python packaging tools and " + warningText;
}
+ setWarningText(warningText);
}
if (isPy3k && !((PyFrameworkProjectGenerator)myProjectGenerator).supportsPython3()) {
setErrorText(frameworkName + " is not supported for the selected interpreter");
@@ -454,6 +438,10 @@ abstract public class AbstractProjectSettingsStep extends AbstractActionWithPane
return myLocationField.getText();
}
+ public void setLocation(@NotNull final String location) {
+ myLocationField.setText(location);
+ }
+
public boolean installFramework() {
return myInstallFramework;
}
diff --git a/python/ide/src/com/jetbrains/python/newProject/actions/GenerateProjectCallback.java b/python/ide/src/com/jetbrains/python/newProject/actions/GenerateProjectCallback.java
index 2aa9a391512f..2e88b7f2767c 100644
--- a/python/ide/src/com/jetbrains/python/newProject/actions/GenerateProjectCallback.java
+++ b/python/ide/src/com/jetbrains/python/newProject/actions/GenerateProjectCallback.java
@@ -104,7 +104,7 @@ public class GenerateProjectCallback implements NullableConsumer<AbstractProject
}
@Nullable
- private Project generateProject(@NotNull final Project project, @NotNull final AbstractProjectSettingsStep settings) {
+ private static Project generateProject(@NotNull final Project project, @NotNull final AbstractProjectSettingsStep settings) {
final DirectoryProjectGenerator generator = settings.getProjectGenerator();
final File location = new File(settings.getProjectLocation());
if (!location.exists() && !location.mkdirs()) {
diff --git a/python/openapi/src/com/jetbrains/python/documentation/PythonDocumentationQuickInfoProvider.java b/python/openapi/src/com/jetbrains/python/documentation/PythonDocumentationQuickInfoProvider.java
new file mode 100644
index 000000000000..52dc4732133c
--- /dev/null
+++ b/python/openapi/src/com/jetbrains/python/documentation/PythonDocumentationQuickInfoProvider.java
@@ -0,0 +1,25 @@
+package com.jetbrains.python.documentation;
+
+import com.intellij.openapi.extensions.ExtensionPointName;
+import com.intellij.psi.PsiElement;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Allows you to inject quick info into python documentation provider
+ *
+ * @author Ilya.Kazakevich
+ */
+public interface PythonDocumentationQuickInfoProvider {
+ ExtensionPointName<PythonDocumentationQuickInfoProvider> EP_NAME =
+ ExtensionPointName.create("Pythonid.pythonDocumentationQuickInfoProvider");
+
+ /**
+ * Return quick info for <strong>original</strong> element.
+ *
+ * @param originalElement original element
+ * @return info (if exists) or null (if another provider should be checked)
+ */
+ @Nullable
+ String getQuickInfo(@NotNull PsiElement originalElement);
+}
diff --git a/python/openapi/src/com/jetbrains/python/packaging/PyPackageManager.java b/python/openapi/src/com/jetbrains/python/packaging/PyPackageManager.java
index 3b2080b00ba1..2a8003c46eaf 100644
--- a/python/openapi/src/com/jetbrains/python/packaging/PyPackageManager.java
+++ b/python/openapi/src/com/jetbrains/python/packaging/PyPackageManager.java
@@ -15,35 +15,45 @@
*/
package com.jetbrains.python.packaging;
-import com.intellij.openapi.project.Project;
+import com.intellij.openapi.module.Module;
import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.util.Key;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import java.awt.*;
+import java.util.List;
+import java.util.Set;
/**
* @author yole
*/
public abstract class PyPackageManager {
+ public static final Key<Boolean> RUNNING_PACKAGING_TASKS = Key.create("PyPackageRequirementsInspection.RunningPackagingTasks");
+
+ public static final String PACKAGE_SETUPTOOLS = "setuptools";
+ public static final String PACKAGE_PIP = "pip";
+ public static final String PACKAGE_DISTRIBUTE = "distribute";
+
+ public static final String USE_USER_SITE = "--user";
+
public static PyPackageManager getInstance(Sdk sdk) {
return PyPackageManagers.getInstance().forSdk(sdk);
}
- /**
- * Returns true if pip is installed for the specific interpreter; returns false if pip is not
- * installed or if it is not currently known whether it's installed (e.g. for a remote interpreter).
- *
- * @return true if pip is known to be installed, false otherwise.
- */
- public abstract boolean hasPip();
- public abstract void install(String requirementString) throws PyExternalProcessException;
- public abstract void showInstallationError(Project project, String title, String description);
- public abstract void showInstallationError(Component owner, String title, String description);
+ public abstract void installManagement() throws PyExternalProcessException;
+ public abstract boolean hasManagement(boolean cachedOnly);
+ public abstract void install(@NotNull String requirementString) throws PyExternalProcessException;
+ public abstract void install(@NotNull List<PyRequirement> requirements, @NotNull List<String> extraArgs) throws PyExternalProcessException;
+ public abstract void uninstall(@NotNull List<PyPackage> packages) throws PyExternalProcessException;
public abstract void refresh();
+ @NotNull
+ public abstract String createVirtualEnv(@NotNull String destinationDir, boolean useGlobalSite) throws PyExternalProcessException;
@Nullable
- public abstract PyPackage findInstalledPackage(String name) throws PyExternalProcessException;
-
- public abstract boolean findPackage(@NotNull final String name);
-
+ public abstract List<PyPackage> getPackages(boolean cachedOnly) throws PyExternalProcessException;
+ @Nullable
+ public abstract PyPackage findPackage(@NotNull String name, boolean cachedOnly) throws PyExternalProcessException;
+ @Nullable
+ public abstract List<PyRequirement> getRequirements(@NotNull Module module);
+ @Nullable
+ public abstract Set<PyPackage> getDependents(@NotNull PyPackage pkg) throws PyExternalProcessException;
}
diff --git a/python/openapi/src/com/jetbrains/python/packaging/PyPackageManagers.java b/python/openapi/src/com/jetbrains/python/packaging/PyPackageManagers.java
index 9f598748aa7b..2b6554040fe7 100644
--- a/python/openapi/src/com/jetbrains/python/packaging/PyPackageManagers.java
+++ b/python/openapi/src/com/jetbrains/python/packaging/PyPackageManagers.java
@@ -16,12 +16,8 @@
package com.jetbrains.python.packaging;
import com.intellij.openapi.components.ServiceManager;
-import com.intellij.openapi.module.Module;
import com.intellij.openapi.projectRoots.Sdk;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.List;
/**
* @author yole
@@ -35,22 +31,4 @@ public abstract class PyPackageManagers {
@NotNull
public abstract PyPackageManager forSdk(Sdk sdk);
-
- /**
- * Returns the list of requirements from 'requirements.txt' or 'setup.py' files in the specified module.
- *
- * @param module the module to check for requirements
- * @return the list of requirements, or null if the module contains neither requirements.txt nor setup.py.
- */
- @Nullable
- public abstract List<PyRequirement> getRequirements(Module module);
-
- /**
- * Returns the list of requirements from 'requirements.txt' file in the specified module.
- *
- * @param module the module to check for requirements
- * @return the list of requirements, or null if the module does not contain a requirements.txt
- */
- @Nullable
- public abstract List<PyRequirement> getRequirementsFromTxt(Module module);
}
diff --git a/python/openapi/src/com/jetbrains/python/templateLanguages/PyTemplatesUtil.java b/python/openapi/src/com/jetbrains/python/templateLanguages/PyTemplatesUtil.java
index e660029fe384..c37c65ed4144 100644
--- a/python/openapi/src/com/jetbrains/python/templateLanguages/PyTemplatesUtil.java
+++ b/python/openapi/src/com/jetbrains/python/templateLanguages/PyTemplatesUtil.java
@@ -40,7 +40,7 @@ public class PyTemplatesUtil {
if (templateBinding != null) {
if (TemplatesService.ALL_TEMPLATE_BINDINGS.contains(templateBinding)) {
try {
- final PyPackage installedPackage = packageManager.findInstalledPackage(templateBinding);
+ final PyPackage installedPackage = packageManager.findPackage(templateBinding, false);
if (installedPackage == null)
return new ValidationResult(templateBinding + " will be installed on selected interpreter");
}
@@ -50,7 +50,7 @@ public class PyTemplatesUtil {
}
if (language != null) {
try {
- final PyPackage installedPackage = packageManager.findInstalledPackage(language);
+ final PyPackage installedPackage = packageManager.findPackage(language, false);
if (installedPackage == null) {
return new ValidationResult(language + " will be installed on selected interpreter");
}
diff --git a/python/psi-api/src/com/jetbrains/python/PyNames.java b/python/psi-api/src/com/jetbrains/python/PyNames.java
index bd927c5d49bf..ec04e1b4cb61 100644
--- a/python/psi-api/src/com/jetbrains/python/PyNames.java
+++ b/python/psi-api/src/com/jetbrains/python/PyNames.java
@@ -164,6 +164,8 @@ public class PyNames {
public static final String UNKNOWN_TYPE = "unknown";
+ public static final String UNNAMED_ELEMENT = "<unnamed>";
+
/**
* Contains all known predefined names of "__foo__" form.
*/
diff --git a/python/pydevSrc/com/jetbrains/python/debugger/IPyDebugProcess.java b/python/pydevSrc/com/jetbrains/python/debugger/IPyDebugProcess.java
index ab6ccfab0bc6..762225f18f12 100644
--- a/python/pydevSrc/com/jetbrains/python/debugger/IPyDebugProcess.java
+++ b/python/pydevSrc/com/jetbrains/python/debugger/IPyDebugProcess.java
@@ -1,6 +1,8 @@
package com.jetbrains.python.debugger;
import com.intellij.execution.ui.ConsoleViewContentType;
+import com.intellij.xdebugger.frame.XValueChildrenList;
+import com.jetbrains.python.debugger.pydev.PyDebugCallback;
import java.io.IOException;
@@ -12,7 +14,7 @@ public interface IPyDebugProcess extends PyFrameAccessor {
void threadSuspended(PyThreadInfo thread);
- boolean isVariable(String name);
+ boolean canSaveToTemp(String name);
void threadResumed(PyThreadInfo thread);
@@ -25,4 +27,6 @@ public interface IPyDebugProcess extends PyFrameAccessor {
void recordSignature(PySignature signature);
void showConsole(PyThreadInfo thread);
+
+ void loadReferrers(PyReferringObjectsValue var, PyDebugCallback<XValueChildrenList> callback);
}
diff --git a/python/pydevSrc/com/jetbrains/python/debugger/PyDebugValue.java b/python/pydevSrc/com/jetbrains/python/debugger/PyDebugValue.java
index 69b64827c40f..ddec6797ea8d 100644
--- a/python/pydevSrc/com/jetbrains/python/debugger/PyDebugValue.java
+++ b/python/pydevSrc/com/jetbrains/python/debugger/PyDebugValue.java
@@ -5,6 +5,7 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.xdebugger.frame.XNamedValue;
import com.intellij.xdebugger.frame.*;
+import com.jetbrains.python.debugger.pydev.PyVariableLocator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -21,14 +22,13 @@ public class PyDebugValue extends XNamedValue {
private final String myValue;
private final boolean myContainer;
private final PyDebugValue myParent;
+ private String myId = null;
private final PyFrameAccessor myFrameAccessor;
- private final boolean myErrorOnEval;
+ private PyVariableLocator myVariableLocator;
- public PyDebugValue(@NotNull final String name, final String type, final String value, final boolean container, boolean errorOnEval) {
- this(name, type, value, container, errorOnEval, null, null);
- }
+ private final boolean myErrorOnEval;
public PyDebugValue(@NotNull final String name, final String type, final String value, final boolean container,
boolean errorOnEval, final PyFrameAccessor frameAccessor) {
@@ -97,7 +97,7 @@ public class PyDebugValue extends XNamedValue {
myParent.buildExpression(result);
if (("dict".equals(myParent.getType()) || "list".equals(myParent.getType()) || "tuple".equals(myParent.getType())) &&
!isLen(myName)) {
- result.append('[').append(removeId(myName)).append(']');
+ result.append('[').append(removeLeadingZeros(removeId(myName))).append(']');
}
else if (("set".equals(myParent.getType())) && !isLen(myName)) {
//set doesn't support indexing
@@ -105,6 +105,9 @@ public class PyDebugValue extends XNamedValue {
else if (isLen(myName)) {
result.append('.').append(myName).append("()");
}
+ else if (("ndarray".equals(myParent.getType()) || "matrix".equals(myParent.getType())) && myName.startsWith("[")) {
+ result.append(removeLeadingZeros(myName));
+ }
else {
result.append('.').append(myName);
}
@@ -119,6 +122,11 @@ public class PyDebugValue extends XNamedValue {
return name;
}
+ private static String removeLeadingZeros(@NotNull String name) {
+ //bugs.python.org/issue15254: "0" prefix for octal
+ return name.replaceFirst("^0+(?!$)", "");
+ }
+
private static boolean isLen(String name) {
return "__len__".equals(name);
}
@@ -179,4 +187,39 @@ public class PyDebugValue extends XNamedValue {
public PyDebugValue setName(String newName) {
return new PyDebugValue(newName, myType, myValue, myContainer, myErrorOnEval, myParent, myFrameAccessor);
}
+
+ @Nullable
+ @Override
+ public XReferrersProvider getReferrersProvider() {
+ if (myFrameAccessor.getReferrersLoader() != null) {
+ return new XReferrersProvider() {
+ @Override
+ public XValue getReferringObjectsValue() {
+ return new PyReferringObjectsValue(PyDebugValue.this);
+ }
+ };
+ } else {
+ return null;
+ }
+ }
+
+ public PyFrameAccessor getFrameAccessor() {
+ return myFrameAccessor;
+ }
+
+ public PyVariableLocator getVariableLocator() {
+ return myVariableLocator;
+ }
+
+ public void setVariableLocator(PyVariableLocator variableLocator) {
+ myVariableLocator = variableLocator;
+ }
+
+ public String getId() {
+ return myId;
+ }
+
+ public void setId(String id) {
+ myId = id;
+ }
}
diff --git a/python/pydevSrc/com/jetbrains/python/debugger/PyFrameAccessor.java b/python/pydevSrc/com/jetbrains/python/debugger/PyFrameAccessor.java
index 530035e78a4b..01666456f420 100644
--- a/python/pydevSrc/com/jetbrains/python/debugger/PyFrameAccessor.java
+++ b/python/pydevSrc/com/jetbrains/python/debugger/PyFrameAccessor.java
@@ -17,4 +17,7 @@ public interface PyFrameAccessor {
XValueChildrenList loadVariable(PyDebugValue var) throws PyDebuggerException;
void changeVariable(PyDebugValue variable, String expression) throws PyDebuggerException;
+
+ @Nullable
+ PyReferrersLoader getReferrersLoader();
}
diff --git a/python/pydevSrc/com/jetbrains/python/debugger/PyReferrersLoader.java b/python/pydevSrc/com/jetbrains/python/debugger/PyReferrersLoader.java
new file mode 100644
index 000000000000..edb2f641b192
--- /dev/null
+++ b/python/pydevSrc/com/jetbrains/python/debugger/PyReferrersLoader.java
@@ -0,0 +1,20 @@
+package com.jetbrains.python.debugger;
+
+import com.intellij.xdebugger.frame.XReferrersProvider;
+import com.intellij.xdebugger.frame.XValueChildrenList;
+import com.jetbrains.python.debugger.pydev.PyDebugCallback;
+
+/**
+ * @author traff
+ */
+public class PyReferrersLoader {
+ private final IPyDebugProcess myProcess;
+
+ public PyReferrersLoader(IPyDebugProcess process) {
+ myProcess = process;
+ }
+
+ public void loadReferrers(PyReferringObjectsValue value, PyDebugCallback<XValueChildrenList> callback) {
+ myProcess.loadReferrers(value, callback);
+ }
+}
diff --git a/python/pydevSrc/com/jetbrains/python/debugger/PyReferringObjectsValue.java b/python/pydevSrc/com/jetbrains/python/debugger/PyReferringObjectsValue.java
new file mode 100644
index 000000000000..283653659d0d
--- /dev/null
+++ b/python/pydevSrc/com/jetbrains/python/debugger/PyReferringObjectsValue.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.debugger;
+
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.xdebugger.frame.XCompositeNode;
+import com.intellij.xdebugger.frame.XValueChildrenList;
+import com.jetbrains.python.debugger.pydev.PyDebugCallback;
+import org.jetbrains.annotations.NotNull;
+
+public class PyReferringObjectsValue extends PyDebugValue {
+ private static final Logger LOG = Logger.getInstance(PyReferringObjectsValue.class);
+
+ private final @NotNull PyReferrersLoader myReferrersLoader;
+
+ public PyReferringObjectsValue(@NotNull String name,
+ String type,
+ String value,
+ boolean container, boolean errorOnEval, @NotNull PyFrameAccessor frameAccessor) {
+ super(name, type, value, container, errorOnEval, frameAccessor);
+ myReferrersLoader = frameAccessor.getReferrersLoader();
+ }
+
+ public PyReferringObjectsValue(PyDebugValue debugValue) {
+ this(debugValue.getName(), debugValue.getType(), debugValue.getValue(), debugValue.isContainer(), debugValue.isErrorOnEval(), debugValue.getFrameAccessor());
+ }
+
+ @Override
+ public boolean canNavigateToSource() {
+ return true;
+ }
+
+ @Override
+ public void computeChildren(@NotNull final XCompositeNode node) {
+ if (node.isObsolete()) return;
+
+ myReferrersLoader.loadReferrers(this, new PyDebugCallback<XValueChildrenList>() {
+ @Override
+ public void ok(XValueChildrenList value) {
+ if (!node.isObsolete()) {
+ node.addChildren(value, true);
+ }
+ }
+
+ @Override
+ public void error(PyDebuggerException e) {
+ if (!node.isObsolete()) {
+ node.setErrorMessage("Unable to display children:" + e.getMessage());
+ }
+ LOG.warn(e);
+ }
+ });
+ }
+
+ public boolean isField() {
+ return false; //TODO
+ }
+}
diff --git a/python/pydevSrc/com/jetbrains/python/debugger/PyThreadInfo.java b/python/pydevSrc/com/jetbrains/python/debugger/PyThreadInfo.java
index c01be15384ab..7fffc636a9fb 100644
--- a/python/pydevSrc/com/jetbrains/python/debugger/PyThreadInfo.java
+++ b/python/pydevSrc/com/jetbrains/python/debugger/PyThreadInfo.java
@@ -80,7 +80,7 @@ public class PyThreadInfo {
}
public boolean isExceptionBreak() {
- return myStopReason == AbstractCommand.ADD_EXCEPTION_BREAKPOINT || myStopReason == AbstractCommand.ADD_DJANGO_EXCEPTION_BREAKPOINT;
+ return myStopReason == AbstractCommand.ADD_EXCEPTION_BREAKPOINT;
}
@Override
diff --git a/python/pydevSrc/com/jetbrains/python/debugger/PyTypeHandler.java b/python/pydevSrc/com/jetbrains/python/debugger/PyTypeHandler.java
index 6db612488d4b..f882aae4d0e7 100644
--- a/python/pydevSrc/com/jetbrains/python/debugger/PyTypeHandler.java
+++ b/python/pydevSrc/com/jetbrains/python/debugger/PyTypeHandler.java
@@ -37,6 +37,9 @@ public class PyTypeHandler {
FORMATTERS = new HashMap<String, Formatter>();
FORMATTERS.put("str", STR_FORMATTER);
FORMATTERS.put("unicode", UNI_FORMATTER);
+ //numpy types
+ FORMATTERS.put("string_", STR_FORMATTER);
+ FORMATTERS.put("unicode_", UNI_FORMATTER);
}
private PyTypeHandler() { }
diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractCommand.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractCommand.java
index 15bb76b6c3d1..d13addaade04 100644
--- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractCommand.java
+++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractCommand.java
@@ -28,11 +28,10 @@ public abstract class AbstractCommand<T> {
public static final int ADD_EXCEPTION_BREAKPOINT = 122;
public static final int REMOVE_EXCEPTION_BREAKPOINT = 123;
public static final int LOAD_SOURCE = 124;
- public static final int ADD_DJANGO_EXCEPTION_BREAKPOINT = 125;
- public static final int REMOVE_DJANGO_EXCEPTION_BREAKPOINT = 126;
public static final int SMART_STEP_INTO = 128;
public static final int EXIT = 129;
public static final int CALL_SIGNATURE_TRACE = 130;
+ public static final int CMD_RUN_CUSTOM_OPERATION = 135;
public static final int SHOW_CONSOLE = 142;
public static final int ERROR = 901;
@@ -41,7 +40,7 @@ public abstract class AbstractCommand<T> {
public static final String TAB_CHAR = "@_@TAB_CHAR@_@";
- @NotNull protected final RemoteDebugger myDebugger;
+ @NotNull private final RemoteDebugger myDebugger;
private final int myCommandCode;
private final ResponseProcessor<T> myResponseProcessor;
@@ -107,7 +106,7 @@ public abstract class AbstractCommand<T> {
}
}
- public void execute(final ProcessDebugger.DebugCallback<T> callback) {
+ public void execute(final PyDebugCallback<T> callback) {
final int sequence = myDebugger.getNextSequence();
final ResponseProcessor<T> processor = getResponseProcessor();
@@ -186,6 +185,11 @@ public abstract class AbstractCommand<T> {
return command == ERROR;
}
+ @NotNull
+ public RemoteDebugger getDebugger() {
+ return myDebugger;
+ }
+
protected static class Payload {
private final StringBuilder myBuilder = new StringBuilder();
private static final char SEPARATOR = '\t';
diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/ConsoleExecCommand.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/ConsoleExecCommand.java
index 14d8c084a39d..c03890f088e8 100644
--- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/ConsoleExecCommand.java
+++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/ConsoleExecCommand.java
@@ -28,7 +28,7 @@ public class ConsoleExecCommand extends AbstractFrameCommand<String> {
return new ResponseProcessor<String>() {
@Override
protected String parseResponse(ProtocolFrame response) throws PyDebuggerException {
- final PyDebugValue value = ProtocolParser.parseValue(response.getPayload(), myDebugger.getDebugProcess());
+ final PyDebugValue value = ProtocolParser.parseValue(response.getPayload(), getDebugger().getDebugProcess());
return value.getValue();
}
};
diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/GetReferrersCommand.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/GetReferrersCommand.java
new file mode 100644
index 000000000000..3698266f66b7
--- /dev/null
+++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/GetReferrersCommand.java
@@ -0,0 +1,50 @@
+package com.jetbrains.python.debugger.pydev;
+
+import com.jetbrains.python.debugger.PyDebugValue;
+import com.jetbrains.python.debugger.PyDebuggerException;
+import com.jetbrains.python.debugger.PyReferringObjectsValue;
+
+import java.util.List;
+
+/**
+ * @author traff
+ */
+public class GetReferrersCommand extends RunCustomOperationCommand<List<PyDebugValue>> {
+
+ public GetReferrersCommand(RemoteDebugger target, String threadId, String frameId, PyReferringObjectsValue value) {
+ super(target, createVariableLocator(threadId, frameId, value), "from pydevd_referrers import get_referrer_info",
+ "get_referrer_info");
+ }
+
+ @Override
+ protected ResponseProcessor<List<PyDebugValue>> createResponseProcessor() {
+ return new ResponseProcessor<List<PyDebugValue>>() {
+ @Override
+ protected List<PyDebugValue> parseResponse(ProtocolFrame response) throws PyDebuggerException {
+ return ProtocolParser.parseReferrers(decode(response.getPayload()), getDebugger().getDebugProcess());
+ }
+ };
+ }
+
+
+ private static PyVariableLocator createVariableLocator(final String threadId, final String frameId, final PyReferringObjectsValue var) {
+ return new PyVariableLocator() {
+ @Override
+ public String getThreadId() {
+ return threadId;
+ }
+
+
+ @Override
+ public String getPyDBLocation() {
+ if (var.getId() == null) {
+ return threadId + "\t" + frameId + "\tFRAME\t" + var.getName();
+ }
+ //Ok, this only happens when we're dealing with references with no proper scope given and we need to get
+ //things by id (which is usually not ideal). In this case we keep the proper thread id and set the frame id
+ //as the id of the object to be searched later on based on the list of all alive objects.
+ return getThreadId() + "\t" + var.getId() + "\tBY_ID";
+ }
+ };
+ }
+}
diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/GetVariableCommand.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/GetVariableCommand.java
index ef4bd12059d7..e5a218607ac8 100644
--- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/GetVariableCommand.java
+++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/GetVariableCommand.java
@@ -5,6 +5,7 @@ import com.jetbrains.python.debugger.PyDebugValue;
public class GetVariableCommand extends GetFrameCommand {
+ public static final String BY_ID = "BY_ID";
private final String myVariableName;
private final PyDebugValue myParent;
@@ -15,23 +16,40 @@ public class GetVariableCommand extends GetFrameCommand {
}
public static String composeName(final PyDebugValue var) {
- final StringBuilder sb = new StringBuilder(var.getTempName());
+ final StringBuilder sb = new StringBuilder();
PyDebugValue p = var;
- while ((p = p.getParent()) != null) {
- sb.insert(0, '\t').insert(0, p.getTempName());
+ while (p != null) {
+ if (sb.length() > 0 ) {
+ sb.insert(0, '\t');
+ }
+ if (p.getId() != null) {
+ sb.insert(0, BY_ID).insert(0, '\t').insert(0, p.getId());
+ break;
+ } else {
+ sb.insert(0, p.getTempName());
+ }
+ p = p.getParent();
}
return sb.toString();
}
@Override
protected void buildPayload(Payload payload) {
- super.buildPayload(payload);
- payload.add(myVariableName);
+ if (myParent.getVariableLocator() != null) {
+ payload.add(myParent.getVariableLocator().getThreadId()).add(myParent.getVariableLocator().getPyDBLocation());
+ }
+ else if (myVariableName.contains(BY_ID)) {
+ payload.add(getThreadId()).add(myVariableName);
+ }
+ else {
+ super.buildPayload(payload);
+ payload.add(myVariableName);
+ }
}
@Override
protected PyDebugValue extend(final PyDebugValue value) {
- return new PyDebugValue(value.getName(), value.getType(), value.getValue(), value.isContainer(), value.isErrorOnEval(), myParent, myDebugProcess);
+ return new PyDebugValue(value.getName(), value.getType(), value.getValue(), value.isContainer(), value.isErrorOnEval(), myParent,
+ myDebugProcess);
}
-
}
diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/MultiProcessDebugger.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/MultiProcessDebugger.java
index d210d7ae03a8..d54bac8de85f 100644
--- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/MultiProcessDebugger.java
+++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/MultiProcessDebugger.java
@@ -8,10 +8,7 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.xdebugger.frame.XValueChildrenList;
import com.jetbrains.python.console.pydev.PydevCompletionVariant;
-import com.jetbrains.python.debugger.IPyDebugProcess;
-import com.jetbrains.python.debugger.PyDebugValue;
-import com.jetbrains.python.debugger.PyDebuggerException;
-import com.jetbrains.python.debugger.PyThreadInfo;
+import com.jetbrains.python.debugger.*;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
@@ -168,7 +165,7 @@ public class MultiProcessDebugger implements ProcessDebugger {
}
@Override
- public void consoleExec(String threadId, String frameId, String expression, DebugCallback<String> callback) {
+ public void consoleExec(String threadId, String frameId, String expression, PyDebugCallback<String> callback) {
debugger(threadId).consoleExec(threadId, frameId, expression, callback);
}
@@ -182,6 +179,11 @@ public class MultiProcessDebugger implements ProcessDebugger {
return debugger(threadId).loadVariable(threadId, frameId, var);
}
+ @Override
+ public void loadReferrers(String threadId, String frameId, PyReferringObjectsValue var, PyDebugCallback<XValueChildrenList> callback) {
+ debugger(threadId).loadReferrers(threadId, frameId, var, callback);
+ }
+
@NotNull
private ProcessDebugger debugger(@NotNull String threadId) {
ProcessDebugger debugger = myThreadRegistry.getDebugger(threadId);
diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProcessDebugger.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProcessDebugger.java
index 2d864f0df2ca..0fa5a5c21931 100644
--- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProcessDebugger.java
+++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProcessDebugger.java
@@ -4,6 +4,7 @@ import com.intellij.xdebugger.frame.XValueChildrenList;
import com.jetbrains.python.console.pydev.PydevCompletionVariant;
import com.jetbrains.python.debugger.PyDebugValue;
import com.jetbrains.python.debugger.PyDebuggerException;
+import com.jetbrains.python.debugger.PyReferringObjectsValue;
import com.jetbrains.python.debugger.PyThreadInfo;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -26,15 +27,17 @@ public interface ProcessDebugger {
String expression,
boolean execute,
boolean trimResult)
- throws PyDebuggerException;
+ throws PyDebuggerException;
- void consoleExec(String threadId, String frameId, String expression, DebugCallback<String> callback);
+ void consoleExec(String threadId, String frameId, String expression, PyDebugCallback<String> callback);
XValueChildrenList loadFrame(String threadId, String frameId) throws PyDebuggerException;
// todo: don't generate temp variables for qualified expressions - just split 'em
XValueChildrenList loadVariable(String threadId, String frameId, PyDebugValue var) throws PyDebuggerException;
+ void loadReferrers(String threadId, String frameId, PyReferringObjectsValue var, PyDebugCallback<XValueChildrenList> callback);
+
PyDebugValue changeVariable(String threadId, String frameId, PyDebugValue var, String value)
throws PyDebuggerException;
@@ -50,7 +53,7 @@ public interface ProcessDebugger {
void suspendThread(String threadId);
/**
- * Disconnects current debug process. Closes all resources.
+ * Disconnects current debug process. Closes all resources.
*/
void close();
@@ -84,12 +87,4 @@ public interface ProcessDebugger {
void addExceptionBreakpoint(ExceptionBreakpointCommandFactory factory);
void removeExceptionBreakpoint(ExceptionBreakpointCommandFactory factory);
-
- /**
- * @author traff
- */
- interface DebugCallback<T> {
- void ok(T value);
- void error(PyDebuggerException exception);
- }
}
diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProtocolParser.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProtocolParser.java
index 0801077fbea3..1822b17efaa3 100644
--- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProtocolParser.java
+++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProtocolParser.java
@@ -122,6 +122,32 @@ public class ProtocolParser {
}
@NotNull
+ public static List<PyDebugValue> parseReferrers(final String text, final PyFrameAccessor frameAccessor) throws PyDebuggerException {
+ final List<PyDebugValue> values = new LinkedList<PyDebugValue>();
+
+ final XppReader reader = openReader(text, false);
+
+ while (reader.hasMoreChildren()) {
+ reader.moveDown();
+ if (reader.getNodeName().equals("var")) {
+ PyDebugValue value = parseValue(reader, frameAccessor);
+ value.setId(readString(reader, "id", null));
+ values.add(value);
+ }
+ else if (reader.getNodeName().equals("for")) {
+ //TODO
+ }
+ else {
+ throw new PyDebuggerException("Expected <var> or <for>, found " + reader.getNodeName());
+ }
+ reader.moveUp();
+ }
+
+ return values;
+ }
+
+
+ @NotNull
public static List<PyDebugValue> parseValues(final String text, final PyFrameAccessor frameAccessor) throws PyDebuggerException {
final List<PyDebugValue> values = new LinkedList<PyDebugValue>();
diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/PyDebugCallback.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/PyDebugCallback.java
new file mode 100644
index 000000000000..c78f3e20bdc5
--- /dev/null
+++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/PyDebugCallback.java
@@ -0,0 +1,12 @@
+package com.jetbrains.python.debugger.pydev;
+
+import com.jetbrains.python.debugger.PyDebuggerException;
+
+/**
+ * @author traff
+ */
+public interface PyDebugCallback<T> {
+ void ok(T value);
+
+ void error(PyDebuggerException exception);
+}
diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/PyVariableLocator.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/PyVariableLocator.java
new file mode 100644
index 000000000000..3ba4e1cd96de
--- /dev/null
+++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/PyVariableLocator.java
@@ -0,0 +1,17 @@
+package com.jetbrains.python.debugger.pydev;
+
+/**
+ * IVariableLocator knows how to produce location information
+ * for CMD_GET_VARIABLE
+ *
+ * The location is specified as:
+ *
+ * thread_id, stack_frame, LOCAL|GLOBAL, attribute*
+ */
+public interface PyVariableLocator {
+
+ public String getThreadId();
+
+ public String getPyDBLocation();
+
+}
diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java
index df33148edb10..4ce7bdf67434 100644
--- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java
+++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java
@@ -133,7 +133,7 @@ public class RemoteDebugger implements ProcessDebugger {
}
@Override
- public void consoleExec(String threadId, String frameId, String expression, DebugCallback<String> callback) {
+ public void consoleExec(String threadId, String frameId, String expression, PyDebugCallback<String> callback) {
final ConsoleExecCommand command = new ConsoleExecCommand(this, threadId, frameId, expression);
command.execute(callback);
}
@@ -154,6 +154,31 @@ public class RemoteDebugger implements ProcessDebugger {
return command.getVariables();
}
+
+ @Override
+ public void loadReferrers(final String threadId,
+ final String frameId,
+ final PyReferringObjectsValue var,
+ final PyDebugCallback<XValueChildrenList> callback) {
+ RunCustomOperationCommand cmd = new GetReferrersCommand(this, threadId, frameId, var);
+
+ cmd.execute(new PyDebugCallback<List<PyDebugValue>>() {
+ @Override
+ public void ok(List<PyDebugValue> value) {
+ XValueChildrenList list = new XValueChildrenList();
+ for (PyDebugValue v : value) {
+ list.add(v);
+ }
+ callback.ok(list);
+ }
+
+ @Override
+ public void error(PyDebuggerException exception) {
+ callback.error(exception);
+ }
+ });
+ }
+
@Override
public PyDebugValue changeVariable(final String threadId, final String frameId, final PyDebugValue var, final String value)
throws PyDebuggerException {
@@ -191,7 +216,7 @@ public class RemoteDebugger implements ProcessDebugger {
// todo: change variable in lists doesn't work - either fix in pydevd or format var name appropriately
private void setTempVariable(final String threadId, final String frameId, final PyDebugValue var) {
final PyDebugValue topVar = var.getTopParent();
- if (myDebugProcess.isVariable(topVar.getName())) {
+ if (!myDebugProcess.canSaveToTemp(topVar.getName())) {
return;
}
if (myTempVars.contains(threadId, frameId, topVar.getTempName())) {
@@ -343,7 +368,7 @@ public class RemoteDebugger implements ProcessDebugger {
}
}
if (myDebuggerReader != null) {
- myDebuggerReader.close();
+ myDebuggerReader.stop();
}
fireCloseEvent();
}
@@ -428,7 +453,6 @@ public class RemoteDebugger implements ProcessDebugger {
}
private class DebuggerReader extends BaseOutputReader {
- private boolean myClosing = false;
private Reader myReader;
private DebuggerReader(final Reader reader) throws IOException {
@@ -442,7 +466,7 @@ public class RemoteDebugger implements ProcessDebugger {
while (true) {
boolean read = readAvailable();
- if (myClosing) {
+ if (isStopped) {
break;
}
@@ -453,7 +477,7 @@ public class RemoteDebugger implements ProcessDebugger {
fireCommunicationError();
}
finally {
- closeReader(myReader);
+ close();
fireExitEvent();
}
}
@@ -475,10 +499,10 @@ public class RemoteDebugger implements ProcessDebugger {
else if (AbstractCommand.isCallSignatureTrace(frame.getCommand())) {
recordCallSignature(ProtocolParser.parseCallSignature(frame.getPayload()));
}
- else if (AbstractCommand.isErrorEvent(frame.getCommand())) {
- LOG.error("Error response from debugger: " + frame.getPayload());
- }
else {
+ if (AbstractCommand.isErrorEvent(frame.getCommand())) {
+ LOG.error("Error response from debugger: " + frame.getPayload());
+ }
placeResponse(frame.getSequence(), frame);
}
}
@@ -568,7 +592,13 @@ public class RemoteDebugger implements ProcessDebugger {
}
public void close() {
- myClosing = true;
+ closeReader(myReader);
+ }
+
+ @Override
+ public void stop() {
+ super.stop();
+ close();
}
@Override
diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/RunCustomOperationCommand.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RunCustomOperationCommand.java
new file mode 100644
index 000000000000..7a3315b4acce
--- /dev/null
+++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RunCustomOperationCommand.java
@@ -0,0 +1,86 @@
+package com.jetbrains.python.debugger.pydev;
+
+import com.intellij.openapi.diagnostic.Logger;
+
+import java.io.File;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+
+
+/**
+ * Run a custom bit of Python in the context of the specified debug target.
+ * <p>
+ * This command takes a variable or expression (expressed as an {@link PyVariableLocator#getPyDBLocation()} style
+ * location) and passes it to the function provided in the constructor. The constructor also takes either a code
+ * snippet that should define the function, or a file to execfile that should define the function.
+ * <p>
+ * Once created, the command should be posted to the target with {@link AbstractDebugTarget#postCommand(AbstractDebuggerCommand)}.
+ * Optionally, the function run on the target can return a string for further processing. In this case the command's
+ * {@link #setCompletionListener(ICommandResponseListener)} should be set and on completion, {@link #getResponsePayload()}
+ * can be used to obtain the returned value.
+ * <p>
+ * For an example, see {@link PrettyPrintCommandHandler}
+ */
+public class RunCustomOperationCommand<T> extends AbstractCommand<T> {
+ private static final Logger LOG = Logger.getInstance(RunCustomOperationCommand.class);
+
+ private String myEncodedCodeOrFile;
+ private String myOperationFnName;
+ private PyVariableLocator myLocator;
+ private String myStyle;
+
+ private RunCustomOperationCommand(RemoteDebugger target, PyVariableLocator locator,
+ String style, String codeOrFile, String operationFnName) {
+ super(target, CMD_RUN_CUSTOM_OPERATION);
+
+ this.myLocator = locator;
+ this.myStyle = style;
+ this.myEncodedCodeOrFile = encode(codeOrFile);
+ this.myOperationFnName = operationFnName;
+ }
+
+ /**
+ * Create a new command to run with the function defined in a string.
+ *
+ * @param target Debug Target to run on
+ * @param locator Location of variable or expression.
+ * @param operationSource Definition of the function to be run (this code is "exec"ed by the target)
+ * @param operationFnName Function to call, must be defined by operationSource
+ */
+ public RunCustomOperationCommand(RemoteDebugger target, PyVariableLocator locator,
+ String operationSource, String operationFnName) {
+ this(target, locator, "EXEC", operationSource, operationFnName);
+ }
+
+
+ @Override
+ protected void buildPayload(Payload payload) {
+ payload.add(myLocator.getPyDBLocation() + "||" + myStyle).add(myEncodedCodeOrFile).add(myOperationFnName);
+ }
+
+ @Override
+ public boolean isResponseExpected() {
+ return true;
+ }
+
+ private static String encode(String in) {
+ try {
+ return URLEncoder.encode(in, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ LOG.error("Unreachable? UTF-8 is always supported.", e);
+ return "";
+ }
+ }
+
+ protected static String decode(String in) {
+ try {
+ return URLDecoder.decode(in, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ LOG.error("Unreachable? UTF-8 is always supported.", e);
+ return "";
+ }
+ }
+
+}
+
diff --git a/python/python-rest/src/com/jetbrains/rest/RestPythonUtil.java b/python/python-rest/src/com/jetbrains/rest/RestPythonUtil.java
index f32fce8e40b7..e6d379f03676 100644
--- a/python/python-rest/src/com/jetbrains/rest/RestPythonUtil.java
+++ b/python/python-rest/src/com/jetbrains/rest/RestPythonUtil.java
@@ -26,7 +26,6 @@ import com.intellij.openapi.projectRoots.Sdk;
import com.jetbrains.python.packaging.PyExternalProcessException;
import com.jetbrains.python.packaging.PyPackage;
import com.jetbrains.python.packaging.PyPackageManager;
-import com.jetbrains.python.packaging.PyPackageManagerImpl;
import com.jetbrains.python.sdk.PythonSdkType;
/**
@@ -48,9 +47,9 @@ public class RestPythonUtil {
if (module != null) {
Sdk sdk = PythonSdkType.findPythonSdk(module);
if (sdk != null) {
- PyPackageManagerImpl manager = (PyPackageManagerImpl)PyPackageManager.getInstance(sdk);
+ PyPackageManager manager = PyPackageManager.getInstance(sdk);
try {
- final PyPackage sphinx = manager.findInstalledPackage("Sphinx");
+ final PyPackage sphinx = manager.findPackage("Sphinx", false);
presentation.setEnabled(sphinx != null);
}
catch (PyExternalProcessException ignored) {
diff --git a/python/src/META-INF/pycharm-core.xml b/python/src/META-INF/pycharm-core.xml
index a9f7824b5340..ac42944c9953 100644
--- a/python/src/META-INF/pycharm-core.xml
+++ b/python/src/META-INF/pycharm-core.xml
@@ -40,10 +40,10 @@
<projectAttachProcessor implementation="com.intellij.platform.ModuleAttachProcessor"/>
- <projectConfigurable instance="com.jetbrains.python.configuration.PythonContentEntriesConfigurable"/>
- <projectConfigurable instance="com.jetbrains.python.buildout.BuildoutModulesConfigurable"/>
+ <projectConfigurable groupId="project" instance="com.jetbrains.python.configuration.PythonContentEntriesConfigurable"/>
+ <projectConfigurable groupId="build" instance="com.jetbrains.python.buildout.BuildoutModulesConfigurable"/>
<projectConfigurable groupId="project" instance="com.jetbrains.python.configuration.PyActiveSdkModuleConfigurable"/>
- <projectConfigurable instance="com.jetbrains.python.configuration.PyDependenciesConfigurable"/>
+ <projectConfigurable groupId="project" instance="com.jetbrains.python.configuration.PyDependenciesConfigurable"/>
<directoryProjectConfigurator implementation="com.jetbrains.python.PythonSdkConfigurator" id="sdk"
order="after PlatformProjectConfigurator"/>
@@ -104,7 +104,7 @@
<add-to-group group-id="FileOpenGroup" anchor="after" relative-to-action="OpenFile"/>
</action>
- <action id="RerunFailedTests" class="com.intellij.execution.testframework.actions.AbstractRerunFailedTestsAction"
+ <action id="RerunFailedTests" class="com.intellij.execution.testframework.actions.RerunFailedTestsAction"
icon="AllIcons.RunConfigurations.RerunFailedTests"/>
<group id="WelcomeScreen.Platform.NewProject">
diff --git a/python/src/META-INF/python-core.xml b/python/src/META-INF/python-core.xml
index 7adbc46c189c..5091d43386a1 100644
--- a/python/src/META-INF/python-core.xml
+++ b/python/src/META-INF/python-core.xml
@@ -137,6 +137,7 @@
<gotoTargetRendererProvider implementation="com.jetbrains.python.codeInsight.PyGotoTargetRendererProvider"/>
<typeHierarchyProvider language="Python" implementationClass="com.jetbrains.python.hierarchy.PyTypeHierachyProvider"/>
+ <callHierarchyProvider language="Python" implementationClass="com.jetbrains.python.hierarchy.call.PyCallHierarchyProvider"/>
<highlightUsagesHandlerFactory implementation="com.jetbrains.python.codeInsight.highlighting.PyHighlightExitPointsHandlerFactory"/>
<joinLinesHandler implementation="com.jetbrains.python.editor.PyJoinLinesHandler"/>
@@ -531,7 +532,8 @@
</extensions>
- <extensionPoints>
+ <extensionPoints>
+ <extensionPoint qualifiedName="Pythonid.pythonDocumentationQuickInfoProvider" interface="com.jetbrains.python.documentation.PythonDocumentationQuickInfoProvider"/>
<extensionPoint qualifiedName="Pythonid.importResolver" interface="com.jetbrains.python.psi.impl.PyImportResolver"/>
<extensionPoint qualifiedName="Pythonid.magicLiteral" interface="com.jetbrains.python.magicLiteral.PyMagicLiteralExtensionPoint"/>
<extensionPoint qualifiedName="Pythonid.unresolvedReferenceSkipper" interface="com.jetbrains.python.inspections.unresolvedReference.PyUnresolvedReferenceSkipperExtPoint"/>
@@ -633,8 +635,6 @@
<separator/>
<reference ref="AddToFavorites"/>
<separator/>
- <reference ref="RunContextPopupGroup"/>
- <separator/>
<reference ref="ReformatCode"/>
<reference ref="OptimizeImports"/>
<reference ref="$Delete"/>
@@ -647,7 +647,26 @@
<reference ref="CompareFileWithEditor"/>
</group>
+ <group id="PyCallHierarchyPopupMenu">
+ <reference ref="EditSource"/>
+ <separator/>
+ <reference ref="FindUsages"/>
+ <reference ref="RefactoringMenu"/>
+ <separator/>
+ <reference ref="AddToFavorites"/>
+ <separator/>
+ <reference ref="ReformatCode"/>
+ <reference ref="OptimizeImports"/>
+ <separator/>
+ <reference ref="VersionControlsGroup"/>
+
+ <separator/>
+ <reference ref="ExternalToolsGroup"/>
+ <separator/>
+ <reference ref="CompareTwoFiles"/>
+ <reference ref="CompareFileWithEditor"/>
+ </group>
<action id="com.jetbrains.python.console.PyOpenDebugConsoleAction"
class="com.jetbrains.python.console.PyOpenDebugConsoleAction"
diff --git a/python/src/com/jetbrains/python/PyBundle.properties b/python/src/com/jetbrains/python/PyBundle.properties
index 482daa88b66c..d82e9a6fde62 100644
--- a/python/src/com/jetbrains/python/PyBundle.properties
+++ b/python/src/com/jetbrains/python/PyBundle.properties
@@ -676,6 +676,9 @@ ANN.tuple.py3=tuple parameter unpacking is not supported in Python 3
ANN.star.import.at.top.only='import *' only allowed at module level
+ANN.missing.closing.quote=Missing closing quote [{0}]
+ANN.missing.closing.triple.quotes=Missing closing triple quotes
+
ANN.method.$0.removed.use.$1=Method ''{0}'' has been removed, use ''{1}'' instead
ANN.method.$0.removed=Method ''{0}'' removed
diff --git a/python/src/com/jetbrains/python/codeInsight/completion/PyKeywordCompletionContributor.java b/python/src/com/jetbrains/python/codeInsight/completion/PyKeywordCompletionContributor.java
index 2ecf3b54a8d0..ab13a59ff0b8 100644
--- a/python/src/com/jetbrains/python/codeInsight/completion/PyKeywordCompletionContributor.java
+++ b/python/src/com/jetbrains/python/codeInsight/completion/PyKeywordCompletionContributor.java
@@ -278,7 +278,7 @@ public class PyKeywordCompletionContributor extends CompletionContributor {
private static final PsiElementPattern.Capture<PsiElement> IN_IF_BODY =
psiElement().inside(psiElement(PyStatementList.class).inside(psiElement(PyIfPart.class)));
- private static final PsiElementPattern.Capture<PsiElement> IN_LOOP =
+ private static final PsiElementPattern.Capture<PsiElement> IN_LOOP =
psiElement().inside(false, psiElement(PyLoopStatement.class), or(psiElement(PyFunction.class), psiElement(PyClass.class)));
// not exactly a beauty
@@ -645,6 +645,20 @@ public class PyKeywordCompletionContributor extends CompletionContributor {
new PyKeywordCompletionProvider(PyNames.FROM));
}
+ private void addYieldExpression() {
+ extend(CompletionType.BASIC,
+ psiElement()
+ .withLanguage(PythonLanguage.getInstance())
+ .andOr(psiElement()
+ .inside(false, psiElement(PyAssignmentStatement.class), psiElement(PyTargetExpression.class))
+ .afterLeaf(psiElement().withElementType(PyTokenTypes.EQ)),
+ psiElement()
+ .inside(false, psiElement(PyAugAssignmentStatement.class), psiElement(PyTargetExpression.class))
+ .afterLeaf(psiElement().withElementType(PyTokenTypes.AUG_ASSIGN_OPERATIONS)),
+ psiElement().inside(true, psiElement(PyParenthesizedExpression.class))),
+ new PyKeywordCompletionProvider(PyNames.YIELD));
+ }
+
private void addYieldFrom() {
extend(CompletionType.BASIC,
psiElement()
@@ -671,6 +685,7 @@ public class PyKeywordCompletionContributor extends CompletionContributor {
//addExprIf();
addExprElse();
addRaiseFrom();
+ addYieldExpression();
addYieldFrom();
addForToComprehensions();
addInToFor();
diff --git a/python/src/com/jetbrains/python/codeInsight/editorActions/moveUpDown/PyStatementMover.java b/python/src/com/jetbrains/python/codeInsight/editorActions/moveUpDown/PyStatementMover.java
index 65cd5e1a79ce..89b6d9bc4a5d 100644
--- a/python/src/com/jetbrains/python/codeInsight/editorActions/moveUpDown/PyStatementMover.java
+++ b/python/src/com/jetbrains/python/codeInsight/editorActions/moveUpDown/PyStatementMover.java
@@ -108,7 +108,6 @@ public class PyStatementMover extends LineMover {
if (moveOutsideFile(document, lineNumber)) return null;
int lineEndOffset = document.getLineEndOffset(lineNumber);
final int startOffset = document.getLineStartOffset(lineNumber);
- lineEndOffset = startOffset != lineEndOffset ? lineEndOffset - 1 : lineEndOffset;
final PyStatementList statementList = getStatementList(elementToMove);
@@ -119,10 +118,6 @@ public class PyStatementMover extends LineMover {
final int startLine = document.getLineNumber(start);
final int endLine = document.getLineNumber(end);
- if (elementToMove instanceof PsiComment && destination instanceof PsiComment) {
- return new LineRange(lineNumber, lineNumber + 1);
- }
-
if (elementToMove instanceof PyClass || elementToMove instanceof PyFunction) {
PyElement scope = statementList == null ? (PyElement)elementToMove.getContainingFile() : statementList;
if (destination != null)
@@ -137,6 +132,11 @@ public class PyStatementMover extends LineMover {
scopeRange = moveInto(elementToMove, file, editor, down, lineEndOffset);
if (scopeRange != null) return scopeRange;
+ if (elementToMove instanceof PsiComment && ( PsiTreeUtil.isAncestor(destination, elementToMove, true)) ||
+ destination instanceof PsiComment) {
+ return new LineRange(lineNumber, lineNumber + 1);
+ }
+
final PyElement scope = statementList == null ? (PyElement)elementToMove.getContainingFile() : statementList;
if ((elementToMove instanceof PyClass) || (elementToMove instanceof PyFunction))
return new ScopeRange(scope, scope.getFirstChild(), !down, true);
@@ -185,7 +185,6 @@ public class PyStatementMover extends LineMover {
if (sibling != null) {
final PyStatementList list = sibling.getStatementList();
- assert list != null;
return new ScopeRange(list, down ? list.getFirstChild() : list.getLastChild(), !addBefore);
}
else {
@@ -278,11 +277,23 @@ public class PyStatementMover extends LineMover {
private static PsiElement getDestinationElement(@NotNull final PsiElement elementToMove, @NotNull final Document document,
int lineEndOffset, boolean down) {
- PsiElement destination = elementToMove.getContainingFile().findElementAt(lineEndOffset);
- if (destination == null) return null;
- if (destination instanceof PsiComment) return destination;
+ PsiElement destination = PyUtil.findPrevAtOffset(elementToMove.getContainingFile(), lineEndOffset, PsiWhiteSpace.class);
PsiElement sibling = down ? PsiTreeUtil.getNextSiblingOfType(elementToMove, PyStatement.class) :
- PsiTreeUtil.getPrevSiblingOfType(elementToMove, PyStatement.class);
+ PsiTreeUtil.getPrevSiblingOfType(elementToMove, PyStatement.class);
+ if (destination == null) {
+ if (elementToMove instanceof PyClass) {
+ destination = sibling;
+ }
+ else if (elementToMove instanceof PyFunction) {
+ if (!(sibling instanceof PyClass))
+ destination = sibling;
+ else destination = null;
+ }
+ else {
+ return null;
+ }
+ }
+ if (destination instanceof PsiComment) return destination;
if (elementToMove instanceof PyClass) {
destination = sibling;
}
diff --git a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyWithFixer.java b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyWithFixer.java
index ec236d9242f5..b2b71cb9e0d2 100644
--- a/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyWithFixer.java
+++ b/python/src/com/jetbrains/python/codeInsight/editorActions/smartEnter/fixers/PyWithFixer.java
@@ -18,6 +18,7 @@ package com.jetbrains.python.codeInsight.editorActions.smartEnter.fixers;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.PsiElement;
+import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.codeInsight.editorActions.smartEnter.PySmartEnterProcessor;
@@ -27,8 +28,6 @@ import com.jetbrains.python.psi.PyWithItem;
import com.jetbrains.python.psi.PyWithStatement;
import org.jetbrains.annotations.NotNull;
-import static com.jetbrains.python.psi.PyUtil.sure;
-
/**
* @author Mikhail Golubev
*/
@@ -42,11 +41,10 @@ public class PyWithFixer extends PyFixer<PyWithStatement> {
final PsiElement colonToken = PyUtil.getFirstChildOfType(withStatement, PyTokenTypes.COLON);
final PsiElement withToken = PyUtil.getFirstChildOfType(withStatement, PyTokenTypes.WITH_KEYWORD);
final Document document = editor.getDocument();
- if (colonToken == null) {
- int insertAt = sure(withToken).getTextRange().getEndOffset();
+ if (colonToken == null && withToken != null) {
+ int insertAt = withToken.getTextRange().getEndOffset();
String textToInsert = ":";
- final PyWithItem[] withItems = withStatement.getWithItems();
- final PyWithItem lastItem = withItems.length != 0 ? withItems[withItems.length - 1] : null;
+ final PyWithItem lastItem = ArrayUtil.getLastElement(withStatement.getWithItems());
if (lastItem == null || lastItem.getExpression() == null) {
textToInsert = " :";
processor.registerUnresolvedError(insertAt + 1);
diff --git a/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.java b/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.java
index fa869bfca359..e9585a5cd952 100644
--- a/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.java
+++ b/python/src/com/jetbrains/python/configuration/PyIntegratedToolsConfigurable.java
@@ -156,7 +156,7 @@ public class PyIntegratedToolsConfigurable implements SearchableConfigurable, No
return new FacetConfigurationQuickFix() {
@Override
public void run(JComponent place) {
- final PyPackageManagerImpl.UI ui = new PyPackageManagerImpl.UI(myProject, sdk, new PyPackageManagerImpl.UI.Listener() {
+ final PyPackageManagerUI ui = new PyPackageManagerUI(myProject, sdk, new PyPackageManagerUI.Listener() {
@Override
public void started() {}
diff --git a/python/src/com/jetbrains/python/console/PydevConsoleCommunication.java b/python/src/com/jetbrains/python/console/PydevConsoleCommunication.java
index 9c95b1cffda8..5bf06782d376 100644
--- a/python/src/com/jetbrains/python/console/PydevConsoleCommunication.java
+++ b/python/src/com/jetbrains/python/console/PydevConsoleCommunication.java
@@ -31,10 +31,7 @@ import com.intellij.util.Function;
import com.intellij.xdebugger.frame.XValueChildrenList;
import com.jetbrains.python.console.parsing.PythonConsoleData;
import com.jetbrains.python.console.pydev.*;
-import com.jetbrains.python.debugger.PyDebugValue;
-import com.jetbrains.python.debugger.PyDebuggerException;
-import com.jetbrains.python.debugger.PyFrameAccessor;
-import com.jetbrains.python.debugger.PydevXmlUtils;
+import com.jetbrains.python.debugger.*;
import com.jetbrains.python.debugger.pydev.GetVariableCommand;
import com.jetbrains.python.debugger.pydev.ProtocolParser;
import org.apache.xmlrpc.WebServer;
@@ -528,6 +525,11 @@ public class PydevConsoleCommunication extends AbstractConsoleCommunication impl
}
}
+ @Nullable
+ @Override
+ public PyReferrersLoader getReferrersLoader() {
+ return null;
+ }
/**
* Request that pydevconsole connect (with pydevd) to the specified port
diff --git a/python/src/com/jetbrains/python/console/PythonDebugConsoleCommunication.java b/python/src/com/jetbrains/python/console/PythonDebugConsoleCommunication.java
index da1ac53113ef..5f361b30228a 100644
--- a/python/src/com/jetbrains/python/console/PythonDebugConsoleCommunication.java
+++ b/python/src/com/jetbrains/python/console/PythonDebugConsoleCommunication.java
@@ -23,7 +23,7 @@ import com.jetbrains.python.console.pydev.InterpreterResponse;
import com.jetbrains.python.console.pydev.PydevCompletionVariant;
import com.jetbrains.python.debugger.PyDebugProcess;
import com.jetbrains.python.debugger.PyDebuggerException;
-import com.jetbrains.python.debugger.pydev.ProcessDebugger;
+import com.jetbrains.python.debugger.pydev.PyDebugCallback;
import org.jetbrains.annotations.NotNull;
import java.util.List;
@@ -63,8 +63,8 @@ public class PythonDebugConsoleCommunication extends AbstractConsoleCommunicatio
return false;
}
- protected void exec(final ConsoleCodeFragment command, final ProcessDebugger.DebugCallback<Pair<String, Boolean>> callback) {
- myDebugProcess.consoleExec(command.getText(), new ProcessDebugger.DebugCallback<String>() {
+ protected void exec(final ConsoleCodeFragment command, final PyDebugCallback<Pair<String, Boolean>> callback) {
+ myDebugProcess.consoleExec(command.getText(), new PyDebugCallback<String>() {
@Override
public void ok(String value) {
callback.ok(parseExecResponseString(value));
@@ -79,7 +79,7 @@ public class PythonDebugConsoleCommunication extends AbstractConsoleCommunicatio
public void execInterpreter(ConsoleCodeFragment code, final Function<InterpreterResponse, Object> callback) {
myExpression.append(code.getText());
- exec(new ConsoleCodeFragment(myExpression.toString(), false), new ProcessDebugger.DebugCallback<Pair<String, Boolean>>() {
+ exec(new ConsoleCodeFragment(myExpression.toString(), false), new PyDebugCallback<Pair<String, Boolean>>() {
@Override
public void ok(Pair<String, Boolean> executed) {
boolean more = executed.second;
diff --git a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java
index cdea41298a4e..ea492e43cf2d 100644
--- a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java
+++ b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java
@@ -17,7 +17,6 @@ package com.jetbrains.python.debugger;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
-import com.intellij.execution.console.DuplexConsoleView;
import com.intellij.execution.process.ProcessEvent;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.process.ProcessListener;
@@ -88,6 +87,7 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr
private boolean myWaitingForConnection = false;
private PyStackFrame myStackFrameBeforeResume;
private PyStackFrame myConsoleContextFrame = null;
+ private PyReferrersLoader myReferrersProvider;
public PyDebugProcess(final @NotNull XDebugSession session,
@NotNull final ServerSocket serverSocket,
@@ -489,7 +489,7 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr
return myDebugger.evaluate(frame.getThreadId(), frame.getFrameId(), expression, execute, trimResult);
}
- public void consoleExec(String command, ProcessDebugger.DebugCallback<String> callback) {
+ public void consoleExec(String command, PyDebugCallback<String> callback) {
dropFrameCaches();
try {
final PyStackFrame frame = currentFrame();
@@ -539,6 +539,17 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr
}
@Override
+ public void loadReferrers(PyReferringObjectsValue var, PyDebugCallback<XValueChildrenList> callback) {
+ try {
+ final PyStackFrame frame = currentFrame();
+ myDebugger.loadReferrers(frame.getThreadId(), frame.getFrameId(), var, callback);
+ }
+ catch (PyDebuggerException e) {
+ callback.error(e);
+ }
+ }
+
+ @Override
public void changeVariable(final PyDebugValue var, final String value) throws PyDebuggerException {
final PyStackFrame frame = currentFrame();
PyDebugValue newValue = myDebugger.changeVariable(frame.getThreadId(), frame.getFrameId(), var, value);
@@ -546,14 +557,23 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr
}
@Nullable
+ @Override
+ public PyReferrersLoader getReferrersLoader() {
+ if (myReferrersProvider == null) {
+ myReferrersProvider = new PyReferrersLoader(this);
+ }
+ return myReferrersProvider;
+ }
+
+ @Nullable
public String loadSource(String path) {
return myDebugger.loadSource(path);
}
@Override
- public boolean isVariable(String name) {
+ public boolean canSaveToTemp(String name) {
final Project project = getSession().getProject();
- return PyDebugSupportUtils.isVariable(project, name);
+ return PyDebugSupportUtils.canSaveToTemp(project, name);
}
private PyStackFrame currentFrame() throws PyDebuggerException {
diff --git a/python/src/com/jetbrains/python/debugger/PyDebugSupportUtils.java b/python/src/com/jetbrains/python/debugger/PyDebugSupportUtils.java
index d29259d559c6..d25596a13f2a 100644
--- a/python/src/com/jetbrains/python/debugger/PyDebugSupportUtils.java
+++ b/python/src/com/jetbrains/python/debugger/PyDebugSupportUtils.java
@@ -80,25 +80,29 @@ public class PyDebugSupportUtils {
element instanceof PyNamedParameter;
}
- // is expression a variable reference
+ // is expression a variable reference and can be evaluated
// todo: use patterns (?)
- public static boolean isVariable(final Project project, final String expression) {
+ public static boolean canSaveToTemp(final Project project, final String expression) {
return ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
public Boolean compute() {
final PsiFile file = PyElementGenerator.getInstance(project).createDummyFile(LanguageLevel.getDefault(), expression);
final PsiElement root = file.getFirstChild();
- return root instanceof PyExpressionStatement &&
- root.getFirstChild() instanceof PyReferenceExpression &&
- root.getFirstChild() == root.getLastChild() &&
- root.getFirstChild().getFirstChild() != null &&
- root.getFirstChild().getFirstChild().getNode().getElementType() == PyTokenTypes.IDENTIFIER &&
- root.getFirstChild().getFirstChild() == root.getFirstChild().getLastChild() &&
- root.getFirstChild().getFirstChild().getFirstChild() == null;
+ return !isVariable(root) && (root instanceof PyExpressionStatement);
}
});
}
+ private static Boolean isVariable(PsiElement root) {
+ return root instanceof PyExpressionStatement &&
+ root.getFirstChild() instanceof PyReferenceExpression &&
+ root.getFirstChild() == root.getLastChild() &&
+ root.getFirstChild().getFirstChild() != null &&
+ root.getFirstChild().getFirstChild().getNode().getElementType() == PyTokenTypes.IDENTIFIER &&
+ root.getFirstChild().getFirstChild() == root.getFirstChild().getLastChild() &&
+ root.getFirstChild().getFirstChild().getFirstChild() == null;
+ }
+
@Nullable
private static String getLineText(@NotNull Document document, int line) {
if (line > 0 && line < document.getLineCount()) {
diff --git a/python/src/com/jetbrains/python/debugger/PyExceptionBreakpointProperties.java b/python/src/com/jetbrains/python/debugger/PyExceptionBreakpointProperties.java
index d6bfd13f488c..93f9d89e386c 100644
--- a/python/src/com/jetbrains/python/debugger/PyExceptionBreakpointProperties.java
+++ b/python/src/com/jetbrains/python/debugger/PyExceptionBreakpointProperties.java
@@ -39,6 +39,7 @@ public class PyExceptionBreakpointProperties extends ExceptionBreakpointProperti
public PyExceptionBreakpointProperties(@NotNull final String exception) {
myException = exception;
+ myNotifyOnTerminate = true;
}
@Override
@@ -78,6 +79,10 @@ public class PyExceptionBreakpointProperties extends ExceptionBreakpointProperti
myNotifyOnlyOnFirst = notifyOnlyOnFirst;
}
+ public String getException() {
+ return "python-" + myException;
+ }
+
@Override
public ExceptionBreakpointCommand createAddCommand(RemoteDebugger debugger) {
return ExceptionBreakpointCommand.addExceptionBreakpointCommand(debugger, getException(),
diff --git a/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java b/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java
index 913ed65f1e53..73a0cb604091 100644
--- a/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java
+++ b/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java
@@ -81,7 +81,16 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i
@NonNls private static final String EPYDOC_PREFIX = "@";
// provides ctrl+hover info
- public String getQuickNavigateInfo(final PsiElement element, PsiElement originalElement) {
+ @Override
+ @Nullable
+ public String getQuickNavigateInfo(final PsiElement element, final PsiElement originalElement) {
+ for (final PythonDocumentationQuickInfoProvider point : PythonDocumentationQuickInfoProvider.EP_NAME.getExtensions()) {
+ String info = point.getQuickInfo(originalElement);
+ if (info != null) {
+ return info;
+ }
+ }
+
if (element instanceof PyFunction) {
PyFunction func = (PyFunction)element;
StringBuilder cat = new StringBuilder();
@@ -637,8 +646,9 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i
String raiseTarget = visitor.myRaiseTarget.getText();
if (visitor.myRaiseTarget instanceof PyCallExpression) {
final PyExpression callee = ((PyCallExpression)visitor.myRaiseTarget).getCallee();
- if (callee != null)
+ if (callee != null) {
raiseTarget = callee.getText();
+ }
}
builder.append(" ").append(raiseTarget);
}
diff --git a/python/src/com/jetbrains/python/findUsages/PyFunctionFindUsagesHandler.java b/python/src/com/jetbrains/python/findUsages/PyFunctionFindUsagesHandler.java
index 8c96916c9d80..fa7cf1b429c4 100644
--- a/python/src/com/jetbrains/python/findUsages/PyFunctionFindUsagesHandler.java
+++ b/python/src/com/jetbrains/python/findUsages/PyFunctionFindUsagesHandler.java
@@ -27,12 +27,12 @@ import java.util.List;
public class PyFunctionFindUsagesHandler extends FindUsagesHandler {
private final List<PsiElement> myAllElements;
- protected PyFunctionFindUsagesHandler(@NotNull PsiElement psiElement) {
+ public PyFunctionFindUsagesHandler(@NotNull PsiElement psiElement) {
super(psiElement);
myAllElements = null;
}
- protected PyFunctionFindUsagesHandler(@NotNull PsiElement psiElement, List<PsiElement> allElements) {
+ public PyFunctionFindUsagesHandler(@NotNull PsiElement psiElement, List<PsiElement> allElements) {
super(psiElement);
myAllElements = allElements;
}
diff --git a/python/src/com/jetbrains/python/hierarchy/PyTypeHierarchyNodeDescriptor.java b/python/src/com/jetbrains/python/hierarchy/PyHierarchyNodeDescriptor.java
index ea8c250b2e4f..c9720fb01af3 100644
--- a/python/src/com/jetbrains/python/hierarchy/PyTypeHierarchyNodeDescriptor.java
+++ b/python/src/com/jetbrains/python/hierarchy/PyHierarchyNodeDescriptor.java
@@ -19,15 +19,14 @@ import com.intellij.ide.IdeBundle;
import com.intellij.ide.hierarchy.HierarchyNodeDescriptor;
import com.intellij.ide.util.treeView.NodeDescriptor;
import com.intellij.navigation.ItemPresentation;
-import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.roots.ui.util.CompositeAppearance;
import com.intellij.openapi.util.Comparing;
import com.intellij.psi.NavigatablePsiElement;
import com.intellij.psi.PsiElement;
import com.jetbrains.python.psi.PyClass;
+import com.jetbrains.python.psi.PyFunction;
import org.jetbrains.annotations.NotNull;
-
-import java.awt.*;
+import org.jetbrains.annotations.Nullable;
/**
* Created by IntelliJ IDEA.
@@ -35,14 +34,14 @@ import java.awt.*;
* Date: Jul 31, 2009
* Time: 6:26:37 PM
*/
-public class PyTypeHierarchyNodeDescriptor extends HierarchyNodeDescriptor {
-
- public PyTypeHierarchyNodeDescriptor(final NodeDescriptor parentDescriptor, @NotNull final PsiElement element, final boolean isBase) {
+public class PyHierarchyNodeDescriptor extends HierarchyNodeDescriptor {
+ public PyHierarchyNodeDescriptor(final NodeDescriptor parentDescriptor, @NotNull final PsiElement element, final boolean isBase) {
super(element.getProject(), parentDescriptor, element, isBase);
}
- public PyClass getClassElement() {
- return (PyClass)myElement;
+ @Nullable
+ public PsiElement getPsiElement() {
+ return myElement;
}
public boolean isValid() {
@@ -55,10 +54,6 @@ public class PyTypeHierarchyNodeDescriptor extends HierarchyNodeDescriptor {
final CompositeAppearance oldText = myHighlightedText;
myHighlightedText = new CompositeAppearance();
- TextAttributes classNameAttributes = null;
- if (myColor != null) {
- classNameAttributes = new TextAttributes(myColor, null, null, null, Font.PLAIN);
- }
NavigatablePsiElement element = (NavigatablePsiElement)myElement;
if (element == null) {
@@ -71,10 +66,14 @@ public class PyTypeHierarchyNodeDescriptor extends HierarchyNodeDescriptor {
final ItemPresentation presentation = element.getPresentation();
if (presentation != null) {
- final PyClass cl = getClassElement();
- myHighlightedText.getEnding().addText(cl.getName(), classNameAttributes);
- myHighlightedText.getEnding()
- .addText(" (" + cl.getContainingFile().getName() + ")", HierarchyNodeDescriptor.getPackageNameAttributes());
+ if (element instanceof PyFunction) {
+ final PyClass cls = ((PyFunction)element).getContainingClass();
+ if (cls != null) {
+ myHighlightedText.getEnding().addText(cls.getName() + ".");
+ }
+ }
+ myHighlightedText.getEnding().addText(presentation.getPresentableText());
+ myHighlightedText.getEnding().addText(" " + presentation.getLocationString(), HierarchyNodeDescriptor.getPackageNameAttributes());
}
myName = myHighlightedText.getText();
diff --git a/python/src/com/jetbrains/python/hierarchy/PyTypeHierarchyBrowser.java b/python/src/com/jetbrains/python/hierarchy/PyTypeHierarchyBrowser.java
index 643440571618..817d462044fe 100644
--- a/python/src/com/jetbrains/python/hierarchy/PyTypeHierarchyBrowser.java
+++ b/python/src/com/jetbrains/python/hierarchy/PyTypeHierarchyBrowser.java
@@ -52,10 +52,10 @@ public class PyTypeHierarchyBrowser extends TypeHierarchyBrowserBase {
@Nullable
protected PsiElement getElementFromDescriptor(@NotNull HierarchyNodeDescriptor descriptor) {
- if (!(descriptor instanceof PyTypeHierarchyNodeDescriptor)) {
+ if (!(descriptor instanceof PyHierarchyNodeDescriptor)) {
return null;
}
- return ((PyTypeHierarchyNodeDescriptor)descriptor).getClassElement();
+ return ((PyHierarchyNodeDescriptor)descriptor).getPsiElement();
}
protected void createTrees(@NotNull Map<String, JTree> trees) {
diff --git a/python/src/com/jetbrains/python/hierarchy/call/PyCallHierarchyBrowser.java b/python/src/com/jetbrains/python/hierarchy/call/PyCallHierarchyBrowser.java
new file mode 100644
index 000000000000..c5224e617ec9
--- /dev/null
+++ b/python/src/com/jetbrains/python/hierarchy/call/PyCallHierarchyBrowser.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.hierarchy.call;
+
+import com.intellij.ide.hierarchy.CallHierarchyBrowserBase;
+import com.intellij.ide.hierarchy.HierarchyNodeDescriptor;
+import com.intellij.ide.hierarchy.HierarchyTreeStructure;
+import com.intellij.ide.util.treeView.NodeDescriptor;
+import com.intellij.openapi.actionSystem.*;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.psi.PsiElement;
+import com.intellij.ui.PopupHandler;
+import com.jetbrains.python.hierarchy.PyHierarchyNodeDescriptor;
+import com.jetbrains.python.hierarchy.PyHierarchyUtils;
+import com.jetbrains.python.psi.PyClass;
+import com.jetbrains.python.psi.PyFile;
+import com.jetbrains.python.psi.PyFunction;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.util.Comparator;
+import java.util.Map;
+
+/**
+ * @author novokrest
+ */
+public class PyCallHierarchyBrowser extends CallHierarchyBrowserBase {
+ private static final Logger LOG = Logger.getInstance("#com.jetbrains.python.hierarchy.call.PyCallHierarchyBrowser");
+ private static final String GROUP_PY_CALL_HIERARCHY_POPUP = "PyCallHierarchyPopupMenu";
+
+ public PyCallHierarchyBrowser(PsiElement function) {
+ super(function.getProject(), function);
+ }
+
+ @Nullable
+ @Override
+ protected PsiElement getElementFromDescriptor(@NotNull HierarchyNodeDescriptor descriptor) {
+ if (descriptor instanceof PyHierarchyNodeDescriptor) {
+ PyHierarchyNodeDescriptor pyDescriptor = (PyHierarchyNodeDescriptor)descriptor;
+ return pyDescriptor.getPsiElement();
+ }
+ return null;
+ }
+
+ @Override
+ protected void createTrees(@NotNull Map<String, JTree> type2TreeMap) {
+ final ActionGroup group = (ActionGroup)ActionManager.getInstance().getAction(GROUP_PY_CALL_HIERARCHY_POPUP);
+
+ final JTree callerTree = createHierarchyTree(group);
+ final JTree calleeTree = createHierarchyTree(group);
+
+ type2TreeMap.put(CALLER_TYPE, callerTree);
+ type2TreeMap.put(CALLEE_TYPE, calleeTree);
+ }
+
+ private JTree createHierarchyTree(ActionGroup group) {
+ final JTree tree = createTree(false);
+ PopupHandler.installPopupHandler(tree, group, ActionPlaces.CALL_HIERARCHY_VIEW_POPUP, ActionManager.getInstance());
+ return tree;
+ }
+
+ @Override
+ protected boolean isApplicableElement(@NotNull PsiElement element) {
+ return element instanceof PyFunction || element instanceof PyClass || element instanceof PyFile;
+ }
+
+ @Nullable
+ @Override
+ protected HierarchyTreeStructure createHierarchyTreeStructure(@NotNull String typeName, @NotNull PsiElement psiElement) {
+ if (CALLER_TYPE.equals(typeName)) {
+ return new PyCallerFunctionTreeStructure(myProject, psiElement, getCurrentScopeType());
+ }
+ else if (CALLEE_TYPE.equals(typeName)) {
+ return new PyCalleeFunctionTreeStructure(myProject, psiElement, getCurrentScopeType());
+ }
+ else {
+ LOG.error("unexpected type: " + typeName);
+ return null;
+ }
+ }
+
+ @Nullable
+ @Override
+ protected Comparator<NodeDescriptor> getComparator() {
+ return PyHierarchyUtils.getComparator(myProject);
+ }
+}
diff --git a/python/src/com/jetbrains/python/hierarchy/call/PyCallHierarchyProvider.java b/python/src/com/jetbrains/python/hierarchy/call/PyCallHierarchyProvider.java
new file mode 100644
index 000000000000..67c0d6ddfa0b
--- /dev/null
+++ b/python/src/com/jetbrains/python/hierarchy/call/PyCallHierarchyProvider.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.hierarchy.call;
+
+import com.intellij.codeInsight.TargetElementUtilBase;
+import com.intellij.ide.hierarchy.CallHierarchyBrowserBase;
+import com.intellij.ide.hierarchy.HierarchyBrowser;
+import com.intellij.ide.hierarchy.HierarchyProvider;
+import com.intellij.openapi.actionSystem.CommonDataKeys;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.jetbrains.python.psi.PyClass;
+import com.jetbrains.python.psi.PyFile;
+import com.jetbrains.python.psi.PyFunction;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author novokrest
+ */
+public class PyCallHierarchyProvider implements HierarchyProvider {
+ @Nullable
+ @Override
+ public PsiElement getTarget(@NotNull DataContext dataContext) {
+ Project project = CommonDataKeys.PROJECT.getData(dataContext);
+ if (project == null) return null;
+
+ PsiElement element = CommonDataKeys.PSI_ELEMENT.getData(dataContext);
+ if (element == null) {
+ Editor editor = CommonDataKeys.EDITOR.getData(dataContext);
+ if (editor != null) {
+ PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
+ if (file == null) return null;
+
+ element = TargetElementUtilBase.findTargetElement(editor, TargetElementUtilBase.ELEMENT_NAME_ACCEPTED |
+ TargetElementUtilBase.REFERENCED_ELEMENT_ACCEPTED |
+ TargetElementUtilBase.LOOKUP_ITEM_ACCEPTED);
+ if (element instanceof PyFunction || element instanceof PyClass || element instanceof PyFile) {
+ return element;
+ }
+
+ element = file.findElementAt(editor.getCaretModel().getOffset());
+ }
+ }
+ return PsiTreeUtil.getNonStrictParentOfType(element, PyFunction.class, PyClass.class, PyFile.class);
+ }
+
+ @NotNull
+ @Override
+ public HierarchyBrowser createHierarchyBrowser(PsiElement target) {
+ return new PyCallHierarchyBrowser(target);
+ }
+
+ @Override
+ public void browserActivated(@NotNull HierarchyBrowser hierarchyBrowser) {
+ ((PyCallHierarchyBrowser)hierarchyBrowser).changeView(CallHierarchyBrowserBase.CALLER_TYPE);
+ }
+}
diff --git a/python/src/com/jetbrains/python/hierarchy/call/PyCallHierarchyTreeStructureBase.java b/python/src/com/jetbrains/python/hierarchy/call/PyCallHierarchyTreeStructureBase.java
new file mode 100644
index 000000000000..c5d60138299c
--- /dev/null
+++ b/python/src/com/jetbrains/python/hierarchy/call/PyCallHierarchyTreeStructureBase.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.hierarchy.call;
+
+import com.intellij.ide.hierarchy.HierarchyNodeDescriptor;
+import com.intellij.ide.hierarchy.HierarchyTreeStructure;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiElement;
+import com.intellij.util.ArrayUtil;
+import com.jetbrains.python.hierarchy.PyHierarchyNodeDescriptor;
+import com.jetbrains.python.psi.PyClass;
+import com.jetbrains.python.psi.PyElement;
+import com.jetbrains.python.psi.PyFile;
+import com.jetbrains.python.psi.PyFunction;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * @author novokrest
+ */
+public abstract class PyCallHierarchyTreeStructureBase extends HierarchyTreeStructure {
+ private final String myScopeType;
+
+ public PyCallHierarchyTreeStructureBase(Project project, PsiElement element, String currentScopeType) {
+ super(project, new PyHierarchyNodeDescriptor(null, element, true));
+ myScopeType = currentScopeType;
+ }
+
+ @NotNull
+ protected abstract List<PsiElement> getChildren(@NotNull PyElement element);
+
+ @NotNull
+ @Override
+ protected Object[] buildChildren(@NotNull HierarchyNodeDescriptor descriptor) {
+ final List<PyHierarchyNodeDescriptor> descriptors = new ArrayList<PyHierarchyNodeDescriptor>();
+ if (descriptor instanceof PyHierarchyNodeDescriptor) {
+ final PyHierarchyNodeDescriptor pyDescriptor = (PyHierarchyNodeDescriptor)descriptor;
+ final PsiElement element = pyDescriptor.getPsiElement();
+ final boolean isCallable = element instanceof PyFunction || element instanceof PyClass || element instanceof PyFile;
+ HierarchyNodeDescriptor nodeDescriptor = getBaseDescriptor();
+ if (!(element instanceof PyElement) || !isCallable || nodeDescriptor == null) {
+ return ArrayUtil.EMPTY_OBJECT_ARRAY;
+ }
+
+ final List<PsiElement> children = getChildren((PyElement)element);
+
+ final HashMap<PsiElement, PyHierarchyNodeDescriptor> callerToDescriptorMap = new HashMap<PsiElement, PyHierarchyNodeDescriptor>();
+ PsiElement baseClass = element instanceof PyFunction ? ((PyFunction)element).getContainingClass() : null;
+
+ for (PsiElement caller : children) {
+ if (isInScope(baseClass, caller, myScopeType)) {
+ PyHierarchyNodeDescriptor callerDescriptor = callerToDescriptorMap.get(caller);
+ if (callerDescriptor == null) {
+ callerDescriptor = new PyHierarchyNodeDescriptor(descriptor, caller, false);
+ callerToDescriptorMap.put(caller, callerDescriptor);
+ descriptors.add(callerDescriptor);
+ }
+ }
+ }
+
+ }
+ return ArrayUtil.toObjectArray(descriptors);
+ }
+
+ @Override
+ public boolean isAlwaysShowPlus() {
+ return true;
+ }
+}
diff --git a/python/src/com/jetbrains/python/hierarchy/call/PyCalleeFunctionTreeStructure.java b/python/src/com/jetbrains/python/hierarchy/call/PyCalleeFunctionTreeStructure.java
new file mode 100644
index 000000000000..b0465083ef05
--- /dev/null
+++ b/python/src/com/jetbrains/python/hierarchy/call/PyCalleeFunctionTreeStructure.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.hierarchy.call;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiElement;
+import com.jetbrains.python.psi.PyElement;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author novokrest
+ */
+public class PyCalleeFunctionTreeStructure extends PyCallHierarchyTreeStructureBase {
+ public PyCalleeFunctionTreeStructure(Project project, PsiElement element, String currentScopeType) {
+ super(project, element, currentScopeType);
+ }
+
+ @NotNull
+ @Override
+ protected List<PsiElement> getChildren(@NotNull PyElement element) {
+ final List<PsiElement> callees = new ArrayList<PsiElement>();
+ // TODO: Add callees from the dynamic call data manager
+ callees.addAll(PyStaticCallHierarchyUtil.getCallees(element));
+ return callees;
+ }
+}
diff --git a/python/src/com/jetbrains/python/hierarchy/call/PyCallerFunctionTreeStructure.java b/python/src/com/jetbrains/python/hierarchy/call/PyCallerFunctionTreeStructure.java
new file mode 100644
index 000000000000..d45e79ce8d95
--- /dev/null
+++ b/python/src/com/jetbrains/python/hierarchy/call/PyCallerFunctionTreeStructure.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.hierarchy.call;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiElement;
+import com.jetbrains.python.psi.PyElement;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author novokrest
+ */
+public class PyCallerFunctionTreeStructure extends PyCallHierarchyTreeStructureBase {
+ public PyCallerFunctionTreeStructure(Project project, PsiElement element, String currentScopeType) {
+ super(project, element, currentScopeType);
+ }
+
+ @NotNull
+ @Override
+ protected List<PsiElement> getChildren(@NotNull PyElement element) {
+ final List<PsiElement> callers = new ArrayList<PsiElement>();
+ // TODO: Add callers from the dynamic call data manager
+ callers.addAll(PyStaticCallHierarchyUtil.getCallers(element));
+ return callers;
+ }
+}
diff --git a/python/src/com/jetbrains/python/hierarchy/call/PyStaticCallHierarchyUtil.java b/python/src/com/jetbrains/python/hierarchy/call/PyStaticCallHierarchyUtil.java
new file mode 100644
index 000000000000..5657dcb589e9
--- /dev/null
+++ b/python/src/com/jetbrains/python/hierarchy/call/PyStaticCallHierarchyUtil.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.hierarchy.call;
+
+import com.google.common.collect.Lists;
+import com.intellij.find.findUsages.FindUsagesHandler;
+import com.intellij.find.findUsages.FindUsagesOptions;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.usageView.UsageInfo;
+import com.intellij.util.ArrayUtil;
+import com.intellij.util.CommonProcessors;
+import com.jetbrains.python.PyNames;
+import com.jetbrains.python.findUsages.PyClassFindUsagesHandler;
+import com.jetbrains.python.findUsages.PyFunctionFindUsagesHandler;
+import com.jetbrains.python.psi.*;
+import com.jetbrains.python.psi.impl.PyBuiltinCache;
+import com.jetbrains.python.psi.resolve.PyResolveContext;
+import com.jetbrains.python.psi.search.PySuperMethodsSearch;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * @author novokrest
+ */
+public class PyStaticCallHierarchyUtil {
+ public static Collection<PsiElement> getCallees(@NotNull PyElement element) {
+ final List<PsiElement> callees = Lists.newArrayList();
+
+ final PyRecursiveElementVisitor visitor = new PyRecursiveElementVisitor() {
+ @Override
+ public void visitPyParameterList(PyParameterList node) {
+ }
+
+ @Override
+ public void visitPyLambdaExpression(PyLambdaExpression node) {
+ }
+
+ @Override
+ public void visitPyFunction(PyFunction innerFunction) {
+ for (PyParameter parameter : innerFunction.getParameterList().getParameters()) {
+ PsiElement defaultValue = parameter.getDefaultValue();
+ if (defaultValue != null) {
+ defaultValue.accept(this);
+ }
+ }
+ }
+
+ @Override
+ public void visitPyCallExpression(PyCallExpression callExpression) {
+ super.visitPyCallExpression(callExpression);
+ PsiElement calleeFunction = callExpression.resolveCalleeFunction(PyResolveContext.defaultContext());
+ if (calleeFunction instanceof PyFunction) {
+ callees.add(calleeFunction);
+ }
+ }
+ };
+
+ visitor.visitElement(element);
+
+ return callees;
+ }
+
+ public static Collection<PsiElement> getCallers(@NotNull PyElement pyElement) {
+ final List<PsiElement> callers = Lists.newArrayList();
+ final Collection<UsageInfo> usages = findUsages(pyElement);
+
+ for (UsageInfo usage : usages) {
+ PsiElement element = usage.getElement();
+ if (element == null) {
+ continue;
+ }
+
+ element = element.getParent();
+ while (element instanceof PyParenthesizedExpression) {
+ element = element.getParent();
+ }
+
+ if (element instanceof PyCallExpression) {
+ PsiElement caller = PsiTreeUtil.getParentOfType(element, PyParameterList.class, PyFunction.class);
+ if (caller instanceof PyFunction) {
+ callers.add(caller);
+ }
+ else if (caller instanceof PyParameterList) {
+ PsiElement innerFunction = PsiTreeUtil.getParentOfType(caller, PyFunction.class);
+ PsiElement outerFunction = PsiTreeUtil.getParentOfType(innerFunction, PyFunction.class);
+ if (innerFunction != null && outerFunction != null) {
+ callers.add(outerFunction);
+ }
+ }
+ }
+ }
+
+ return callers;
+ }
+
+ private static Collection<UsageInfo> findUsages(@NotNull final PsiElement element) {
+ final FindUsagesHandler handler = createFindUsageHandler(element);
+ if (handler == null) {
+ return Lists.newArrayList();
+ }
+ final CommonProcessors.CollectProcessor<UsageInfo> processor = new CommonProcessors.CollectProcessor<UsageInfo>();
+ final PsiElement[] psiElements = ArrayUtil.mergeArrays(handler.getPrimaryElements(), handler.getSecondaryElements());
+ final FindUsagesOptions options = handler.getFindUsagesOptions(null);
+ for (PsiElement psiElement : psiElements) {
+ handler.processElementUsages(psiElement, processor, options);
+ }
+ return processor.getResults();
+ }
+
+ /**
+ * @see {@link com.jetbrains.python.findUsages.PyFindUsagesHandlerFactory#createFindUsagesHandler(com.intellij.psi.PsiElement, boolean) createFindUsagesHandler}
+ */
+ @Nullable
+ private static FindUsagesHandler createFindUsageHandler(@NotNull final PsiElement element) {
+ if (element instanceof PyFunction) {
+ final Collection<PsiElement> superMethods = PySuperMethodsSearch.search((PyFunction)element, true).findAll();
+ if (superMethods.size() > 0) {
+ final PsiElement next = superMethods.iterator().next();
+ if (next instanceof PyFunction && !isInObject((PyFunction)next)) {
+ List<PsiElement> allMethods = Lists.newArrayList();
+ allMethods.add(element);
+ allMethods.addAll(superMethods);
+
+ return new PyFunctionFindUsagesHandler(element, allMethods);
+ }
+ }
+ return new PyFunctionFindUsagesHandler(element);
+ }
+ if (element instanceof PyClass) {
+ return new PyClassFindUsagesHandler((PyClass)element);
+ }
+ return null;
+ }
+
+ /**
+ * @see {@link com.jetbrains.python.findUsages.PyFindUsagesHandlerFactory#isInObject(com.jetbrains.python.psi.PyFunction) isInObject}
+ */
+ private static boolean isInObject(PyFunction fun) {
+ final PyClass containingClass = fun.getContainingClass();
+ if (containingClass == null) {
+ return false;
+ }
+ return (PyNames.FAKE_OLD_BASE.equals(containingClass.getName()) ||
+ (PyNames.OBJECT.equals(containingClass.getName()) && PyBuiltinCache.getInstance(fun).isBuiltin(containingClass)));
+ }
+}
diff --git a/python/src/com/jetbrains/python/hierarchy/treestructures/PySubTypesHierarchyTreeStructure.java b/python/src/com/jetbrains/python/hierarchy/treestructures/PySubTypesHierarchyTreeStructure.java
index 7b43fe7329cf..f4287b28bd6c 100644
--- a/python/src/com/jetbrains/python/hierarchy/treestructures/PySubTypesHierarchyTreeStructure.java
+++ b/python/src/com/jetbrains/python/hierarchy/treestructures/PySubTypesHierarchyTreeStructure.java
@@ -18,9 +18,10 @@ package com.jetbrains.python.hierarchy.treestructures;
import com.intellij.ide.hierarchy.HierarchyNodeDescriptor;
import com.intellij.ide.hierarchy.HierarchyTreeStructure;
import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiElement;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Query;
-import com.jetbrains.python.hierarchy.PyTypeHierarchyNodeDescriptor;
+import com.jetbrains.python.hierarchy.PyHierarchyNodeDescriptor;
import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.search.PyClassInheritorsSearch;
import org.jetbrains.annotations.NotNull;
@@ -40,17 +41,20 @@ public class PySubTypesHierarchyTreeStructure extends HierarchyTreeStructure {
}
public PySubTypesHierarchyTreeStructure(@NotNull final PyClass cl) {
- super(cl.getProject(), new PyTypeHierarchyNodeDescriptor(null, cl, true));
+ super(cl.getProject(), new PyHierarchyNodeDescriptor(null, cl, true));
}
@NotNull
protected Object[] buildChildren(@NotNull HierarchyNodeDescriptor descriptor) {
- final PyClass classElement = ((PyTypeHierarchyNodeDescriptor)descriptor).getClassElement();
- Query<PyClass> subClasses = PyClassInheritorsSearch.search(classElement, false);
+ final List<PyHierarchyNodeDescriptor> res = new ArrayList<PyHierarchyNodeDescriptor>();
+ final PsiElement element = ((PyHierarchyNodeDescriptor)descriptor).getPsiElement();
+ if (element instanceof PyClass) {
+ final PyClass cls = (PyClass)element;
+ Query<PyClass> subClasses = PyClassInheritorsSearch.search(cls, false);
+ for (PyClass subClass : subClasses) {
+ res.add(new PyHierarchyNodeDescriptor(descriptor, subClass, false));
+ }
- List<PyTypeHierarchyNodeDescriptor> res = new ArrayList<PyTypeHierarchyNodeDescriptor>();
- for (PyClass cl : subClasses) {
- res.add(new PyTypeHierarchyNodeDescriptor(descriptor, cl, false));
}
return ArrayUtil.toObjectArray(res);
diff --git a/python/src/com/jetbrains/python/hierarchy/treestructures/PySuperTypesHierarchyTreeStructure.java b/python/src/com/jetbrains/python/hierarchy/treestructures/PySuperTypesHierarchyTreeStructure.java
index 38b4c6ee7f76..8087767c61d8 100644
--- a/python/src/com/jetbrains/python/hierarchy/treestructures/PySuperTypesHierarchyTreeStructure.java
+++ b/python/src/com/jetbrains/python/hierarchy/treestructures/PySuperTypesHierarchyTreeStructure.java
@@ -17,8 +17,8 @@ package com.jetbrains.python.hierarchy.treestructures;
import com.intellij.ide.hierarchy.HierarchyNodeDescriptor;
import com.intellij.ide.hierarchy.HierarchyTreeStructure;
-import com.intellij.openapi.project.Project;
-import com.jetbrains.python.hierarchy.PyTypeHierarchyNodeDescriptor;
+import com.intellij.psi.PsiElement;
+import com.jetbrains.python.hierarchy.PyHierarchyNodeDescriptor;
import com.jetbrains.python.psi.PyClass;
import org.jetbrains.annotations.NotNull;
@@ -32,20 +32,23 @@ import java.util.List;
* Time: 7:04:07 PM
*/
public class PySuperTypesHierarchyTreeStructure extends HierarchyTreeStructure {
- protected PySuperTypesHierarchyTreeStructure(final Project project, final HierarchyNodeDescriptor baseDescriptor) {
- super(project, baseDescriptor);
- }
-
public PySuperTypesHierarchyTreeStructure(@NotNull final PyClass cl) {
- super(cl.getProject(), new PyTypeHierarchyNodeDescriptor(null, cl, true));
+ super(cl.getProject(), new PyHierarchyNodeDescriptor(null, cl, true));
}
@NotNull
protected Object[] buildChildren(@NotNull HierarchyNodeDescriptor descriptor) {
- final PyClass[] superClasses = ((PyTypeHierarchyNodeDescriptor)descriptor).getClassElement().getSuperClasses();
- List<PyTypeHierarchyNodeDescriptor> res = new ArrayList<PyTypeHierarchyNodeDescriptor>();
- for (PyClass superClass : superClasses) {
- res.add(new PyTypeHierarchyNodeDescriptor(descriptor, superClass, false));
+ final List<PyHierarchyNodeDescriptor> res = new ArrayList<PyHierarchyNodeDescriptor>();
+ if (descriptor instanceof PyHierarchyNodeDescriptor) {
+ final PyHierarchyNodeDescriptor pyDescriptor = (PyHierarchyNodeDescriptor)descriptor;
+ final PsiElement element = pyDescriptor.getPsiElement();
+ if (element instanceof PyClass) {
+ final PyClass cls = (PyClass)element;
+ final PyClass[] superClasses = cls.getSuperClasses();
+ for (PyClass superClass : superClasses) {
+ res.add(new PyHierarchyNodeDescriptor(descriptor, superClass, false));
+ }
+ }
}
return res.toArray();
}
diff --git a/python/src/com/jetbrains/python/hierarchy/treestructures/PyTypeHierarchyTreeStructure.java b/python/src/com/jetbrains/python/hierarchy/treestructures/PyTypeHierarchyTreeStructure.java
index 6707ac9b7e14..0eb505f4857b 100644
--- a/python/src/com/jetbrains/python/hierarchy/treestructures/PyTypeHierarchyTreeStructure.java
+++ b/python/src/com/jetbrains/python/hierarchy/treestructures/PyTypeHierarchyTreeStructure.java
@@ -16,8 +16,7 @@
package com.jetbrains.python.hierarchy.treestructures;
import com.intellij.ide.hierarchy.HierarchyNodeDescriptor;
-import com.intellij.openapi.project.Project;
-import com.jetbrains.python.hierarchy.PyTypeHierarchyNodeDescriptor;
+import com.jetbrains.python.hierarchy.PyHierarchyNodeDescriptor;
import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.PyUtil;
import org.jetbrains.annotations.NotNull;
@@ -28,30 +27,26 @@ import java.util.List;
* @author Alexey.Ivanov
*/
public class PyTypeHierarchyTreeStructure extends PySubTypesHierarchyTreeStructure {
- private static PyTypeHierarchyNodeDescriptor buildHierarchyElement(@NotNull final PyClass cl) {
- PyTypeHierarchyNodeDescriptor descriptor = null;
+ public PyTypeHierarchyTreeStructure(@NotNull final PyClass cl) {
+ super(cl.getProject(), buildHierarchyElement(cl));
+ setBaseElement(myBaseDescriptor);
+ }
+
+ private static PyHierarchyNodeDescriptor buildHierarchyElement(@NotNull final PyClass cl) {
+ PyHierarchyNodeDescriptor descriptor = null;
List<PyClass> superClasses = PyUtil.getAllSuperClasses(cl);
for (int i = superClasses.size() - 1; i >= 0; --i) {
final PyClass superClass = superClasses.get(i);
- final PyTypeHierarchyNodeDescriptor newDescriptor = new PyTypeHierarchyNodeDescriptor(descriptor, superClass, false);
+ final PyHierarchyNodeDescriptor newDescriptor = new PyHierarchyNodeDescriptor(descriptor, superClass, false);
if (descriptor != null) {
- descriptor.setCachedChildren(new PyTypeHierarchyNodeDescriptor[]{newDescriptor});
+ descriptor.setCachedChildren(new PyHierarchyNodeDescriptor[]{newDescriptor});
}
descriptor = newDescriptor;
}
- final PyTypeHierarchyNodeDescriptor newDescriptor = new PyTypeHierarchyNodeDescriptor(descriptor, cl, true);
+ final PyHierarchyNodeDescriptor newDescriptor = new PyHierarchyNodeDescriptor(descriptor, cl, true);
if (descriptor != null) {
descriptor.setCachedChildren(new HierarchyNodeDescriptor[]{newDescriptor});
}
return newDescriptor;
}
-
- protected PyTypeHierarchyTreeStructure(final Project project, final HierarchyNodeDescriptor baseDescriptor) {
- super(project, baseDescriptor);
- }
-
- public PyTypeHierarchyTreeStructure(@NotNull final PyClass cl) {
- super(cl.getProject(), buildHierarchyElement(cl));
- setBaseElement(myBaseDescriptor);
- }
}
diff --git a/python/src/com/jetbrains/python/inspections/PyPackageRequirementsInspection.java b/python/src/com/jetbrains/python/inspections/PyPackageRequirementsInspection.java
index ec3761154f28..0b73adc3fa4c 100644
--- a/python/src/com/jetbrains/python/inspections/PyPackageRequirementsInspection.java
+++ b/python/src/com/jetbrains/python/inspections/PyPackageRequirementsInspection.java
@@ -27,6 +27,7 @@ import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.JDOMExternalizableStringList;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
@@ -42,6 +43,7 @@ import com.jetbrains.python.packaging.*;
import com.jetbrains.python.packaging.ui.PyChooseRequirementsDialog;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyPsiUtils;
+import com.jetbrains.python.sdk.PySdkUtil;
import com.jetbrains.python.sdk.PythonSdkType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -111,9 +113,7 @@ public class PyPackageRequirementsInspection extends PyInspection {
unsatisfiedNames.add(req.getName());
}
final List<LocalQuickFix> quickFixes = new ArrayList<LocalQuickFix>();
- if (PyPackageManager.getInstance(sdk).hasPip()) {
- quickFixes.add(new PyInstallRequirementsFix(null, module, sdk, unsatisfied));
- }
+ quickFixes.add(new PyInstallRequirementsFix(null, module, sdk, unsatisfied));
quickFixes.add(new IgnoreRequirementFix(unsatisfiedNames));
registerProblem(node, msg,
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, null,
@@ -160,15 +160,16 @@ public class PyPackageRequirementsInspection extends PyInspection {
return;
}
}
- if (PyPackageManagerImpl.PACKAGE_SETUPTOOLS.equals(packageName)) {
+ if (PyPackageManager.PACKAGE_SETUPTOOLS.equals(packageName)) {
return;
}
final Module module = ModuleUtilCore.findModuleForPsiElement(packageReferenceExpression);
if (module != null) {
- Collection<PyRequirement> requirements = PyPackageManagerImpl.getRequirements(module);
- if (requirements != null) {
- final Sdk sdk = PythonSdkType.findPythonSdk(module);
- if (sdk != null) {
+ final Sdk sdk = PythonSdkType.findPythonSdk(module);
+ if (sdk != null) {
+ final PyPackageManager manager = PyPackageManager.getInstance(sdk);
+ Collection<PyRequirement> requirements = manager.getRequirements(module);
+ if (requirements != null) {
requirements = getTransitiveRequirements(sdk, requirements, new HashSet<PyPackage>());
}
if (requirements == null) return;
@@ -191,9 +192,7 @@ public class PyPackageRequirementsInspection extends PyInspection {
}
}
final List<LocalQuickFix> quickFixes = new ArrayList<LocalQuickFix>();
- if (sdk != null && PyPackageManager.getInstance(sdk).hasPip()) {
- quickFixes.add(new AddToRequirementsFix(module, packageName, LanguageLevel.forElement(importedExpression)));
- }
+ quickFixes.add(new AddToRequirementsFix(module, packageName, LanguageLevel.forElement(importedExpression)));
quickFixes.add(new IgnoreRequirementFix(Collections.singleton(packageName)));
registerProblem(packageReferenceExpression, String.format("Package '%s' is not listed in project requirements", packageName),
ProblemHighlightType.WEAK_WARNING, null,
@@ -211,7 +210,7 @@ public class PyPackageRequirementsInspection extends PyInspection {
final Set<PyRequirement> results = new HashSet<PyRequirement>(requirements);
final List<PyPackage> packages;
try {
- packages = ((PyPackageManagerImpl) PyPackageManager.getInstance(sdk)).getPackagesFast();
+ packages = PyPackageManager.getInstance(sdk).getPackages(PySdkUtil.isRemote(sdk));
}
catch (PyExternalProcessException e) {
return null;
@@ -242,12 +241,12 @@ public class PyPackageRequirementsInspection extends PyInspection {
@Nullable
private static List<PyRequirement> findUnsatisfiedRequirements(@NotNull Module module, @NotNull Sdk sdk,
@NotNull Set<String> ignoredPackages) {
- final PyPackageManagerImpl manager = (PyPackageManagerImpl)PyPackageManager.getInstance(sdk);
- List<PyRequirement> requirements = PyPackageManagerImpl.getRequirements(module);
+ final PyPackageManager manager = PyPackageManager.getInstance(sdk);
+ List<PyRequirement> requirements = manager.getRequirements(module);
if (requirements != null) {
final List<PyPackage> packages;
try {
- packages = manager.getPackagesFast();
+ packages = manager.getPackages(PySdkUtil.isRemote(sdk));
}
catch (PyExternalProcessException e) {
return null;
@@ -265,11 +264,11 @@ public class PyPackageRequirementsInspection extends PyInspection {
}
private static void setRunningPackagingTasks(@NotNull Module module, boolean value) {
- module.putUserData(PyPackageManagerImpl.RUNNING_PACKAGING_TASKS, value);
+ module.putUserData(PyPackageManager.RUNNING_PACKAGING_TASKS, value);
}
private static boolean isRunningPackagingTasks(@NotNull Module module) {
- final Boolean value = module.getUserData(PyPackageManagerImpl.RUNNING_PACKAGING_TASKS);
+ final Boolean value = module.getUserData(PyPackageManager.RUNNING_PACKAGING_TASKS);
return value != null && value;
}
@@ -302,6 +301,21 @@ public class PyPackageRequirementsInspection extends PyInspection {
@Override
public void applyFix(@NotNull final Project project, @NotNull ProblemDescriptor descriptor) {
+ boolean installManagement = false;
+ final PyPackageManager manager = PyPackageManager.getInstance(mySdk);
+ if (!manager.hasManagement(false)) {
+ final int result = Messages.showYesNoDialog(project,
+ "Python packaging tools are required for installing packages. Do you want to " +
+ "install 'pip' and 'setuptools' for your interpreter?",
+ "Install Python Packaging Tools",
+ Messages.getQuestionIcon());
+ if (result == Messages.YES) {
+ installManagement = true;
+ }
+ else {
+ return;
+ }
+ }
final List<PyRequirement> chosen;
if (myUnsatisfied.size() > 1) {
final PyChooseRequirementsDialog dialog = new PyChooseRequirementsDialog(project, myUnsatisfied);
@@ -313,21 +327,48 @@ public class PyPackageRequirementsInspection extends PyInspection {
if (chosen.isEmpty()) {
return;
}
- final PyPackageManagerImpl.UI ui = new PyPackageManagerImpl.UI(project, mySdk, new PyPackageManagerImpl.UI.Listener() {
- @Override
- public void started() {
- setRunningPackagingTasks(myModule, true);
- }
+ if (installManagement) {
+ final PyPackageManagerUI ui = new PyPackageManagerUI(project, mySdk, new UIListener(myModule) {
+ @Override
+ public void finished(List<PyExternalProcessException> exceptions) {
+ super.finished(exceptions);
+ if (exceptions.isEmpty()) {
+ installRequirements(project, chosen);
+ }
+ }
+ });
+ ui.installManagement();
+ }
+ else {
+ installRequirements(project, chosen);
+ }
+ }
- @Override
- public void finished(List<PyExternalProcessException> exceptions) {
- setRunningPackagingTasks(myModule, false);
- }
- });
- ui.install(chosen, Collections.<String>emptyList());
+ private void installRequirements(Project project, List<PyRequirement> requirements) {
+ final PyPackageManagerUI ui = new PyPackageManagerUI(project, mySdk, new UIListener(myModule));
+ ui.install(requirements, Collections.<String>emptyList());
+ }
+ }
+
+ private static class UIListener implements PyPackageManagerUI.Listener {
+ private final Module myModule;
+
+ public UIListener(Module module) {
+ myModule = module;
+ }
+
+ @Override
+ public void started() {
+ setRunningPackagingTasks(myModule, true);
+ }
+
+ @Override
+ public void finished(List<PyExternalProcessException> exceptions) {
+ setRunningPackagingTasks(myModule, false);
}
}
+
private static class IgnoreRequirementFix implements LocalQuickFix {
@NotNull private final Set<String> myPackageNames;
diff --git a/python/src/com/jetbrains/python/inspections/quickfix/GenerateBinaryStubsFix.java b/python/src/com/jetbrains/python/inspections/quickfix/GenerateBinaryStubsFix.java
index 7d087bd3eb08..17600d32befb 100644
--- a/python/src/com/jetbrains/python/inspections/quickfix/GenerateBinaryStubsFix.java
+++ b/python/src/com/jetbrains/python/inspections/quickfix/GenerateBinaryStubsFix.java
@@ -170,7 +170,7 @@ public class GenerateBinaryStubsFix implements LocalQuickFix {
new String[]{
homePath,
PythonHelpersLocator.getHelperPath("extra_syspath.py"), myQualifiedName},
- PythonSdkType.getVirtualEnvAdditionalEnv(homePath), 5000
+ PythonSdkType.getVirtualEnvExtraEnv(homePath), 5000
);
if (runResult.getExitCode() == 0 && !runResult.isTimeout()) {
final String extraPath = runResult.getStdout();
diff --git a/python/src/com/jetbrains/python/inspections/quickfix/PyDefaultArgumentQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/PyDefaultArgumentQuickFix.java
index db47f17f8ea8..6e0d5c465d0e 100644
--- a/python/src/com/jetbrains/python/inspections/quickfix/PyDefaultArgumentQuickFix.java
+++ b/python/src/com/jetbrains/python/inspections/quickfix/PyDefaultArgumentQuickFix.java
@@ -61,7 +61,7 @@ public class PyDefaultArgumentQuickFix implements LocalQuickFix {
PyStatementList list = function.getStatementList();
PyParameterList paramList = function.getParameterList();
- final StringBuilder functionText = new StringBuilder("def foo(");
+ final StringBuilder functionText = new StringBuilder("def " + function.getName() + "(");
int size = paramList.getParameters().length;
for (int i = 0; i != size; ++i) {
PyParameter p = paramList.getParameters()[i];
diff --git a/python/src/com/jetbrains/python/inspections/quickfix/StatementEffectFunctionCallQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/StatementEffectFunctionCallQuickFix.java
index 43f4f0394015..017bf1a1af29 100644
--- a/python/src/com/jetbrains/python/inspections/quickfix/StatementEffectFunctionCallQuickFix.java
+++ b/python/src/com/jetbrains/python/inspections/quickfix/StatementEffectFunctionCallQuickFix.java
@@ -88,7 +88,13 @@ public class StatementEffectFunctionCallQuickFix implements LocalQuickFix {
if (next instanceof PyExpressionStatement) {
final PyExpression expr = ((PyExpressionStatement)next).getExpression();
if (expr instanceof PyBinaryExpression) {
- addInArguments(stringBuilder, (PyBinaryExpression)expr);
+ final PsiElement operator = ((PyBinaryExpression)expr).getPsiOperator();
+ if (operator instanceof LeafPsiElement && ((LeafPsiElement)operator).getElementType() == PyTokenTypes.IN_KEYWORD) {
+ addInArguments(stringBuilder, (PyBinaryExpression)expr);
+ }
+ else {
+ stringBuilder.append(next.getText());
+ }
}
else if (expr instanceof PyTupleExpression) {
final PyExpression[] elements = ((PyTupleExpression)expr).getElements();
@@ -114,14 +120,11 @@ public class StatementEffectFunctionCallQuickFix implements LocalQuickFix {
}
private static void addInArguments(@NotNull final StringBuilder stringBuilder, @NotNull final PyBinaryExpression binaryExpression) {
- final PsiElement operator = binaryExpression.getPsiOperator();
- if (operator instanceof LeafPsiElement && ((LeafPsiElement)operator).getElementType() == PyTokenTypes.IN_KEYWORD) {
- stringBuilder.append(binaryExpression.getLeftExpression().getText());
- stringBuilder.append(", ");
- final PyExpression rightExpression = binaryExpression.getRightExpression();
- if (rightExpression != null)
- stringBuilder.append(rightExpression.getText());
- }
+ stringBuilder.append(binaryExpression.getLeftExpression().getText());
+ stringBuilder.append(", ");
+ final PyExpression rightExpression = binaryExpression.getRightExpression();
+ if (rightExpression != null)
+ stringBuilder.append(rightExpression.getText());
}
private static void replacePrint(@NotNull final PsiElement expression) {
diff --git a/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java b/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java
index b7523caf90e7..8049546a6e92 100644
--- a/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java
+++ b/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java
@@ -48,7 +48,6 @@ import com.jetbrains.python.documentation.DocStringTypeReference;
import com.jetbrains.python.inspections.*;
import com.jetbrains.python.inspections.quickfix.*;
import com.jetbrains.python.packaging.PyPIPackageUtil;
-import com.jetbrains.python.packaging.PyPackageManager;
import com.jetbrains.python.packaging.PyRequirement;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyBuiltinCache;
@@ -598,9 +597,7 @@ public class PyUnresolvedReferencesInspection extends PyInspection {
if (PyPIPackageUtil.INSTANCE.isInPyPI(packageName)) {
final List<PyRequirement> requirements = Collections.singletonList(new PyRequirement(packageName));
final String name = "Install package " + packageName;
- if (PyPackageManager.getInstance(sdk).hasPip()) {
- actions.add(new PyPackageRequirementsInspection.PyInstallRequirementsFix(name, module, sdk, requirements));
- }
+ actions.add(new PyPackageRequirementsInspection.PyInstallRequirementsFix(name, module, sdk, requirements));
}
}
}
diff --git a/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java b/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java
index 65d95eb62713..9b5f669168f7 100644
--- a/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java
+++ b/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java
@@ -15,31 +15,17 @@
*/
package com.jetbrains.python.packaging;
-import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.process.ProcessOutput;
import com.intellij.execution.util.ExecUtil;
-import com.intellij.icons.AllIcons;
-import com.intellij.notification.Notification;
-import com.intellij.notification.NotificationListener;
-import com.intellij.notification.NotificationType;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
-import com.intellij.openapi.progress.ProgressIndicator;
-import com.intellij.openapi.progress.ProgressManager;
-import com.intellij.openapi.progress.Task;
-import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
-import com.intellij.openapi.projectRoots.SdkAdditionalData;
import com.intellij.openapi.projectRoots.impl.ProjectJdkImpl;
import com.intellij.openapi.roots.OrderRootType;
-import com.intellij.openapi.ui.Messages;
-import com.intellij.openapi.util.Key;
-import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
@@ -49,46 +35,36 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.openapi.vfs.newvfs.BulkFileListener;
import com.intellij.openapi.vfs.newvfs.events.VFileEvent;
-import com.intellij.remote.RemoteFile;
-import com.intellij.remote.RemoteSdkAdditionalData;
-import com.intellij.remote.RemoteSdkCredentials;
-import com.intellij.remote.VagrantNotStartedException;
import com.intellij.util.ArrayUtil;
-import com.intellij.util.Function;
-import com.intellij.util.PathMappingSettings;
-import com.intellij.util.SystemProperties;
import com.intellij.util.containers.HashSet;
import com.intellij.util.messages.MessageBusConnection;
import com.intellij.util.net.HttpConfigurable;
-import com.intellij.webcore.packaging.PackagesNotificationPanel;
import com.jetbrains.python.PythonHelpersLocator;
import com.jetbrains.python.psi.LanguageLevel;
import com.jetbrains.python.psi.PyExpression;
import com.jetbrains.python.psi.PyListLiteralExpression;
import com.jetbrains.python.psi.PyStringLiteralExpression;
-import com.jetbrains.python.remote.PyRemoteSdkAdditionalDataBase;
-import com.jetbrains.python.remote.PythonRemoteInterpreterManager;
import com.jetbrains.python.sdk.PySdkUtil;
import com.jetbrains.python.sdk.PythonSdkType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import javax.swing.event.HyperlinkEvent;
-import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.util.*;
-import java.util.List;
/**
* @author vlan
*/
-@SuppressWarnings({"UnusedDeclaration", "FieldAccessedSynchronizedAndUnsynchronized"})
public class PyPackageManagerImpl extends PyPackageManager {
- private static final Logger LOG = Logger.getInstance(PyPackageManagerImpl.class);
+ // Bundled versions of package management tools
+ public static final String SETUPTOOLS_VERSION = "1.1.5";
+ public static final String PIP_VERSION = "1.4.1";
+
+ public static final String SETUPTOOLS = PACKAGE_SETUPTOOLS + "-" + SETUPTOOLS_VERSION;
+ public static final String PIP = PACKAGE_PIP + "-" + PIP_VERSION;
public static final int OK = 0;
- public static final int ERROR_WRONG_USAGE = 1;
public static final int ERROR_NO_PIP = 2;
public static final int ERROR_NO_SETUPTOOLS = 3;
public static final int ERROR_INVALID_SDK = -1;
@@ -97,260 +73,24 @@ public class PyPackageManagerImpl extends PyPackageManager {
public static final int ERROR_INVALID_OUTPUT = -4;
public static final int ERROR_ACCESS_DENIED = -5;
public static final int ERROR_EXECUTION = -6;
- public static final int ERROR_INTERRUPTED = -7;
- public static final int ERROR_VAGRANT_NOT_LAUNCHED = 101;
- public static final int ERROR_REMOTE_ACCESS = 102;
-
- public static final String PACKAGE_PIP = "pip";
- public static final String PACKAGE_DISTRIBUTE = "distribute";
- public static final String PACKAGE_SETUPTOOLS = "setuptools";
-
- public static final Key<Boolean> RUNNING_PACKAGING_TASKS = Key.create("PyPackageRequirementsInspection.RunningPackagingTasks");
+ private static final Logger LOG = Logger.getInstance(PyPackageManagerImpl.class);
private static final String PACKAGING_TOOL = "packaging_tool.py";
private static final String VIRTUALENV = "virtualenv.py";
private static final int TIMEOUT = 10 * 60 * 1000;
private static final String BUILD_DIR_OPTION = "--build-dir";
- public static final String USE_USER_SITE = "--user";
public static final String INSTALL = "install";
public static final String UNINSTALL = "uninstall";
public static final String UNTAR = "untar";
- // Bundled versions of package management tools
- public static final String SETUPTOOLS_VERSION = "1.1.5";
- public static final String PIP_VERSION = "1.4.1";
-
- public static final String SETUPTOOLS = PACKAGE_SETUPTOOLS + "-" + SETUPTOOLS_VERSION;
- public static final String PIP = PACKAGE_PIP + "-" + PIP_VERSION;
- private static final String LAUNCH_VAGRANT = "launchVagrant";
-
private List<PyPackage> myPackagesCache = null;
private Map<String, Set<PyPackage>> myDependenciesCache = null;
private PyExternalProcessException myExceptionCache = null;
- private Sdk mySdk;
-
- public static class UI {
- @Nullable private Listener myListener;
- @NotNull private Project myProject;
- @NotNull private Sdk mySdk;
-
- public interface Listener {
- void started();
-
- void finished(List<PyExternalProcessException> exceptions);
- }
-
- public UI(@NotNull Project project, @NotNull Sdk sdk, @Nullable Listener listener) {
- myProject = project;
- mySdk = sdk;
- myListener = listener;
- }
-
- public void installManagement(@NotNull final String name) {
- final String progressTitle;
- final String successTitle;
- progressTitle = "Installing package " + name;
- successTitle = "Packages installed successfully";
- run(new MultiExternalRunnable() {
- @Override
- public List<PyExternalProcessException> run(@NotNull ProgressIndicator indicator) {
- final List<PyExternalProcessException> exceptions = new ArrayList<PyExternalProcessException>();
- indicator.setText(String.format("Installing package '%s'...", name));
- final PyPackageManagerImpl manager = (PyPackageManagerImpl)PyPackageManagers.getInstance().forSdk(mySdk);
- try {
- manager.installManagement(name);
- }
- catch (PyExternalProcessException e) {
- exceptions.add(e);
- }
- return exceptions;
- }
- }, progressTitle, successTitle, "Installed package " + name,
- "Install package failed"
- );
- }
-
- public void install(@NotNull final List<PyRequirement> requirements, @NotNull final List<String> extraArgs) {
- final String progressTitle;
- final String successTitle;
- progressTitle = "Installing packages";
- successTitle = "Packages installed successfully";
- run(new MultiExternalRunnable() {
- @Override
- public List<PyExternalProcessException> run(@NotNull ProgressIndicator indicator) {
- final int size = requirements.size();
- final List<PyExternalProcessException> exceptions = new ArrayList<PyExternalProcessException>();
- final PyPackageManagerImpl manager = (PyPackageManagerImpl)PyPackageManagers.getInstance().forSdk(mySdk);
- for (int i = 0; i < size; i++) {
- final PyRequirement requirement = requirements.get(i);
- if (myListener != null) {
- indicator.setText(String.format("Installing package '%s'...", requirement));
- indicator.setFraction((double)i / size);
- }
- try {
- manager.install(list(requirement), extraArgs);
- }
- catch (PyExternalProcessException e) {
- exceptions.add(e);
- }
- }
- manager.refresh();
- return exceptions;
- }
- }, progressTitle, successTitle, "Installed packages: " + PyPackageUtil.requirementsToString(requirements),
- "Install packages failed"
- );
- }
-
- public void uninstall(@NotNull final List<PyPackage> packages) {
- final String packagesString = StringUtil.join(packages, new Function<PyPackage, String>() {
- @Override
- public String fun(PyPackage pkg) {
- return "'" + pkg.getName() + "'";
- }
- }, ", ");
- if (checkDependents(packages)) return;
-
- run(new MultiExternalRunnable() {
- @Override
- public List<PyExternalProcessException> run(@NotNull ProgressIndicator indicator) {
- final PyPackageManagerImpl manager = (PyPackageManagerImpl)PyPackageManagers.getInstance().forSdk(mySdk);
- try {
- manager.uninstall(packages);
- return list();
- }
- catch (PyExternalProcessException e) {
- return list(e);
- }
- finally {
- manager.refresh();
- }
- }
- }, "Uninstalling packages", "Packages uninstalled successfully", "Uninstalled packages: " + packagesString,
- "Uninstall packages failed"
- );
- }
-
- private boolean checkDependents(@NotNull final List<PyPackage> packages) {
- try {
- final Map<String, Set<PyPackage>> dependentPackages = collectDependents(packages, mySdk);
- final int[] warning = {0};
- if (!dependentPackages.isEmpty()) {
- ApplicationManager.getApplication().invokeAndWait(new Runnable() {
- @Override
- public void run() {
- if (dependentPackages.size() == 1) {
- String message = "You are attempting to uninstall ";
- List<String> dep = new ArrayList<String>();
- int size = 1;
- for (Map.Entry<String, Set<PyPackage>> entry : dependentPackages.entrySet()) {
- final Set<PyPackage> value = entry.getValue();
- size = value.size();
- dep.add(entry.getKey() + " package which is required for " + StringUtil.join(value, ", "));
- }
- message += StringUtil.join(dep, "\n");
- message += size == 1 ? " package" : " packages";
- message += "\n\nDo you want to proceed?";
- warning[0] = Messages.showYesNoDialog(message, "Warning",
- AllIcons.General.BalloonWarning);
- }
- else {
- String message = "You are attempting to uninstall packages which are required for another packages.\n\n";
- List<String> dep = new ArrayList<String>();
- for (Map.Entry<String, Set<PyPackage>> entry : dependentPackages.entrySet()) {
- dep.add(entry.getKey() + " -> " + StringUtil.join(entry.getValue(), ", "));
- }
- message += StringUtil.join(dep, "\n");
- message += "\n\nDo you want to proceed?";
- warning[0] = Messages.showYesNoDialog(message, "Warning",
- AllIcons.General.BalloonWarning);
- }
- }
- }, ModalityState.current());
- }
- if (warning[0] != Messages.YES) return true;
- }
- catch (PyExternalProcessException e) {
- LOG.info("Error loading packages dependents: " + e.getMessage(), e);
- }
- return false;
- }
-
- private interface MultiExternalRunnable {
- List<PyExternalProcessException> run(@NotNull ProgressIndicator indicator);
- }
-
- private void run(@NotNull final MultiExternalRunnable runnable, @NotNull final String progressTitle,
- @NotNull final String successTitle, @NotNull final String successDescription, @NotNull final String failureTitle) {
- ProgressManager.getInstance().run(new Task.Backgroundable(myProject, progressTitle, false) {
- @Override
- public void run(@NotNull ProgressIndicator indicator) {
- indicator.setText(progressTitle + "...");
- final Ref<Notification> notificationRef = new Ref<Notification>(null);
- final String PACKAGING_GROUP_ID = "Packaging";
- final Application application = ApplicationManager.getApplication();
- if (myListener != null) {
- application.invokeLater(new Runnable() {
- @Override
- public void run() {
- myListener.started();
- }
- });
- }
-
- final List<PyExternalProcessException> exceptions = runnable.run(indicator);
- if (exceptions.isEmpty()) {
- notificationRef.set(new Notification(PACKAGING_GROUP_ID, successTitle, successDescription, NotificationType.INFORMATION));
- }
- else {
- final String progressLower = progressTitle.toLowerCase();
- final String firstLine = String.format("Error%s occurred when %s.", exceptions.size() > 1 ? "s" : "", progressLower);
-
- final String description = createDescription(exceptions, firstLine);
- notificationRef.set(new Notification(PACKAGING_GROUP_ID, failureTitle,
- firstLine + " <a href=\"xxx\">Details...</a>",
- NotificationType.ERROR,
- new NotificationListener() {
- @Override
- public void hyperlinkUpdate(@NotNull Notification notification,
- @NotNull HyperlinkEvent event) {
- assert myProject != null;
- PackagesNotificationPanel.showError(myProject, failureTitle, description);
- }
- }
- ));
- }
- application.invokeLater(new Runnable() {
- @Override
- public void run() {
- if (myListener != null) {
- myListener.finished(exceptions);
- }
- final Notification notification = notificationRef.get();
- if (notification != null) {
- notification.notify(myProject);
- }
- }
- });
- }
- });
- }
-
- public static String createDescription(List<PyExternalProcessException> exceptions, String firstLine) {
- final StringBuilder b = new StringBuilder();
- b.append(firstLine);
- b.append("\n\n");
- for (PyExternalProcessException exception : exceptions) {
- b.append(exception.toString());
- b.append("\n");
- }
- return b.toString();
- }
- }
+ protected Sdk mySdk;
@Override
public void refresh() {
@@ -373,7 +113,23 @@ public class PyPackageManagerImpl extends PyPackageManager {
});
}
- private void installManagement(String name) throws PyExternalProcessException {
+ @Override
+ public void installManagement() throws PyExternalProcessException {
+ if (!hasPackage(PACKAGE_SETUPTOOLS, false) && !hasPackage(PACKAGE_DISTRIBUTE, false)) {
+ installManagement(SETUPTOOLS);
+ }
+ if (!hasPackage(PACKAGE_PIP, false)) {
+ installManagement(PIP);
+ }
+ }
+
+ @Override
+ public boolean hasManagement(boolean cachedOnly) {
+ return (hasPackage(PACKAGE_SETUPTOOLS, cachedOnly) || hasPackage(PACKAGE_DISTRIBUTE, cachedOnly)) &&
+ hasPackage(PACKAGE_PIP, cachedOnly);
+ }
+
+ protected void installManagement(@NotNull String name) throws PyExternalProcessException {
final String helperPath = getHelperPath(name);
ArrayList<String> args = Lists.newArrayList(UNTAR, helperPath);
@@ -390,7 +146,7 @@ public class PyPackageManagerImpl extends PyPackageManager {
}
final String fileName = dirName + name + File.separatorChar + "setup.py";
try {
- output = getProcessOutput(fileName, Collections.<String>singletonList(INSTALL), true, dirName + name);
+ output = getProcessOutput(fileName, Collections.singletonList(INSTALL), true, dirName + name);
final int retcode = output.getExitCode();
if (output.isTimeout()) {
throw new PyExternalProcessException(ERROR_TIMEOUT, fileName, Lists.newArrayList(INSTALL), "Timed out");
@@ -406,17 +162,28 @@ public class PyPackageManagerImpl extends PyPackageManager {
}
finally {
clearCaches();
- FileUtil.delete(new File(dirName)); //TODO: remove temp directory for remote interpreter
+ FileUtil.delete(new File(dirName));
+ }
+ }
+
+ private boolean hasPackage(@NotNull String name, boolean cachedOnly) {
+ try {
+ return findPackage(name, cachedOnly) != null;
+ }
+ catch (PyExternalProcessException ignored) {
+ return false;
}
}
PyPackageManagerImpl(@NotNull Sdk sdk) {
mySdk = sdk;
+ subscribeToLocalChanges(sdk);
+ }
+
+ protected void subscribeToLocalChanges(Sdk sdk) {
final Application app = ApplicationManager.getApplication();
final MessageBusConnection connection = app.getMessageBus().connect();
- if (!PySdkUtil.isRemote(sdk)) {
- connection.subscribe(VirtualFileManager.VFS_CHANGES, new MySdkRootWatcher());
- }
+ connection.subscribe(VirtualFileManager.VFS_CHANGES, new MySdkRootWatcher());
}
public Sdk getSdk() {
@@ -424,27 +191,13 @@ public class PyPackageManagerImpl extends PyPackageManager {
}
@Override
- public void install(String requirementString) throws PyExternalProcessException {
- boolean hasSetuptools = false;
- boolean hasPip = false;
- try {
- hasSetuptools = findInstalledPackage(SETUPTOOLS) != null;
- }
- catch (PyExternalProcessException ignored) {
- }
- try {
- hasPip = findInstalledPackage(PIP) != null;
- }
- catch (PyExternalProcessException ignored) {
- }
-
- if (!hasSetuptools) installManagement(SETUPTOOLS);
- if (!hasPip) installManagement(PIP);
+ public void install(@NotNull String requirementString) throws PyExternalProcessException {
+ installManagement();
install(Collections.singletonList(PyRequirement.fromString(requirementString)), Collections.<String>emptyList());
}
- public void install(@NotNull List<PyRequirement> requirements, @NotNull List<String> extraArgs)
- throws PyExternalProcessException {
+ @Override
+ public void install(@NotNull List<PyRequirement> requirements, @NotNull List<String> extraArgs) throws PyExternalProcessException {
final List<String> args = new ArrayList<String>();
args.add(INSTALL);
final File buildDir;
@@ -455,7 +208,7 @@ public class PyPackageManagerImpl extends PyPackageManager {
throw new PyExternalProcessException(ERROR_ACCESS_DENIED, PACKAGING_TOOL, args, "Cannot create temporary build directory");
}
if (!extraArgs.contains(BUILD_DIR_OPTION)) {
- args.addAll(list(BUILD_DIR_OPTION, buildDir.getAbsolutePath()));
+ args.addAll(Arrays.asList(BUILD_DIR_OPTION, buildDir.getAbsolutePath()));
}
boolean useUserSite = extraArgs.contains(USE_USER_SITE);
@@ -499,69 +252,22 @@ public class PyPackageManagerImpl extends PyPackageManager {
}
}
- private static Map<String, Set<PyPackage>> collectDependents(@NotNull final List<PyPackage> packages, Sdk sdk)
- throws PyExternalProcessException {
- Map<String, Set<PyPackage>> dependentPackages = new HashMap<String, Set<PyPackage>>();
- for (PyPackage pkg : packages) {
- final Set<PyPackage> dependents =
- ((PyPackageManagerImpl)PyPackageManager.getInstance(sdk)).getDependents(pkg.getName());
- if (dependents != null && !dependents.isEmpty()) {
- for (PyPackage dependent : dependents) {
- if (!packages.contains(dependent)) {
- dependentPackages.put(pkg.getName(), dependents);
- }
- }
- }
- }
- return dependentPackages;
- }
-
- public static String getUserSite() {
- if (SystemInfo.isWindows) {
- final String appdata = System.getenv("APPDATA");
- return appdata + File.separator + "Python";
- }
- else {
- final String userHome = SystemProperties.getUserHome();
- return userHome + File.separator + ".local";
- }
- }
-
-
- public boolean cacheIsNotNull() {
- return myPackagesCache != null;
- }
-
- /**
- * Returns the list of packages for the SDK without initiating a remote connection. Returns null
- * for a remote interpreter if the list of packages was not loaded.
- *
- * @return the list of packages or null
- */
@Nullable
- public synchronized List<PyPackage> getPackagesFast() throws PyExternalProcessException {
- if (myPackagesCache != null) {
- return myPackagesCache;
- }
- if (PySdkUtil.isRemote(mySdk)) {
- return null;
- }
- return getPackages();
- }
-
- @NotNull
- public synchronized List<PyPackage> getPackages() throws PyExternalProcessException {
+ public synchronized List<PyPackage> getPackages(boolean cachedOnly) throws PyExternalProcessException {
if (myPackagesCache == null) {
if (myExceptionCache != null) {
throw myExceptionCache;
}
-
+ if (cachedOnly) {
+ return null;
+ }
loadPackages();
}
return myPackagesCache;
}
- public synchronized Set<PyPackage> getDependents(String pkg) throws PyExternalProcessException {
+ @Nullable
+ public synchronized Set<PyPackage> getDependents(@NotNull PyPackage pkg) throws PyExternalProcessException {
if (myDependenciesCache == null) {
if (myExceptionCache != null) {
throw myExceptionCache;
@@ -569,12 +275,12 @@ public class PyPackageManagerImpl extends PyPackageManager {
loadPackages();
}
- return myDependenciesCache.get(pkg);
+ return myDependenciesCache.get(pkg.getName());
}
public synchronized void loadPackages() throws PyExternalProcessException {
try {
- final String output = runPythonHelper(PACKAGING_TOOL, list("list"));
+ final String output = runPythonHelper(PACKAGING_TOOL, Arrays.asList("list"));
myPackagesCache = parsePackagingToolOutput(output);
Collections.sort(myPackagesCache, new Comparator<PyPackage>() {
@Override
@@ -592,7 +298,7 @@ public class PyPackageManagerImpl extends PyPackageManager {
}
}
- private void calculateDependents() {
+ private synchronized void calculateDependents() {
myDependenciesCache = new HashMap<String, Set<PyPackage>>();
for (PyPackage p : myPackagesCache) {
final List<PyRequirement> requirements = p.getRequirements();
@@ -608,47 +314,18 @@ public class PyPackageManagerImpl extends PyPackageManager {
@Override
@Nullable
- public PyPackage findInstalledPackage(String name) throws PyExternalProcessException {
- return findPackageByName(name, getPackages());
- }
-
- @Override
- public boolean findPackage(@NotNull final String name) {
- try {
- final String output = runPythonHelper(PACKAGING_TOOL, list("search", name));
- return StringUtil.containsIgnoreCase(output, name + " ");
- }
- catch (PyExternalProcessException e) {
- LOG.error(e.getMessage());
- return false;
- }
- }
-
- @Nullable
- public PyPackage findPackageFast(String name) throws PyExternalProcessException {
- final List<PyPackage> packages = getPackagesFast();
- return packages != null ? findPackageByName(name, packages) : null;
- }
-
- @Nullable
- private static PyPackage findPackageByName(String name, List<PyPackage> packages) {
- for (PyPackage pkg : packages) {
- if (name.equalsIgnoreCase(pkg.getName())) {
- return pkg;
+ public PyPackage findPackage(@NotNull String name, boolean cachedOnly) throws PyExternalProcessException {
+ final List<PyPackage> packages = getPackages(cachedOnly);
+ if (packages != null) {
+ for (PyPackage pkg : packages) {
+ if (name.equalsIgnoreCase(pkg.getName())) {
+ return pkg;
+ }
}
}
return null;
}
- public boolean hasPip() {
- try {
- return findPackageFast(PACKAGE_PIP) != null;
- }
- catch (PyExternalProcessException e) {
- return false;
- }
- }
-
@NotNull
public String createVirtualEnv(@NotNull String destinationDir, boolean useGlobalSite) throws PyExternalProcessException {
final List<String> args = new ArrayList<String>();
@@ -674,30 +351,21 @@ public class PyPackageManagerImpl extends PyPackageManager {
final String path = (binary != null) ? binary : binaryFallback;
if (usePyVenv) {
- // TODO: Still no 'packaging' and 'pysetup3' for Python 3.3rc1, see PEP 405
+ // Still no 'packaging' and 'pysetup3' for Python 3.3rc1, see PEP 405
final VirtualFile binaryFile = LocalFileSystem.getInstance().refreshAndFindFileByPath(path);
if (binaryFile != null) {
final ProjectJdkImpl tmpSdk = new ProjectJdkImpl("", PythonSdkType.getInstance());
tmpSdk.setHomePath(path);
- final PyPackageManagerImpl manager = new PyPackageManagerImpl(tmpSdk);
- manager.installManagement(SETUPTOOLS);
- manager.installManagement(PIP);
+ final PyPackageManager manager = PyPackageManager.getInstance(tmpSdk);
+ manager.installManagement();
}
}
return path;
}
- public static void deleteVirtualEnv(@NotNull String sdkHome) throws PyExternalProcessException {
- final File root = PythonSdkType.getVirtualEnvRoot(sdkHome);
- if (root != null) {
- FileUtil.delete(root);
- }
- }
-
@Nullable
- public static List<PyRequirement> getRequirements(@NotNull Module module) {
- // TODO: Cache requirements, clear cache on requirements.txt or setup.py updates
- List<PyRequirement> requirements = getRequirementsFromTxt(module);
+ public List<PyRequirement> getRequirements(@NotNull Module module) {
+ List<PyRequirement> requirements = PySdkUtil.getRequirementsFromTxt(module);
if (requirements != null) {
return requirements;
}
@@ -721,25 +389,12 @@ public class PyPackageManagerImpl extends PyPackageManager {
return null;
}
- @Nullable
- public static List<PyRequirement> getRequirementsFromTxt(Module module) {
- final VirtualFile requirementsTxt = PyPackageUtil.findRequirementsTxt(module);
- if (requirementsTxt != null) {
- return PyRequirement.parse(requirementsTxt);
- }
- return null;
- }
-
- private void clearCaches() {
+ protected synchronized void clearCaches() {
myPackagesCache = null;
myDependenciesCache = null;
myExceptionCache = null;
}
- private static <T> List<T> list(T... xs) {
- return Arrays.asList(xs);
- }
-
@Nullable
private static String getProxyString() {
final HttpConfigurable settings = HttpConfigurable.getInstance();
@@ -792,164 +447,61 @@ public class PyPackageManagerImpl extends PyPackageManager {
}
@Nullable
- private String getHelperPath(String helper) {
- String helperPath;
- final SdkAdditionalData sdkData = mySdk.getSdkAdditionalData();
- if (sdkData instanceof PyRemoteSdkAdditionalDataBase) {
- PyRemoteSdkAdditionalDataBase remoteSdkData = (PyRemoteSdkAdditionalDataBase)mySdk.getSdkAdditionalData();
-
- try {
- final RemoteSdkCredentials remoteSdkCredentials = remoteSdkData.getRemoteSdkCredentials(false);
- if (!StringUtil.isEmpty(remoteSdkCredentials.getHelpersPath())) {
- helperPath = new RemoteFile(remoteSdkCredentials.getHelpersPath(),
- helper).getPath();
- }
- else {
- helperPath = null;
- }
- }
- catch (Exception e) {
- helperPath = null;
- LOG.error(e);
- }
- }
- else {
- helperPath = PythonHelpersLocator.getHelperPath(helper);
- }
- return helperPath;
+ protected String getHelperPath(String helper) {
+ return PythonHelpersLocator.getHelperPath(helper);
}
- private ProcessOutput getProcessOutput(@NotNull String helperPath,
+ protected ProcessOutput getProcessOutput(@NotNull String helperPath,
@NotNull List<String> args,
boolean askForSudo,
- @Nullable String workingDir)
- throws PyExternalProcessException {
- final SdkAdditionalData sdkData = mySdk.getSdkAdditionalData();
+ @Nullable String workingDir) throws PyExternalProcessException {
final String homePath = mySdk.getHomePath();
if (homePath == null) {
throw new PyExternalProcessException(ERROR_INVALID_SDK, helperPath, args, "Cannot find interpreter for SDK");
}
- if (sdkData instanceof PyRemoteSdkAdditionalDataBase) { //remote interpreter
- RemoteSdkCredentials remoteSdkCredentials;
+ if (workingDir == null) {
+ workingDir = new File(homePath).getParent();
+ }
+ final List<String> cmdline = new ArrayList<String>();
+ cmdline.add(homePath);
+ cmdline.add(helperPath);
+ cmdline.addAll(args);
+ LOG.info("Running packaging tool: " + StringUtil.join(cmdline, " "));
+
+ final boolean canCreate = FileUtil.ensureCanCreateFile(new File(homePath));
+ if (!canCreate && !SystemInfo.isWindows && askForSudo) { //is system site interpreter --> we need sudo privileges
try {
- remoteSdkCredentials = ((RemoteSdkAdditionalData)sdkData).getRemoteSdkCredentials(false);
- }
- catch (InterruptedException e) {
- LOG.error(e);
- remoteSdkCredentials = null;
- }
- catch (final ExecutionException e) {
- if (e.getCause() instanceof VagrantNotStartedException) {
- throw new PyExternalProcessException(ERROR_VAGRANT_NOT_LAUNCHED, helperPath, args, "Vagrant instance is down. <a href=\"" +
- LAUNCH_VAGRANT +
- "\">Launch vagrant</a>")
- .withHandler(LAUNCH_VAGRANT, new Runnable() {
- @Override
- public void run() {
- final PythonRemoteInterpreterManager manager = PythonRemoteInterpreterManager.getInstance();
- if (manager != null) {
-
- try {
- manager.runVagrant(((VagrantNotStartedException)e.getCause()).getVagrantFolder());
- clearCaches();
- }
- catch (ExecutionException e1) {
- throw new RuntimeException(e1);
- }
- }
- }
- });
- }
- else {
- throw new PyExternalProcessException(ERROR_REMOTE_ACCESS, helperPath, args, e.getMessage());
- }
- }
- final PythonRemoteInterpreterManager manager = PythonRemoteInterpreterManager.getInstance();
- if (manager != null && remoteSdkCredentials != null) {
- final List<String> cmdline = new ArrayList<String>();
- cmdline.add(homePath);
- cmdline.add(RemoteFile.detectSystemByPath(homePath).createRemoteFile(helperPath).getPath());
- cmdline.addAll(Collections2.transform(args, new com.google.common.base.Function<String, String>() {
- @Override
- public String apply(@Nullable String input) {
- return quoteIfNeeded(input);
+ final ProcessOutput result = ExecUtil.sudoAndGetOutput(cmdline,
+ "Please enter your password to make changes in system packages: ",
+ workingDir);
+ String message = result.getStderr();
+ if (result.getExitCode() != 0) {
+ final String stdout = result.getStdout();
+ if (StringUtil.isEmptyOrSpaces(message)) {
+ message = stdout;
}
- }));
- try {
- if (askForSudo) {
- askForSudo = !manager.ensureCanWrite(null, remoteSdkCredentials, remoteSdkCredentials.getInterpreterPath());
+ if (StringUtil.isEmptyOrSpaces(message)) {
+ message = "Failed to perform action. Permission denied.";
}
- ProcessOutput processOutput;
- do {
- PathMappingSettings mappings = manager.setupMappings(null, (PyRemoteSdkAdditionalDataBase)sdkData, null);
- processOutput =
- manager.runRemoteProcess(null, remoteSdkCredentials, mappings, ArrayUtil.toStringArray(cmdline), workingDir, askForSudo);
- if (askForSudo && processOutput.getStderr().contains("sudo: 3 incorrect password attempts")) {
- continue;
- }
- break;
- }
- while (true);
- return processOutput;
+ throw new PyExternalProcessException(result.getExitCode(), helperPath, args, message);
}
- catch (ExecutionException e) {
- throw new PyExternalProcessException(ERROR_INVALID_SDK, helperPath, args, "Error running SDK: " + e.getMessage(), e);
+ if (SystemInfo.isMac && !StringUtil.isEmptyOrSpaces(message)) {
+ throw new PyExternalProcessException(result.getExitCode(), helperPath, args, message);
}
+ return result;
}
- else {
- throw new PyExternalProcessException(ERROR_INVALID_SDK, helperPath, args,
- PythonRemoteInterpreterManager.WEB_DEPLOYMENT_PLUGIN_IS_DISABLED);
+ catch (ExecutionException e) {
+ throw new PyExternalProcessException(ERROR_EXECUTION, helperPath, args, e.getMessage());
+ }
+ catch (IOException e) {
+ throw new PyExternalProcessException(ERROR_ACCESS_DENIED, helperPath, args, e.getMessage());
}
}
else {
- if (workingDir == null) {
- workingDir = new File(homePath).getParent();
- }
- final List<String> cmdline = new ArrayList<String>();
- cmdline.add(homePath);
- cmdline.add(helperPath);
- cmdline.addAll(args);
- LOG.info("Running packaging tool: " + StringUtil.join(cmdline, " "));
-
- final boolean canCreate = FileUtil.ensureCanCreateFile(new File(homePath));
- if (!canCreate && !SystemInfo.isWindows && askForSudo) { //is system site interpreter --> we need sudo privileges
- try {
- final ProcessOutput result = ExecUtil.sudoAndGetOutput(cmdline,
- "Please enter your password to make changes in system packages: ",
- workingDir);
- String message = result.getStderr();
- if (result.getExitCode() != 0) {
- final String stdout = result.getStdout();
- if (StringUtil.isEmptyOrSpaces(message)) {
- message = stdout;
- }
- if (StringUtil.isEmptyOrSpaces(message)) {
- message = "Failed to perform action. Permission denied.";
- }
- throw new PyExternalProcessException(result.getExitCode(), helperPath, args, message);
- }
- if (SystemInfo.isMac && !StringUtil.isEmptyOrSpaces(message)) {
- throw new PyExternalProcessException(result.getExitCode(), helperPath, args, message);
- }
- return result;
- }
- catch (ExecutionException e) {
- throw new PyExternalProcessException(ERROR_EXECUTION, helperPath, args, e.getMessage());
- }
- catch (IOException e) {
- throw new PyExternalProcessException(ERROR_ACCESS_DENIED, helperPath, args, e.getMessage());
- }
- }
- else {
- return PySdkUtil.getProcessOutput(workingDir, ArrayUtil.toStringArray(cmdline), TIMEOUT);
- }
+ return PySdkUtil.getProcessOutput(workingDir, ArrayUtil.toStringArray(cmdline), TIMEOUT);
}
}
- private static String quoteIfNeeded(String arg) {
- return arg.replace("<", "\\<").replace(">", "\\>"); //TODO: move this logic to ParametersListUtil.encode
- }
-
@NotNull
private static List<PyPackage> parsePackagingToolOutput(@NotNull String s) throws PyExternalProcessException {
final String[] lines = StringUtil.splitByLines(s);
@@ -976,17 +528,6 @@ public class PyPackageManagerImpl extends PyPackageManager {
return packages;
}
-
- @Override
- public void showInstallationError(Project project, String title, String description) {
- PackagesNotificationPanel.showError(project, title, description);
- }
-
- @Override
- public void showInstallationError(Component owner, String title, String description) {
- PackagesNotificationPanel.showError(owner, title, description);
- }
-
private class MySdkRootWatcher extends BulkFileListener.Adapter {
@Override
public void after(@NotNull List<? extends VFileEvent> events) {
diff --git a/python/src/com/jetbrains/python/packaging/PyPackageManagerUI.java b/python/src/com/jetbrains/python/packaging/PyPackageManagerUI.java
new file mode 100644
index 000000000000..28dfa6c834a4
--- /dev/null
+++ b/python/src/com/jetbrains/python/packaging/PyPackageManagerUI.java
@@ -0,0 +1,367 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.packaging;
+
+import com.intellij.icons.AllIcons;
+import com.intellij.notification.Notification;
+import com.intellij.notification.NotificationListener;
+import com.intellij.notification.NotificationType;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.application.ModalityState;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.progress.ProgressIndicator;
+import com.intellij.openapi.progress.ProgressManager;
+import com.intellij.openapi.progress.Task;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.ui.Messages;
+import com.intellij.openapi.util.Ref;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.util.Function;
+import com.intellij.webcore.packaging.PackagesNotificationPanel;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.event.HyperlinkEvent;
+import java.util.*;
+
+/**
+* @author vlan
+*/
+public class PyPackageManagerUI {
+ private static final Logger LOG = Logger.getInstance(PyPackageManagerUI.class);
+ @Nullable private Listener myListener;
+ @NotNull private Project myProject;
+ @NotNull private Sdk mySdk;
+
+ public interface Listener {
+ void started();
+
+ void finished(List<PyExternalProcessException> exceptions);
+ }
+
+ public PyPackageManagerUI(@NotNull Project project, @NotNull Sdk sdk, @Nullable Listener listener) {
+ myProject = project;
+ mySdk = sdk;
+ myListener = listener;
+ }
+
+ public void installManagement() {
+ ProgressManager.getInstance().run(new InstallManagementTask(myProject, mySdk, myListener));
+ }
+
+ public void install(@NotNull final List<PyRequirement> requirements, @NotNull final List<String> extraArgs) {
+ ProgressManager.getInstance().run(new InstallTask(myProject, mySdk, requirements, extraArgs, myListener));
+ }
+
+ public void uninstall(@NotNull final List<PyPackage> packages) {
+ if (checkDependents(packages)) {
+ return;
+ }
+ ProgressManager.getInstance().run(new UninstallTask(myProject, mySdk, myListener, packages));
+ }
+
+ private boolean checkDependents(@NotNull final List<PyPackage> packages) {
+ try {
+ final Map<String, Set<PyPackage>> dependentPackages = collectDependents(packages, mySdk);
+ final int[] warning = {0};
+ if (!dependentPackages.isEmpty()) {
+ ApplicationManager.getApplication().invokeAndWait(new Runnable() {
+ @Override
+ public void run() {
+ if (dependentPackages.size() == 1) {
+ String message = "You are attempting to uninstall ";
+ List<String> dep = new ArrayList<String>();
+ int size = 1;
+ for (Map.Entry<String, Set<PyPackage>> entry : dependentPackages.entrySet()) {
+ final Set<PyPackage> value = entry.getValue();
+ size = value.size();
+ dep.add(entry.getKey() + " package which is required for " + StringUtil.join(value, ", "));
+ }
+ message += StringUtil.join(dep, "\n");
+ message += size == 1 ? " package" : " packages";
+ message += "\n\nDo you want to proceed?";
+ warning[0] = Messages.showYesNoDialog(message, "Warning",
+ AllIcons.General.BalloonWarning);
+ }
+ else {
+ String message = "You are attempting to uninstall packages which are required for another packages.\n\n";
+ List<String> dep = new ArrayList<String>();
+ for (Map.Entry<String, Set<PyPackage>> entry : dependentPackages.entrySet()) {
+ dep.add(entry.getKey() + " -> " + StringUtil.join(entry.getValue(), ", "));
+ }
+ message += StringUtil.join(dep, "\n");
+ message += "\n\nDo you want to proceed?";
+ warning[0] = Messages.showYesNoDialog(message, "Warning",
+ AllIcons.General.BalloonWarning);
+ }
+ }
+ }, ModalityState.current());
+ }
+ if (warning[0] != Messages.YES) return true;
+ }
+ catch (PyExternalProcessException e) {
+ LOG.info("Error loading packages dependents: " + e.getMessage(), e);
+ }
+ return false;
+ }
+
+ private static Map<String, Set<PyPackage>> collectDependents(@NotNull final List<PyPackage> packages, Sdk sdk)
+ throws PyExternalProcessException {
+ Map<String, Set<PyPackage>> dependentPackages = new HashMap<String, Set<PyPackage>>();
+ for (PyPackage pkg : packages) {
+ final Set<PyPackage> dependents = PyPackageManager.getInstance(sdk).getDependents(pkg);
+ if (dependents != null && !dependents.isEmpty()) {
+ for (PyPackage dependent : dependents) {
+ if (!packages.contains(dependent)) {
+ dependentPackages.put(pkg.getName(), dependents);
+ }
+ }
+ }
+ }
+ return dependentPackages;
+ }
+
+ private abstract static class PackagingTask extends Task.Backgroundable {
+ private static final String PACKAGING_GROUP_ID = "Packaging";
+
+ @Nullable protected final Listener myListener;
+
+ public PackagingTask(@Nullable Project project, @NotNull String title, @Nullable Listener listener) {
+ super(project, title);
+ myListener = listener;
+ }
+
+ @Override
+ public void run(@NotNull ProgressIndicator indicator) {
+ taskStarted(indicator);
+ taskFinished(runTask(indicator));
+ }
+
+ @NotNull
+ protected abstract List<PyExternalProcessException> runTask(@NotNull ProgressIndicator indicator);
+
+ @NotNull
+ protected abstract String getSuccessTitle();
+
+ @NotNull
+ protected abstract String getSuccessDescription();
+
+ @NotNull
+ protected abstract String getFailureTitle();
+
+ protected void taskStarted(@NotNull ProgressIndicator indicator) {
+ indicator.setText(getTitle() + "...");
+ if (myListener != null) {
+ ApplicationManager.getApplication().invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ myListener.started();
+ }
+ });
+ }
+ }
+
+ protected void taskFinished(@NotNull final List<PyExternalProcessException> exceptions) {
+ final Ref<Notification> notificationRef = new Ref<Notification>(null);
+ if (exceptions.isEmpty()) {
+ notificationRef.set(new Notification(PACKAGING_GROUP_ID, getSuccessTitle(), getSuccessDescription(),
+ NotificationType.INFORMATION));
+ }
+ else {
+ final String firstLine = getTitle() + ": error occurred.";
+ final String description = createDescription(exceptions, firstLine);
+ notificationRef.set(new Notification(PACKAGING_GROUP_ID, getFailureTitle(),
+ firstLine + " <a href=\"xxx\">Details...</a>",
+ NotificationType.ERROR,
+ new NotificationListener() {
+ @Override
+ public void hyperlinkUpdate(@NotNull Notification notification,
+ @NotNull HyperlinkEvent event) {
+ assert myProject != null;
+ PackagesNotificationPanel.showError(myProject, getFailureTitle(), description);
+ }
+ }
+ ));
+ }
+ ApplicationManager.getApplication().invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ if (myListener != null) {
+ myListener.finished(exceptions);
+ }
+ final Notification notification = notificationRef.get();
+ if (notification != null) {
+ notification.notify(myProject);
+ }
+ }
+ });
+ }
+ }
+
+ private static class InstallTask extends PackagingTask {
+ @NotNull protected final Sdk mySdk;
+ @NotNull private final List<PyRequirement> myRequirements;
+ @NotNull private final List<String> myExtraArgs;
+
+ public InstallTask(@Nullable Project project,
+ @NotNull Sdk sdk,
+ @NotNull List<PyRequirement> requirements,
+ @NotNull List<String> extraArgs,
+ @Nullable Listener listener) {
+ super(project, "Installing packages", listener);
+ mySdk = sdk;
+ myRequirements = requirements;
+ myExtraArgs = extraArgs;
+ }
+
+ @NotNull
+ @Override
+ protected List<PyExternalProcessException> runTask(@NotNull ProgressIndicator indicator) {
+ final List<PyExternalProcessException> exceptions = new ArrayList<PyExternalProcessException>();
+ final int size = myRequirements.size();
+ final PyPackageManager manager = PyPackageManagers.getInstance().forSdk(mySdk);
+ for (int i = 0; i < size; i++) {
+ final PyRequirement requirement = myRequirements.get(i);
+ indicator.setText(String.format("Installing package '%s'...", requirement));
+ indicator.setFraction((double)i / size);
+ try {
+ manager.install(Arrays.asList(requirement), myExtraArgs);
+ }
+ catch (PyExternalProcessException e) {
+ exceptions.add(e);
+ }
+ }
+ manager.refresh();
+ return exceptions;
+ }
+
+ @NotNull
+ @Override
+ protected String getSuccessTitle() {
+ return "Packages installed successfully";
+ }
+
+ @NotNull
+ @Override
+ protected String getSuccessDescription() {
+ return "Installed packages: " + PyPackageUtil.requirementsToString(myRequirements);
+ }
+
+ @NotNull
+ @Override
+ protected String getFailureTitle() {
+ return "Install packages failed";
+ }
+ }
+
+ private static class InstallManagementTask extends InstallTask {
+
+ public InstallManagementTask(@Nullable Project project,
+ @NotNull Sdk sdk,
+ @Nullable Listener listener) {
+ super(project, sdk, Collections.<PyRequirement>emptyList(), Collections.<String>emptyList(), listener);
+ }
+
+ @NotNull
+ @Override
+ protected List<PyExternalProcessException> runTask(@NotNull ProgressIndicator indicator) {
+ final List<PyExternalProcessException> exceptions = new ArrayList<PyExternalProcessException>();
+ final PyPackageManager manager = PyPackageManagers.getInstance().forSdk(mySdk);
+ indicator.setText("Installing packaging tools...");
+ indicator.setIndeterminate(true);
+ try {
+ manager.installManagement();
+ }
+ catch (PyExternalProcessException e) {
+ exceptions.add(e);
+ }
+ manager.refresh();
+ return exceptions;
+ }
+
+ @NotNull
+ @Override
+ protected String getSuccessDescription() {
+ return "Installed Python packaging tools";
+ }
+ }
+
+ private static class UninstallTask extends PackagingTask {
+ @NotNull private final Sdk mySdk;
+ @NotNull private final List<PyPackage> myPackages;
+
+ public UninstallTask(@Nullable Project project,
+ @NotNull Sdk sdk,
+ @Nullable Listener listener,
+ @NotNull List<PyPackage> packages) {
+ super(project, "Uninstalling packages", listener);
+ mySdk = sdk;
+ myPackages = packages;
+ }
+
+ @NotNull
+ @Override
+ protected List<PyExternalProcessException> runTask(@NotNull ProgressIndicator indicator) {
+ final PyPackageManager manager = PyPackageManagers.getInstance().forSdk(mySdk);
+ try {
+ manager.uninstall(myPackages);
+ return Arrays.asList();
+ }
+ catch (PyExternalProcessException e) {
+ return Arrays.asList(e);
+ }
+ finally {
+ manager.refresh();
+ }
+ }
+
+ @NotNull
+ @Override
+ protected String getSuccessTitle() {
+ return "Packages uninstalled successfully";
+ }
+
+ @NotNull
+ @Override
+ protected String getSuccessDescription() {
+ final String packagesString = StringUtil.join(myPackages, new Function<PyPackage, String>() {
+ @Override
+ public String fun(PyPackage pkg) {
+ return "'" + pkg.getName() + "'";
+ }
+ }, ", ");
+ return "Uninstalled packages: " + packagesString;
+ }
+
+ @NotNull
+ @Override
+ protected String getFailureTitle() {
+ return "Uninstall packages failed";
+ }
+ }
+
+ public static String createDescription(List<PyExternalProcessException> exceptions, String firstLine) {
+ final StringBuilder b = new StringBuilder();
+ b.append(firstLine);
+ b.append("\n\n");
+ for (PyExternalProcessException exception : exceptions) {
+ b.append(exception.toString());
+ b.append("\n");
+ }
+ return b.toString();
+ }
+}
diff --git a/python/src/com/jetbrains/python/packaging/PyPackageManagersImpl.java b/python/src/com/jetbrains/python/packaging/PyPackageManagersImpl.java
index 054e9e01d23f..e68cede3f799 100644
--- a/python/src/com/jetbrains/python/packaging/PyPackageManagersImpl.java
+++ b/python/src/com/jetbrains/python/packaging/PyPackageManagersImpl.java
@@ -15,13 +15,11 @@
*/
package com.jetbrains.python.packaging;
-import com.intellij.openapi.module.Module;
import com.intellij.openapi.projectRoots.Sdk;
+import com.jetbrains.python.sdk.PythonSdkType;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
/**
@@ -36,22 +34,14 @@ public class PyPackageManagersImpl extends PyPackageManagers {
final String name = sdk.getName();
PyPackageManagerImpl manager = myInstances.get(name);
if (manager == null) {
- manager = new PyPackageManagerImpl(sdk);
+ if (PythonSdkType.isRemote(sdk)) {
+ manager = new PyRemotePackageManagerImpl(sdk);
+ }
+ else {
+ manager = new PyPackageManagerImpl(sdk);
+ }
myInstances.put(name, manager);
}
return manager;
}
-
- @Nullable
- @Override
- public List<PyRequirement> getRequirements(Module module) {
- return PyPackageManagerImpl.getRequirements(module);
- }
-
-
- @Nullable
- @Override
- public List<PyRequirement> getRequirementsFromTxt(Module module) {
- return PyPackageManagerImpl.getRequirementsFromTxt(module);
- }
}
diff --git a/python/src/com/jetbrains/python/packaging/PyRemotePackageManagerImpl.java b/python/src/com/jetbrains/python/packaging/PyRemotePackageManagerImpl.java
new file mode 100644
index 000000000000..6c6de77d9454
--- /dev/null
+++ b/python/src/com/jetbrains/python/packaging/PyRemotePackageManagerImpl.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.packaging;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Collections2;
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.process.ProcessOutput;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.projectRoots.SdkAdditionalData;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.remote.RemoteFile;
+import com.intellij.remote.RemoteSdkAdditionalData;
+import com.intellij.remote.RemoteSdkCredentials;
+import com.intellij.remote.VagrantNotStartedException;
+import com.intellij.util.ArrayUtil;
+import com.intellij.util.PathMappingSettings;
+import com.jetbrains.python.remote.PyRemoteSdkAdditionalDataBase;
+import com.jetbrains.python.remote.PythonRemoteInterpreterManager;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author vlan
+ */
+public class PyRemotePackageManagerImpl extends PyPackageManagerImpl {
+ private static final String LAUNCH_VAGRANT = "launchVagrant";
+ public static final int ERROR_VAGRANT_NOT_LAUNCHED = 101;
+ public static final int ERROR_REMOTE_ACCESS = 102;
+
+ private static final Logger LOG = Logger.getInstance(PyRemotePackageManagerImpl.class);
+
+ PyRemotePackageManagerImpl(@NotNull Sdk sdk) {
+ super(sdk);
+ }
+
+ @Nullable
+ @Override
+ protected String getHelperPath(String helper) {
+ final SdkAdditionalData sdkData = mySdk.getSdkAdditionalData();
+ if (sdkData instanceof PyRemoteSdkAdditionalDataBase) {
+ final PyRemoteSdkAdditionalDataBase remoteSdkData = (PyRemoteSdkAdditionalDataBase)mySdk.getSdkAdditionalData();
+ try {
+ final RemoteSdkCredentials remoteSdkCredentials = remoteSdkData.getRemoteSdkCredentials(false);
+ if (!StringUtil.isEmpty(remoteSdkCredentials.getHelpersPath())) {
+ return new RemoteFile(remoteSdkCredentials.getHelpersPath(), helper).getPath();
+ }
+ else {
+ return null;
+ }
+ }
+ catch (Exception e) {
+ LOG.error(e);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ protected ProcessOutput getProcessOutput(@NotNull String helperPath,
+ @NotNull List<String> args,
+ boolean askForSudo,
+ @Nullable String workingDir) throws PyExternalProcessException {
+ final String homePath = mySdk.getHomePath();
+ if (homePath == null) {
+ throw new PyExternalProcessException(ERROR_INVALID_SDK, helperPath, args, "Cannot find interpreter for SDK");
+ }
+ final SdkAdditionalData sdkData = mySdk.getSdkAdditionalData();
+ if (sdkData instanceof PyRemoteSdkAdditionalDataBase) { //remote interpreter
+ RemoteSdkCredentials remoteSdkCredentials;
+ try {
+ remoteSdkCredentials = ((RemoteSdkAdditionalData)sdkData).getRemoteSdkCredentials(false);
+ }
+ catch (InterruptedException e) {
+ LOG.error(e);
+ remoteSdkCredentials = null;
+ }
+ catch (final ExecutionException e) {
+ if (e.getCause() instanceof VagrantNotStartedException) {
+ throw new PyExternalProcessException(ERROR_VAGRANT_NOT_LAUNCHED, helperPath, args, "Vagrant instance is down. <a href=\"" +
+ LAUNCH_VAGRANT +
+ "\">Launch vagrant</a>")
+ .withHandler(LAUNCH_VAGRANT, new Runnable() {
+ @Override
+ public void run() {
+ final PythonRemoteInterpreterManager manager = PythonRemoteInterpreterManager.getInstance();
+ if (manager != null) {
+
+ try {
+ manager.runVagrant(((VagrantNotStartedException)e.getCause()).getVagrantFolder());
+ clearCaches();
+ }
+ catch (ExecutionException e1) {
+ throw new RuntimeException(e1);
+ }
+ }
+ }
+ });
+ }
+ else {
+ throw new PyExternalProcessException(ERROR_REMOTE_ACCESS, helperPath, args, e.getMessage());
+ }
+ }
+ final PythonRemoteInterpreterManager manager = PythonRemoteInterpreterManager.getInstance();
+ if (manager != null && remoteSdkCredentials != null) {
+ final List<String> cmdline = new ArrayList<String>();
+ cmdline.add(homePath);
+ cmdline.add(RemoteFile.detectSystemByPath(homePath).createRemoteFile(helperPath).getPath());
+ cmdline.addAll(Collections2.transform(args, new Function<String, String>() {
+ @Override
+ public String apply(@Nullable String input) {
+ return quoteIfNeeded(input);
+ }
+ }));
+ try {
+ if (askForSudo) {
+ askForSudo = !manager.ensureCanWrite(null, remoteSdkCredentials, remoteSdkCredentials.getInterpreterPath());
+ }
+ ProcessOutput processOutput;
+ do {
+ PathMappingSettings mappings = manager.setupMappings(null, (PyRemoteSdkAdditionalDataBase)sdkData, null);
+ processOutput =
+ manager.runRemoteProcess(null, remoteSdkCredentials, mappings, ArrayUtil.toStringArray(cmdline), workingDir, askForSudo);
+ if (askForSudo && processOutput.getStderr().contains("sudo: 3 incorrect password attempts")) {
+ continue;
+ }
+ break;
+ }
+ while (true);
+ return processOutput;
+ }
+ catch (ExecutionException e) {
+ throw new PyExternalProcessException(ERROR_INVALID_SDK, helperPath, args, "Error running SDK: " + e.getMessage(), e);
+ }
+ }
+ else {
+ throw new PyExternalProcessException(ERROR_INVALID_SDK, helperPath, args,
+ PythonRemoteInterpreterManager.WEB_DEPLOYMENT_PLUGIN_IS_DISABLED);
+ }
+ }
+ else {
+ throw new PyExternalProcessException(ERROR_INVALID_SDK, helperPath, args, "Invalid remote SDK");
+ }
+ }
+
+ @Override
+ protected void subscribeToLocalChanges(Sdk sdk) {
+ // Local VFS changes aren't needed
+ }
+
+ @Override
+ protected void installManagement(@NotNull String name) throws PyExternalProcessException {
+ super.installManagement(name);
+ // TODO: remove temp directory for remote interpreter
+ }
+
+ private static String quoteIfNeeded(String arg) {
+ return arg.replace("<", "\\<").replace(">", "\\>"); //TODO: move this logic to ParametersListUtil.encode
+ }
+}
diff --git a/python/src/com/jetbrains/python/packaging/ui/PyInstalledPackagesPanel.java b/python/src/com/jetbrains/python/packaging/ui/PyInstalledPackagesPanel.java
index 348d2817ec75..094149336d5d 100644
--- a/python/src/com/jetbrains/python/packaging/ui/PyInstalledPackagesPanel.java
+++ b/python/src/com/jetbrains/python/packaging/ui/PyInstalledPackagesPanel.java
@@ -25,10 +25,8 @@ import com.intellij.util.Consumer;
import com.intellij.webcore.packaging.InstalledPackage;
import com.intellij.webcore.packaging.InstalledPackagesPanel;
import com.intellij.webcore.packaging.PackagesNotificationPanel;
-import com.jetbrains.python.packaging.PyExternalProcessException;
-import com.jetbrains.python.packaging.PyPackage;
-import com.jetbrains.python.packaging.PyPackageManager;
-import com.jetbrains.python.packaging.PyPackageManagerImpl;
+import com.jetbrains.python.packaging.*;
+import com.jetbrains.python.sdk.PySdkUtil;
import com.jetbrains.python.sdk.PythonSdkType;
import com.jetbrains.python.sdk.flavors.IronPythonSdkFlavor;
import com.jetbrains.python.sdk.flavors.PythonSdkFlavor;
@@ -42,33 +40,13 @@ import java.util.Set;
* @author yole
*/
public class PyInstalledPackagesPanel extends InstalledPackagesPanel {
- public static final String INSTALL_SETUPTOOLS = "installSetuptools";
- public static final String INSTALL_PIP = "installPip";
+ public static final String INSTALL_MANAGEMENT = "installManagement";
public static final String CREATE_VENV = "createVEnv";
- private boolean myHasSetuptools;
- private boolean myHasPip = true;
+ private boolean myHasManagement = false;
public PyInstalledPackagesPanel(Project project, PackagesNotificationPanel area) {
super(project, area);
- myNotificationArea.addLinkHandler(INSTALL_SETUPTOOLS, new Runnable() {
- @Override
- public void run() {
- final Sdk sdk = getSelectedSdk();
- if (sdk != null) {
- installManagementTool(sdk, PyPackageManagerImpl.SETUPTOOLS);
- }
- }
- });
- myNotificationArea.addLinkHandler(INSTALL_PIP, new Runnable() {
- @Override
- public void run() {
- final Sdk sdk = getSelectedSdk();
- if (sdk != null) {
- installManagementTool(sdk, PyPackageManagerImpl.PIP);
- }
- }
- });
}
private Sdk getSelectedSdk() {
@@ -85,19 +63,8 @@ public class PyInstalledPackagesPanel extends InstalledPackagesPanel {
application.executeOnPooledThread(new Runnable() {
@Override
public void run() {
- PyExternalProcessException exc = null;
- try {
- PyPackageManagerImpl packageManager = (PyPackageManagerImpl)PyPackageManager.getInstance(selectedSdk);
- myHasSetuptools = packageManager.findInstalledPackage(PyPackageManagerImpl.PACKAGE_SETUPTOOLS) != null;
- if (!myHasSetuptools) {
- myHasSetuptools = packageManager.findInstalledPackage(PyPackageManagerImpl.PACKAGE_DISTRIBUTE) != null;
- }
- myHasPip = packageManager.findInstalledPackage(PyPackageManagerImpl.PACKAGE_PIP) != null;
- }
- catch (PyExternalProcessException e) {
- exc = e;
- }
- final PyExternalProcessException externalProcessException = exc;
+ PyPackageManager packageManager = PyPackageManager.getInstance(selectedSdk);
+ myHasManagement = packageManager.hasManagement(false);
application.invokeLater(new Runnable() {
@Override
public void run() {
@@ -112,42 +79,24 @@ public class PyInstalledPackagesPanel extends InstalledPackagesPanel {
myNotificationArea.hide();
if (!invalid) {
String text = null;
- if (externalProcessException != null) {
- final int retCode = externalProcessException.getRetcode();
- if (retCode == PyPackageManagerImpl.ERROR_NO_PIP) {
- myHasPip = false;
- }
- else if (retCode == PyPackageManagerImpl.ERROR_NO_SETUPTOOLS) {
- myHasSetuptools = false;
- }
- else {
- text = externalProcessException.getMessage();
- }
- final boolean hasPackagingTools = myHasPip && myHasSetuptools;
- allowCreateVirtualEnv &= !hasPackagingTools;
-
- if (externalProcessException.hasHandler()) {
- final String key = externalProcessException.getHandler().first;
- myNotificationArea.addLinkHandler(key,
- new Runnable() {
- @Override
- public void run() {
- externalProcessException.getHandler().second.run();
- myNotificationArea.removeLinkHandler(key);
- updateNotifications(selectedSdk);
+ if (!myHasManagement) {
+ myNotificationArea.addLinkHandler(INSTALL_MANAGEMENT,
+ new Runnable() {
+ @Override
+ public void run() {
+ final Sdk sdk = getSelectedSdk();
+ if (sdk != null) {
+ installManagementTools(sdk);
}
+ myNotificationArea.removeLinkHandler(INSTALL_MANAGEMENT);
+ updateNotifications(selectedSdk);
}
- );
- }
+ }
+ );
}
- if (text == null) {
- if (!myHasSetuptools) {
- text = "Python package management tools not found. <a href=\"" + INSTALL_SETUPTOOLS + "\">Install 'setuptools'</a>";
- }
- else if (!myHasPip) {
- text = "Python packaging tool 'pip' not found. <a href=\"" + INSTALL_PIP + "\">Install 'pip'</a>";
- }
+ if (!myHasManagement) {
+ text = "Python packaging tools not found. <a href=\"" + INSTALL_MANAGEMENT + "\">Install packaging tools</a>";
}
if (text != null) {
if (allowCreateVirtualEnv) {
@@ -157,7 +106,7 @@ public class PyInstalledPackagesPanel extends InstalledPackagesPanel {
}
}
- myInstallButton.setEnabled(!invalid && externalProcessException == null && myHasPip);
+ myInstallButton.setEnabled(!invalid && myHasManagement);
}
}
}, ModalityState.any());
@@ -170,8 +119,8 @@ public class PyInstalledPackagesPanel extends InstalledPackagesPanel {
return Sets.newHashSet("pip", "distutils", "setuptools");
}
- private void installManagementTool(@NotNull final Sdk sdk, final String name) {
- final PyPackageManagerImpl.UI ui = new PyPackageManagerImpl.UI(myProject, sdk, new PyPackageManagerImpl.UI.Listener() {
+ private void installManagementTools(@NotNull final Sdk sdk) {
+ final PyPackageManagerUI ui = new PyPackageManagerUI(myProject, sdk, new PyPackageManagerUI.Listener() {
@Override
public void started() {
myPackagesTable.setPaintBusy(true);
@@ -180,11 +129,11 @@ public class PyInstalledPackagesPanel extends InstalledPackagesPanel {
@Override
public void finished(List<PyExternalProcessException> exceptions) {
myPackagesTable.setPaintBusy(false);
- PyPackageManagerImpl packageManager = (PyPackageManagerImpl)PyPackageManager.getInstance(sdk);
+ PyPackageManager packageManager = PyPackageManager.getInstance(sdk);
if (!exceptions.isEmpty()) {
- final String firstLine = "Install package failed. ";
- final String description = PyPackageManagerImpl.UI.createDescription(exceptions, firstLine);
- packageManager.showInstallationError(myProject, "Failed to install " + name, description);
+ final String firstLine = "Install Python packaging tools failed. ";
+ final String description = PyPackageManagerUI.createDescription(exceptions, firstLine);
+ PackagesNotificationPanel.showError(myProject, "Failed to install Python packaging tools", description);
}
packageManager.refresh();
updatePackages(new PyPackageManagementService(myProject, sdk));
@@ -194,22 +143,22 @@ public class PyInstalledPackagesPanel extends InstalledPackagesPanel {
updateNotifications(sdk);
}
});
- ui.installManagement(name);
+ ui.installManagement();
}
@Override
protected boolean canUninstallPackage(InstalledPackage pkg) {
- if (!myHasPip) return false;
+ if (!myHasManagement) return false;
if (PythonSdkType.isVirtualEnv(getSelectedSdk()) && pkg instanceof PyPackage) {
final String location = ((PyPackage)pkg).getLocation();
- if (location != null && location.startsWith(PyPackageManagerImpl.getUserSite())) {
+ if (location != null && location.startsWith(PySdkUtil.getUserSite())) {
return false;
}
}
final String name = pkg.getName();
- if (PyPackageManagerImpl.PACKAGE_PIP.equals(name) ||
- PyPackageManagerImpl.PACKAGE_SETUPTOOLS.equals(name) ||
- PyPackageManagerImpl.PACKAGE_DISTRIBUTE.equals(name)) {
+ if (PyPackageManager.PACKAGE_PIP.equals(name) ||
+ PyPackageManager.PACKAGE_SETUPTOOLS.equals(name) ||
+ PyPackageManager.PACKAGE_DISTRIBUTE.equals(name)) {
return false;
}
return true;
@@ -217,6 +166,6 @@ public class PyInstalledPackagesPanel extends InstalledPackagesPanel {
@Override
protected boolean canUpgradePackage(InstalledPackage pyPackage) {
- return myHasPip;
+ return myHasManagement;
}
}
diff --git a/python/src/com/jetbrains/python/packaging/ui/PyPackageManagementService.java b/python/src/com/jetbrains/python/packaging/ui/PyPackageManagementService.java
index ffd291a995b1..95330b361dfb 100644
--- a/python/src/com/jetbrains/python/packaging/ui/PyPackageManagementService.java
+++ b/python/src/com/jetbrains/python/packaging/ui/PyPackageManagementService.java
@@ -23,6 +23,7 @@ import com.intellij.webcore.packaging.InstalledPackage;
import com.intellij.webcore.packaging.PackageManagementService;
import com.intellij.webcore.packaging.RepoPackage;
import com.jetbrains.python.packaging.*;
+import com.jetbrains.python.sdk.PySdkUtil;
import com.jetbrains.python.sdk.PythonSdkType;
import org.apache.xmlrpc.AsyncCallback;
import org.jetbrains.annotations.NonNls;
@@ -112,7 +113,7 @@ public class PyPackageManagementService extends PackageManagementService {
public String getInstallToUserText() {
String userSiteText = "Install to user's site packages directory";
if (!PythonSdkType.isRemote(mySdk))
- userSiteText += " (" + PyPackageManagerImpl.getUserSite() + ")";
+ userSiteText += " (" + PySdkUtil.getUserSite() + ")";
return userSiteText;
}
@@ -130,12 +131,12 @@ public class PyPackageManagementService extends PackageManagementService {
public Collection<InstalledPackage> getInstalledPackages() throws IOException {
List<PyPackage> packages;
try {
- packages = ((PyPackageManagerImpl)PyPackageManager.getInstance(mySdk)).getPackages();
+ packages = PyPackageManager.getInstance(mySdk).getPackages(false);
}
catch (PyExternalProcessException e) {
throw new IOException(e);
}
- return new ArrayList<InstalledPackage>(packages);
+ return packages != null ? new ArrayList<InstalledPackage>(packages) : new ArrayList<InstalledPackage>();
}
@Override
@@ -145,7 +146,7 @@ public class PyPackageManagementService extends PackageManagementService {
final String repository = PyPIPackageUtil.PYPI_URL.equals(repoPackage.getRepoUrl()) ? null : repoPackage.getRepoUrl();
final List<String> extraArgs = new ArrayList<String>();
if (installToUser) {
- extraArgs.add(PyPackageManagerImpl.USE_USER_SITE);
+ extraArgs.add(PyPackageManager.USE_USER_SITE);
}
if (extraOptions != null) {
// TODO: Respect arguments quotation
@@ -166,7 +167,7 @@ public class PyPackageManagementService extends PackageManagementService {
req = new PyRequirement(packageName);
}
- final PyPackageManagerImpl.UI ui = new PyPackageManagerImpl.UI(myProject, mySdk, new PyPackageManagerImpl.UI.Listener() {
+ final PyPackageManagerUI ui = new PyPackageManagerUI(myProject, mySdk, new PyPackageManagerUI.Listener() {
@Override
public void started() {
listener.operationStarted(packageName);
@@ -183,7 +184,7 @@ public class PyPackageManagementService extends PackageManagementService {
private String toErrorDescription(List<PyExternalProcessException> exceptions) {
String errorDescription = null;
if (exceptions != null && exceptions.size() > 0) {
- errorDescription = PyPackageManagerImpl.UI.createDescription(exceptions, "");
+ errorDescription = PyPackageManagerUI.createDescription(exceptions, "");
}
return errorDescription;
}
@@ -191,7 +192,7 @@ public class PyPackageManagementService extends PackageManagementService {
@Override
public void uninstallPackages(List<InstalledPackage> installedPackages, final Listener listener) {
final String packageName = installedPackages.size() == 1 ? installedPackages.get(0).getName() : null;
- PyPackageManagerImpl.UI ui = new PyPackageManagerImpl.UI(myProject, mySdk, new PyPackageManagerImpl.UI.Listener() {
+ PyPackageManagerUI ui = new PyPackageManagerUI(myProject, mySdk, new PyPackageManagerUI.Listener() {
@Override
public void started() {
listener.operationStarted(packageName);
diff --git a/python/src/com/jetbrains/python/projectView/PyElementNode.java b/python/src/com/jetbrains/python/projectView/PyElementNode.java
index 20c7b811b8a6..6ec347236773 100644
--- a/python/src/com/jetbrains/python/projectView/PyElementNode.java
+++ b/python/src/com/jetbrains/python/projectView/PyElementNode.java
@@ -19,11 +19,14 @@ import com.intellij.ide.projectView.PresentationData;
import com.intellij.ide.projectView.ViewSettings;
import com.intellij.ide.projectView.impl.nodes.BasePsiNode;
import com.intellij.ide.util.treeView.AbstractTreeNode;
+import com.intellij.navigation.ItemPresentation;
import com.intellij.openapi.project.Project;
+import com.jetbrains.python.PyNames;
import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.PyElement;
import com.jetbrains.python.psi.PyFunction;
+import javax.swing.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -57,14 +60,23 @@ public class PyElementNode extends BasePsiNode<PyElement> {
@Override
protected void updateImpl(PresentationData data) {
- PyElement value = getValue();
+ final PyElement value = getValue();
final String name = value.getName();
- StringBuilder presentableText = new StringBuilder(name != null ? name : "<unnamed>");
- if (value instanceof PyFunction) {
- presentableText.append(((PyFunction) value).getParameterList().getPresentableText(false));
+ final ItemPresentation presentation = value.getPresentation();
+ String presentableText = name != null ? name : PyNames.UNNAMED_ELEMENT;
+ Icon presentableIcon = value.getIcon(0);
+ if (presentation != null) {
+ final String text = presentation.getPresentableText();
+ if (text != null) {
+ presentableText = text;
+ }
+ final Icon icon = presentation.getIcon(false);
+ if (icon != null) {
+ presentableIcon = icon;
+ }
}
- data.setPresentableText(presentableText.toString());
- data.setIcon(value.getIcon(0));
+ data.setPresentableText(presentableText);
+ data.setIcon(presentableIcon);
}
@Override
diff --git a/python/src/com/jetbrains/python/psi/PyUtil.java b/python/src/com/jetbrains/python/psi/PyUtil.java
index cd4e582bb6f2..dc5cbf4917a5 100644
--- a/python/src/com/jetbrains/python/psi/PyUtil.java
+++ b/python/src/com/jetbrains/python/psi/PyUtil.java
@@ -1394,8 +1394,8 @@ public class PyUtil {
@Nullable
public static PsiElement findPrevAtOffset(PsiFile psiFile, int caretOffset, Class... toSkip) {
- PsiElement element = psiFile.findElementAt(caretOffset);
- if (element == null || caretOffset < 0) {
+ PsiElement element;
+ if (caretOffset < 0) {
return null;
}
int lineStartOffset = 0;
diff --git a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java
index bb2104fc0c77..611cbc84ad2e 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java
@@ -17,6 +17,7 @@ package com.jetbrains.python.psi.impl;
import com.intellij.codeInsight.completion.CompletionUtil;
import com.intellij.lang.ASTNode;
+import com.intellij.navigation.ItemPresentation;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.NotNullLazyValue;
@@ -53,10 +54,13 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.*;
+import static com.intellij.openapi.util.text.StringUtil.join;
+import static com.intellij.openapi.util.text.StringUtil.notNullize;
+
/**
* @author yole
*/
-public class PyClassImpl extends PyPresentableElementImpl<PyClassStub> implements PyClass {
+public class PyClassImpl extends PyBaseElementImpl<PyClassStub> implements PyClass {
public static final PyClass[] EMPTY_ARRAY = new PyClassImpl[0];
private List<PyTargetExpression> myInstanceAttributes;
@@ -288,6 +292,32 @@ public class PyClassImpl extends PyPresentableElementImpl<PyClassStub> implement
return result.toArray(new PyClass[result.size()]);
}
+ @Override
+ public ItemPresentation getPresentation() {
+ return new PyElementPresentation(this) {
+ @Nullable
+ @Override
+ public String getPresentableText() {
+ if (!isValid()) {
+ return null;
+ }
+ final StringBuilder result = new StringBuilder(notNullize(getName(), PyNames.UNNAMED_ELEMENT));
+ final PyExpression[] superClassExpressions = getSuperClassExpressions();
+ if (superClassExpressions.length > 0) {
+ result.append("(");
+ result.append(join(Arrays.asList(superClassExpressions), new Function<PyExpression, String>() {
+ public String fun(PyExpression expr) {
+ String name = expr.getText();
+ return notNullize(name, PyNames.UNNAMED_ELEMENT);
+ }
+ }, ", "));
+ result.append(")");
+ }
+ return result.toString();
+ }
+ };
+ }
+
@NotNull
private static List<PyClassLikeType> mroMerge(@NotNull List<List<PyClassLikeType>> sequences) {
List<PyClassLikeType> result = new LinkedList<PyClassLikeType>(); // need to insert to 0th position on linearize
diff --git a/python/src/com/jetbrains/python/psi/impl/PyElementPresentation.java b/python/src/com/jetbrains/python/psi/impl/PyElementPresentation.java
new file mode 100644
index 000000000000..7888071c7321
--- /dev/null
+++ b/python/src/com/jetbrains/python/psi/impl/PyElementPresentation.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.psi.impl;
+
+import com.intellij.navigation.ColoredItemPresentation;
+import com.intellij.openapi.editor.colors.TextAttributesKey;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiFile;
+import com.jetbrains.python.PyNames;
+import com.jetbrains.python.psi.PyElement;
+import com.jetbrains.python.psi.resolve.QualifiedNameFinder;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+
+/**
+* @author vlan
+*/
+public class PyElementPresentation implements ColoredItemPresentation {
+ @NotNull private final PyElement myElement;
+
+ public PyElementPresentation(@NotNull PyElement element) {
+ myElement = element;
+ }
+
+ @Nullable
+ @Override
+ public TextAttributesKey getTextAttributesKey() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public String getPresentableText() {
+ final String name = myElement.getName();
+ return name != null ? name : PyNames.UNNAMED_ELEMENT;
+ }
+
+ @Nullable
+ @Override
+ public String getLocationString() {
+ return "(" + getPackageForFile(myElement.getContainingFile()) + ")";
+ }
+
+ @Nullable
+ @Override
+ public Icon getIcon(boolean unused) {
+ return myElement.getIcon(0);
+ }
+
+ public static String getPackageForFile(@NotNull PsiFile containingFile) {
+ final VirtualFile vFile = containingFile.getVirtualFile();
+
+ if (vFile != null) {
+ final String importableName = QualifiedNameFinder.findShortestImportableName(containingFile, vFile);
+ if (importableName != null) {
+ return importableName;
+ }
+ }
+ return "";
+ }
+}
diff --git a/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java
index 86f84abb7fb6..2c1842f3337f 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java
@@ -16,6 +16,7 @@
package com.jetbrains.python.psi.impl;
import com.intellij.lang.ASTNode;
+import com.intellij.navigation.ItemPresentation;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Ref;
@@ -54,6 +55,7 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.*;
+import static com.intellij.openapi.util.text.StringUtil.notNullize;
import static com.jetbrains.python.psi.PyFunction.Modifier.CLASSMETHOD;
import static com.jetbrains.python.psi.PyFunction.Modifier.STATICMETHOD;
import static com.jetbrains.python.psi.impl.PyCallExpressionHelper.interpretAsModifierWrappingCall;
@@ -61,7 +63,7 @@ import static com.jetbrains.python.psi.impl.PyCallExpressionHelper.interpretAsMo
/**
* Implements PyFunction.
*/
-public class PyFunctionImpl extends PyPresentableElementImpl<PyFunctionStub> implements PyFunction {
+public class PyFunctionImpl extends PyBaseElementImpl<PyFunctionStub> implements PyFunction {
public PyFunctionImpl(ASTNode astNode) {
super(astNode);
@@ -259,6 +261,17 @@ public class PyFunctionImpl extends PyPresentableElementImpl<PyFunctionStub> imp
return type;
}
+ @Override
+ public ItemPresentation getPresentation() {
+ return new PyElementPresentation(this) {
+ @Nullable
+ @Override
+ public String getPresentableText() {
+ return notNullize(getName(), PyNames.UNNAMED_ELEMENT) + getParameterList().getPresentableText(true);
+ }
+ };
+ }
+
@Nullable
private PyType replaceSelf(@Nullable PyType returnType, @Nullable PyExpression receiver, @NotNull TypeEvalContext context) {
if (receiver != null) {
@@ -292,32 +305,30 @@ public class PyFunctionImpl extends PyPresentableElementImpl<PyFunctionStub> imp
final PyBuiltinCache cache = PyBuiltinCache.getInstance(this);
final PyStatementList statements = getStatementList();
final Set<PyType> types = new LinkedHashSet<PyType>();
- if (statements != null) {
- statements.accept(new PyRecursiveElementVisitor() {
- @Override
- public void visitPyYieldExpression(PyYieldExpression node) {
- final PyType type = context.getType(node);
- if (node.isDelegating() && type instanceof PyCollectionType) {
- final PyCollectionType collectionType = (PyCollectionType)type;
- types.add(collectionType.getElementType(context));
- }
- else {
- types.add(type);
- }
+ statements.accept(new PyRecursiveElementVisitor() {
+ @Override
+ public void visitPyYieldExpression(PyYieldExpression node) {
+ final PyType type = context.getType(node);
+ if (node.isDelegating() && type instanceof PyCollectionType) {
+ final PyCollectionType collectionType = (PyCollectionType)type;
+ types.add(collectionType.getElementType(context));
}
-
- @Override
- public void visitPyFunction(PyFunction node) {
- // Ignore nested functions
+ else {
+ types.add(type);
}
- });
- final int n = types.size();
- if (n == 1) {
- elementType = Ref.create(types.iterator().next());
}
- else if (n > 0) {
- elementType = Ref.create(PyUnionType.union(types));
+
+ @Override
+ public void visitPyFunction(PyFunction node) {
+ // Ignore nested functions
}
+ });
+ final int n = types.size();
+ if (n == 1) {
+ elementType = Ref.create(types.iterator().next());
+ }
+ else if (n > 0) {
+ elementType = Ref.create(PyUnionType.union(types));
}
if (elementType != null) {
final PyClass generator = cache.getClass(PyNames.FAKE_GENERATOR);
@@ -335,14 +346,12 @@ public class PyFunctionImpl extends PyPresentableElementImpl<PyFunctionStub> imp
public PyType getReturnStatementType(TypeEvalContext typeEvalContext) {
ReturnVisitor visitor = new ReturnVisitor(this, typeEvalContext);
final PyStatementList statements = getStatementList();
- if (statements != null) {
- statements.accept(visitor);
- if (isGeneratedStub() && !visitor.myHasReturns) {
- if (PyNames.INIT.equals(getName())) {
- return PyNoneType.INSTANCE;
- }
- return null;
+ statements.accept(visitor);
+ if (isGeneratedStub() && !visitor.myHasReturns) {
+ if (PyNames.INIT.equals(getName())) {
+ return PyNoneType.INSTANCE;
}
+ return null;
}
return visitor.result();
}
@@ -376,9 +385,6 @@ public class PyFunctionImpl extends PyPresentableElementImpl<PyFunctionStub> imp
@Nullable
public String extractDeprecationMessage() {
PyStatementList statementList = getStatementList();
- if (statementList == null) {
- return null;
- }
return extractDeprecationMessage(Arrays.asList(statementList.getStatements()));
}
@@ -430,7 +436,7 @@ public class PyFunctionImpl extends PyPresentableElementImpl<PyFunctionStub> imp
@Nullable
@Override
public StructuredDocString getStructuredDocString() {
- return CachedValuesManager.getManager(getProject()).getCachedValue(this, myCachedStructuredDocStringProvider);
+ return CachedValuesManager.getCachedValue(this, myCachedStructuredDocStringProvider);
}
private boolean isGeneratedStub() {
@@ -527,15 +533,7 @@ public class PyFunctionImpl extends PyPresentableElementImpl<PyFunctionStub> imp
public PyStringLiteralExpression getDocStringExpression() {
final PyStatementList stmtList = getStatementList();
- return stmtList != null ? DocStringUtil.findDocStringExpression(stmtList) : null;
- }
-
- protected String getElementLocation() {
- final PyClass containingClass = getContainingClass();
- if (containingClass != null) {
- return "(" + containingClass.getName() + " in " + getPackageForFile(getContainingFile()) + ")";
- }
- return super.getElementLocation();
+ return DocStringUtil.findDocStringExpression(stmtList);
}
@NotNull
diff --git a/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java b/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java
index cc9178c07f9e..64108441c347 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java
@@ -16,6 +16,7 @@
package com.jetbrains.python.psi.impl;
import com.intellij.lang.ASTNode;
+import com.intellij.navigation.ItemPresentation;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
@@ -48,7 +49,7 @@ import java.util.Map;
/**
* @author yole
*/
-public class PyNamedParameterImpl extends PyPresentableElementImpl<PyNamedParameterStub> implements PyNamedParameter {
+public class PyNamedParameterImpl extends PyBaseElementImpl<PyNamedParameterStub> implements PyNamedParameter {
public PyNamedParameterImpl(ASTNode astNode) {
super(astNode);
}
@@ -280,6 +281,11 @@ public class PyNamedParameterImpl extends PyPresentableElementImpl<PyNamedParame
return null;
}
+ @Override
+ public ItemPresentation getPresentation() {
+ return new PyElementPresentation(this);
+ }
+
private static void processLocalCalls(@NotNull PyFunction function, @NotNull Processor<PyCallExpression> processor) {
final PsiFile file = function.getContainingFile();
final String name = function.getName();
diff --git a/python/src/com/jetbrains/python/psi/impl/PyPresentableElementImpl.java b/python/src/com/jetbrains/python/psi/impl/PyPresentableElementImpl.java
deleted file mode 100644
index d04d04062651..000000000000
--- a/python/src/com/jetbrains/python/psi/impl/PyPresentableElementImpl.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright 2000-2013 JetBrains s.r.o.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.jetbrains.python.psi.impl;
-
-import com.intellij.lang.ASTNode;
-import com.intellij.navigation.ItemPresentation;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.psi.PsiFile;
-import com.intellij.psi.PsiNamedElement;
-import com.intellij.psi.stubs.IStubElementType;
-import com.intellij.psi.stubs.StubElement;
-import com.jetbrains.python.psi.resolve.QualifiedNameFinder;
-
-import javax.swing.*;
-
-/**
- * @author yole
- */
-public abstract class PyPresentableElementImpl<T extends StubElement> extends PyBaseElementImpl<T> implements PsiNamedElement {
- public PyPresentableElementImpl(ASTNode astNode) {
- super(astNode);
- }
-
- protected PyPresentableElementImpl(final T stub, final IStubElementType nodeType) {
- super(stub, nodeType);
- }
-
- public ItemPresentation getPresentation() {
- return new ItemPresentation() {
- public String getPresentableText() {
- final String name = getName();
- return name != null ? name : "<none>";
- }
-
- public String getLocationString() {
- return getElementLocation();
- }
-
- public Icon getIcon(final boolean open) {
- return PyPresentableElementImpl.this.getIcon(0);
- }
- };
- }
-
- protected String getElementLocation() {
- return "(" + getPackageForFile(getContainingFile()) + ")";
- }
-
- public static String getPackageForFile(final PsiFile containingFile) {
- final VirtualFile vFile = containingFile.getVirtualFile();
-
- if (vFile != null) {
- final String importableName = QualifiedNameFinder.findShortestImportableName(containingFile, vFile);
- if (importableName != null) {
- return importableName;
- }
- }
- return "";
- }
-}
diff --git a/python/src/com/jetbrains/python/psi/impl/PySingleStarParameterImpl.java b/python/src/com/jetbrains/python/psi/impl/PySingleStarParameterImpl.java
index 70a46fbe39f9..44a01759f403 100644
--- a/python/src/com/jetbrains/python/psi/impl/PySingleStarParameterImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PySingleStarParameterImpl.java
@@ -16,21 +16,18 @@
package com.jetbrains.python.psi.impl;
import com.intellij.lang.ASTNode;
-import com.intellij.psi.PsiElement;
-import com.intellij.util.IncorrectOperationException;
+import com.intellij.navigation.ItemPresentation;
import com.jetbrains.python.PyElementTypes;
import com.jetbrains.python.psi.PyExpression;
import com.jetbrains.python.psi.PyNamedParameter;
import com.jetbrains.python.psi.PySingleStarParameter;
import com.jetbrains.python.psi.PyTupleParameter;
import com.jetbrains.python.psi.stubs.PySingleStarParameterStub;
-import org.jetbrains.annotations.NonNls;
-import org.jetbrains.annotations.NotNull;
/**
* @author yole
*/
-public class PySingleStarParameterImpl extends PyPresentableElementImpl<PySingleStarParameterStub> implements PySingleStarParameter {
+public class PySingleStarParameterImpl extends PyBaseElementImpl<PySingleStarParameterStub> implements PySingleStarParameter {
public PySingleStarParameterImpl(ASTNode astNode) {
super(astNode);
}
@@ -39,22 +36,22 @@ public class PySingleStarParameterImpl extends PyPresentableElementImpl<PySingle
super(stub, PyElementTypes.SINGLE_STAR_PARAMETER);
}
- public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException {
- throw new UnsupportedOperationException();
- }
-
+ @Override
public PyNamedParameter getAsNamed() {
return null;
}
+ @Override
public PyTupleParameter getAsTuple() {
return null;
}
+ @Override
public PyExpression getDefaultValue() {
return null;
}
+ @Override
public boolean hasDefaultValue() {
return false;
}
@@ -63,4 +60,9 @@ public class PySingleStarParameterImpl extends PyPresentableElementImpl<PySingle
public boolean isSelf() {
return false;
}
+
+ @Override
+ public ItemPresentation getPresentation() {
+ return new PyElementPresentation(this);
+ }
}
diff --git a/python/src/com/jetbrains/python/psi/impl/PyStringLiteralExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyStringLiteralExpressionImpl.java
index bf519737f0f4..084aeecc3df0 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyStringLiteralExpressionImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyStringLiteralExpressionImpl.java
@@ -327,7 +327,7 @@ public class PyStringLiteralExpressionImpl extends PyElementImpl implements PySt
@Nullable
@Override
public String getLocationString() {
- return "(" + PyPresentableElementImpl.getPackageForFile(getContainingFile()) + ")";
+ return "(" + PyElementPresentation.getPackageForFile(getContainingFile()) + ")";
}
@Nullable
diff --git a/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java
index 3805c8df525e..d125190b77e9 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java
@@ -16,6 +16,7 @@
package com.jetbrains.python.psi.impl;
import com.intellij.lang.ASTNode;
+import com.intellij.navigation.ItemPresentation;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Ref;
@@ -61,7 +62,7 @@ import java.util.List;
/**
* @author yole
*/
-public class PyTargetExpressionImpl extends PyPresentableElementImpl<PyTargetExpressionStub> implements PyTargetExpression {
+public class PyTargetExpressionImpl extends PyBaseElementImpl<PyTargetExpressionStub> implements PyTargetExpression {
QualifiedName myQualifiedName;
public PyTargetExpressionImpl(ASTNode astNode) {
@@ -659,12 +660,19 @@ public class PyTargetExpressionImpl extends PyPresentableElementImpl<PyTargetExp
return null;
}
- protected String getElementLocation() {
- final PyClass containingClass = getContainingClass();
- if (containingClass != null) {
- return "(" + containingClass.getName() + " in " + getPackageForFile(getContainingFile()) + ")";
- }
- return super.getElementLocation();
+ @Override
+ public ItemPresentation getPresentation() {
+ return new PyElementPresentation(this) {
+ @Nullable
+ @Override
+ public String getLocationString() {
+ final PyClass containingClass = getContainingClass();
+ if (containingClass != null) {
+ return "(" + containingClass.getName() + " in " + getPackageForFile(getContainingFile()) + ")";
+ }
+ return super.getLocationString();
+ }
+ };
}
@Nullable
diff --git a/python/src/com/jetbrains/python/psi/impl/PyTupleParameterImpl.java b/python/src/com/jetbrains/python/psi/impl/PyTupleParameterImpl.java
index 09e097cb0e99..9935841c33bb 100644
--- a/python/src/com/jetbrains/python/psi/impl/PyTupleParameterImpl.java
+++ b/python/src/com/jetbrains/python/psi/impl/PyTupleParameterImpl.java
@@ -16,19 +16,17 @@
package com.jetbrains.python.psi.impl;
import com.intellij.lang.ASTNode;
-import com.intellij.psi.PsiElement;
-import com.intellij.util.IncorrectOperationException;
+import com.intellij.navigation.ItemPresentation;
import com.jetbrains.python.PyElementTypes;
import com.jetbrains.python.PythonDialectsTokenSetProvider;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.stubs.PyTupleParameterStub;
-import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
/**
* Represents a tuple parameter as stubbed element.
*/
-public class PyTupleParameterImpl extends PyPresentableElementImpl<PyTupleParameterStub> implements PyTupleParameter {
+public class PyTupleParameterImpl extends PyBaseElementImpl<PyTupleParameterStub> implements PyTupleParameter {
public PyTupleParameterImpl(ASTNode astNode) {
super(astNode);
@@ -62,10 +60,6 @@ public class PyTupleParameterImpl extends PyPresentableElementImpl<PyTupleParame
return getDefaultValue() != null;
}
- public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException {
- throw new IncorrectOperationException("Can't rename a tuple parameter to '" + name +"'");
- }
-
@Override
protected void acceptPyVisitor(PyElementVisitor pyVisitor) {
pyVisitor.visitPyTupleParameter(this);
@@ -80,4 +74,9 @@ public class PyTupleParameterImpl extends PyPresentableElementImpl<PyTupleParame
public boolean isSelf() {
return false;
}
+
+ @Override
+ public ItemPresentation getPresentation() {
+ return new PyElementPresentation(this);
+ }
}
diff --git a/python/src/com/jetbrains/python/psi/impl/PythonLanguageLevelPusher.java b/python/src/com/jetbrains/python/psi/impl/PythonLanguageLevelPusher.java
index 7e15cab6ffda..af767684643e 100644
--- a/python/src/com/jetbrains/python/psi/impl/PythonLanguageLevelPusher.java
+++ b/python/src/com/jetbrains/python/psi/impl/PythonLanguageLevelPusher.java
@@ -19,7 +19,9 @@ import com.intellij.facet.Facet;
import com.intellij.facet.FacetManager;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypeManager;
+import com.intellij.openapi.fileTypes.FileTypeRegistry;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.module.ModuleType;
@@ -163,7 +165,8 @@ public class PythonLanguageLevelPusher implements FilePropertyPusher<LanguageLev
oStream.close();
for (VirtualFile child : fileOrDir.getChildren()) {
- if (!child.isDirectory() && PythonFileType.INSTANCE.equals(child.getFileType())) {
+ final FileType fileType = FileTypeRegistry.getInstance().getFileTypeByFileName(child.getName());
+ if (!child.isDirectory() && PythonFileType.INSTANCE.equals(fileType)) {
PushedFilePropertiesUpdater.getInstance(project).filePropertiesChanged(child);
}
}
diff --git a/python/src/com/jetbrains/python/refactoring/changeSignature/PyChangeSignatureHandler.java b/python/src/com/jetbrains/python/refactoring/changeSignature/PyChangeSignatureHandler.java
index 6895249a641f..e360c9e46685 100644
--- a/python/src/com/jetbrains/python/refactoring/changeSignature/PyChangeSignatureHandler.java
+++ b/python/src/com/jetbrains/python/refactoring/changeSignature/PyChangeSignatureHandler.java
@@ -126,7 +126,7 @@ public class PyChangeSignatureHandler implements ChangeSignatureHandler {
private static boolean isNotUnderSourceRoot(@NotNull final Project project,
@Nullable final PsiFile psiFile,
- @NotNull final Editor editor) {
+ @Nullable final Editor editor) {
if (psiFile == null) return true;
final VirtualFile virtualFile = psiFile.getVirtualFile();
if (virtualFile != null) {
diff --git a/python/src/com/jetbrains/python/refactoring/move/PyMoveClassOrFunctionDelegate.java b/python/src/com/jetbrains/python/refactoring/move/PyMoveClassOrFunctionDelegate.java
index cf1b4d19dd4e..8306a4faec23 100644
--- a/python/src/com/jetbrains/python/refactoring/move/PyMoveClassOrFunctionDelegate.java
+++ b/python/src/com/jetbrains/python/refactoring/move/PyMoveClassOrFunctionDelegate.java
@@ -39,11 +39,10 @@ import org.jetbrains.annotations.Nullable;
* @author vlan
*/
public class PyMoveClassOrFunctionDelegate extends MoveHandlerDelegate {
-
@Override
public boolean canMove(PsiElement[] elements, @Nullable PsiElement targetContainer) {
for (PsiElement element : elements) {
- if (element instanceof PyClass || element instanceof PyFunction) continue;
+ if ((element instanceof PyClass || element instanceof PyFunction) && PyUtil.isTopLevel(element)) continue;
return false;
}
return super.canMove(elements, targetContainer);
diff --git a/python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.java b/python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.java
index 39fc2c909cf6..1d0a4bc3ad54 100644
--- a/python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.java
+++ b/python/src/com/jetbrains/python/sdk/CreateVirtualEnvDialog.java
@@ -48,9 +48,9 @@ import com.intellij.ui.components.JBLabel;
import com.intellij.util.NullableConsumer;
import com.intellij.util.PathUtil;
import com.intellij.util.PlatformUtils;
+import com.intellij.webcore.packaging.PackagesNotificationPanel;
import com.jetbrains.python.packaging.PyExternalProcessException;
import com.jetbrains.python.packaging.PyPackageManager;
-import com.jetbrains.python.packaging.PyPackageManagerImpl;
import com.jetbrains.python.packaging.PyPackageService;
import com.jetbrains.python.sdk.flavors.VirtualEnvSdkFlavor;
import com.jetbrains.python.ui.IdeaDialog;
@@ -416,7 +416,7 @@ public class CreateVirtualEnvDialog extends IdeaDialog {
String myPath;
public void run(@NotNull final ProgressIndicator indicator) {
- final PyPackageManagerImpl packageManager = (PyPackageManagerImpl)PyPackageManager.getInstance(basicSdk);
+ final PyPackageManager packageManager = PyPackageManager.getInstance(basicSdk);
try {
indicator.setText("Creating virtual environment for " + basicSdk.getName());
myPath = packageManager.createVirtualEnv(getDestination(), useGlobalSitePackages());
@@ -425,7 +425,7 @@ public class CreateVirtualEnvDialog extends IdeaDialog {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
- packageManager.showInstallationError(getOwner(), "Failed to Create Virtual Environment", e.toString());
+ PackagesNotificationPanel.showError(getOwner(), "Failed to Create Virtual Environment", e.toString());
}
}, ModalityState.any());
}
diff --git a/python/src/com/jetbrains/python/sdk/PySdkUtil.java b/python/src/com/jetbrains/python/sdk/PySdkUtil.java
index 8f2b62b1b414..97d5ee545cbb 100644
--- a/python/src/com/jetbrains/python/sdk/PySdkUtil.java
+++ b/python/src/com/jetbrains/python/sdk/PySdkUtil.java
@@ -15,10 +15,13 @@
*/
package com.jetbrains.python.sdk;
+import com.intellij.execution.ExecutionException;
import com.intellij.execution.process.CapturingProcessHandler;
import com.intellij.execution.process.ProcessOutput;
+import com.intellij.execution.util.ExecUtil;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.module.Module;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.util.SystemInfo;
@@ -29,8 +32,10 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.remote.RemoteSdkAdditionalData;
-import com.intellij.util.ArrayUtil;
+import com.intellij.util.SystemProperties;
import com.intellij.util.containers.HashMap;
+import com.jetbrains.python.packaging.PyPackageUtil;
+import com.jetbrains.python.packaging.PyRequirement;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -38,8 +43,7 @@ import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.Collections;
+import java.util.Arrays;
import java.util.List;
import java.util.Map;
@@ -56,6 +60,7 @@ public class PySdkUtil {
// Windows EOF marker, Ctrl+Z
public static final int SUBSTITUTE = 26;
+ public static final String PATH_ENV_VARIABLE = "PATH";
private PySdkUtil() {
// explicitly none
@@ -87,57 +92,29 @@ public class PySdkUtil {
return getProcessOutput(homePath, command, null, timeout);
}
- /**
- * Executes a process and returns its stdout and stderr outputs as lists of lines.
- * Waits for process for possibly limited duration.
- *
- * @param homePath process run directory
- * @param command command to execute and its arguments
- * @param addEnv items are prepended to same-named values of inherited process environment.
- * @param timeout how many milliseconds to wait until the process terminates; non-positive means inifinity.
- * @return a tuple of (stdout lines, stderr lines, exit_code), lines in them have line terminators stripped, or may be null.
- */
@NotNull
public static ProcessOutput getProcessOutput(String homePath,
@NonNls String[] command,
- @Nullable @NonNls String[] addEnv,
+ @Nullable @NonNls Map<String, String> extraEnv,
final int timeout) {
- return getProcessOutput(homePath, command, addEnv, timeout, null, true);
+ return getProcessOutput(homePath, command, extraEnv, timeout, null, true);
}
- /**
- * Executes a process and returns its stdout and stderr outputs as lists of lines.
- * Waits for process for possibly limited duration.
- *
- * @param homePath process run directory
- * @param command command to execute and its arguments
- * @param addEnv items are prepended to same-named values of inherited process environment.
- * @param timeout how many milliseconds to wait until the process terminates; non-positive means infinity.
- * @param stdin the data to write to the process standard input stream
- * @param needEOFMarker
- * @return a tuple of (stdout lines, stderr lines, exit_code), lines in them have line terminators stripped, or may be null.
- */
@NotNull
public static ProcessOutput getProcessOutput(String homePath,
@NonNls String[] command,
- @Nullable @NonNls String[] addEnv,
+ @Nullable @NonNls Map<String, String> extraEnv,
final int timeout,
@Nullable byte[] stdin,
boolean needEOFMarker) {
- final ProcessOutput failureOutput = new ProcessOutput();
if (homePath == null || !new File(homePath).exists()) {
- return failureOutput;
+ return new ProcessOutput();
}
+ final Map<String, String> systemEnv = System.getenv();
+ final Map<String, String> env = extraEnv != null ? mergeEnvVariables(systemEnv, extraEnv) : systemEnv;
try {
- List<String> commands = new ArrayList<String>();
- if (SystemInfo.isWindows && StringUtil.endsWithIgnoreCase(command[0], ".bat")) {
- commands.add("cmd");
- commands.add("/c");
- }
- Collections.addAll(commands, command);
- String[] newEnv = buildAdditionalEnv(addEnv);
- Process process = Runtime.getRuntime().exec(ArrayUtil.toStringArray(commands), newEnv, new File(homePath));
- CapturingProcessHandler processHandler = new CapturingProcessHandler(process);
+ final Process process = ExecUtil.exec(Arrays.asList(command), homePath, env);
+ final CapturingProcessHandler processHandler = new CapturingProcessHandler(process);
if (stdin != null) {
final OutputStream processInput = processHandler.getProcessInput();
assert processInput != null;
@@ -152,72 +129,61 @@ public class PySdkUtil {
}
return processHandler.runProcess(timeout);
}
- catch (final IOException ex) {
- LOG.warn(ex);
- return new ProcessOutput() {
- @Override
- public String getStderr() {
- String err = super.getStderr();
- if (!StringUtil.isEmpty(err)) {
- err += "\n" + ex.getMessage();
- }
- else {
- err = ex.getMessage();
- }
- return err;
- }
- };
+ catch (ExecutionException e) {
+ return getOutputForException(e);
+ }
+ catch (IOException e) {
+ return getOutputForException(e);
}
}
- private static String[] buildAdditionalEnv(String[] addEnv) {
- String[] newEnv = null;
- if (addEnv != null) {
- Map<String, String> envMap = buildEnvMap(addEnv);
- newEnv = new String[envMap.size()];
- int i = 0;
- for (Map.Entry<String, String> entry : envMap.entrySet()) {
- newEnv[i] = entry.getKey() + "=" + entry.getValue();
- i += 1;
+ private static ProcessOutput getOutputForException(final Exception e) {
+ LOG.warn(e);
+ return new ProcessOutput() {
+ @Override
+ public String getStderr() {
+ String err = super.getStderr();
+ if (!StringUtil.isEmpty(err)) {
+ err += "\n" + e.getMessage();
+ }
+ else {
+ err = e.getMessage();
+ }
+ return err;
}
- }
- return newEnv;
+ };
}
- public static Map<String, String> buildEnvMap(String[] addEnv) {
- Map<String, String> envMap = new HashMap<String, String>(System.getenv());
- // turn additional ent into map
- Map<String, String> addMap = new HashMap<String, String>();
- for (String envItem : addEnv) {
- int pos = envItem.indexOf('=');
- if (pos > 0) {
- String key = envItem.substring(0, pos);
- String value = envItem.substring(pos + 1, envItem.length());
- addMap.put(key, value);
- }
- else {
- LOG.warn(String.format("Invalid env value: '%s'", envItem));
- }
- }
- // fuse old and new
- for (Map.Entry<String, String> entry : addMap.entrySet()) {
- final String key = entry.getKey();
- final String value = entry.getValue();
- final String oldValue = envMap.get(key);
- if (oldValue != null) {
- envMap.put(key, value + oldValue);
+ @NotNull
+ public static Map<String, String> mergeEnvVariables(@NotNull Map<String, String> environment,
+ @NotNull Map<String, String> extraEnvironment) {
+ final Map<String, String> result = new HashMap<String, String>(environment);
+ for (Map.Entry<String, String> entry : extraEnvironment.entrySet()) {
+ if (PATH_ENV_VARIABLE.equals(entry.getKey()) && result.containsKey(PATH_ENV_VARIABLE)) {
+ result.put(PATH_ENV_VARIABLE, result.get(PATH_ENV_VARIABLE) + File.pathSeparator + entry.getValue());
}
else {
- envMap.put(key, value);
+ result.put(entry.getKey(), entry.getValue());
}
}
- return envMap;
+ return result;
}
public static boolean isRemote(@Nullable Sdk sdk) {
return sdk != null && sdk.getSdkAdditionalData() instanceof RemoteSdkAdditionalData;
}
+ public static String getUserSite() {
+ if (SystemInfo.isWindows) {
+ final String appdata = System.getenv("APPDATA");
+ return appdata + File.separator + "Python";
+ }
+ else {
+ final String userHome = SystemProperties.getUserHome();
+ return userHome + File.separator + ".local";
+ }
+ }
+
public static boolean isElementInSkeletons(@NotNull final PsiElement element) {
final PsiFile file = element.getContainingFile();
if (file != null) {
@@ -266,4 +232,13 @@ public class PySdkUtil {
}
return null;
}
+
+ @Nullable
+ public static List<PyRequirement> getRequirementsFromTxt(Module module) {
+ final VirtualFile requirementsTxt = PyPackageUtil.findRequirementsTxt(module);
+ if (requirementsTxt != null) {
+ return PyRequirement.parse(requirementsTxt);
+ }
+ return null;
+ }
}
diff --git a/python/src/com/jetbrains/python/sdk/PythonSdkDetailsStep.java b/python/src/com/jetbrains/python/sdk/PythonSdkDetailsStep.java
index 923629ce4473..cc6a2c6b6121 100644
--- a/python/src/com/jetbrains/python/sdk/PythonSdkDetailsStep.java
+++ b/python/src/com/jetbrains/python/sdk/PythonSdkDetailsStep.java
@@ -46,7 +46,7 @@ import java.util.List;
import java.util.Set;
public class PythonSdkDetailsStep extends BaseListPopupStep<String> {
- private DialogWrapper myMore;
+ @Nullable private DialogWrapper myMore;
private final Project myProject;
private final Component myOwnerComponent;
private final Sdk[] myExistingSdks;
@@ -120,6 +120,8 @@ public class PythonSdkDetailsStep extends BaseListPopupStep<String> {
}
private void optionSelected(final String selectedValue) {
+ if (!MORE.equals(selectedValue) && myMore != null)
+ Disposer.dispose(myMore.getDisposable());
if (LOCAL.equals(selectedValue)) {
createLocalSdk();
}
@@ -129,7 +131,7 @@ public class PythonSdkDetailsStep extends BaseListPopupStep<String> {
else if (VIRTUALENV.equals(selectedValue)) {
createVirtualEnvSdk();
}
- else {
+ else if (myMore != null) {
myMore.show();
}
}
diff --git a/python/src/com/jetbrains/python/sdk/PythonSdkType.java b/python/src/com/jetbrains/python/sdk/PythonSdkType.java
index 58de09370d37..460c875491ce 100644
--- a/python/src/com/jetbrains/python/sdk/PythonSdkType.java
+++ b/python/src/com/jetbrains/python/sdk/PythonSdkType.java
@@ -15,6 +15,7 @@
*/
package com.jetbrains.python.sdk;
+import com.google.common.collect.ImmutableMap;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.execution.process.ProcessOutput;
@@ -771,16 +772,12 @@ public class PythonSdkType extends SdkType {
}
@NotNull
- public static List<String> getSysPathsFromScript(String bin_path) throws InvalidSdkException {
+ public static List<String> getSysPathsFromScript(@NotNull String binaryPath) throws InvalidSdkException {
String scriptFile = PythonHelpersLocator.getHelperPath("syspath.py");
// to handle the situation when PYTHONPATH contains ., we need to run the syspath script in the
// directory of the script itself - otherwise the dir in which we run the script (e.g. /usr/bin) will be added to SDK path
- String[] add_environment = getVirtualEnvAdditionalEnv(bin_path);
- final ProcessOutput run_result = PySdkUtil.getProcessOutput(
- new File(scriptFile).getParent(),
- new String[]{bin_path, scriptFile},
- add_environment, MINUTE
- );
+ final ProcessOutput run_result = PySdkUtil.getProcessOutput(new File(scriptFile).getParent(), new String[]{binaryPath, scriptFile},
+ getVirtualEnvExtraEnv(binaryPath), MINUTE);
if (!run_result.checkSuccess(LOG)) {
throw new InvalidSdkException(String.format("Failed to determine Python's sys.path value:\nSTDOUT: %s\nSTDERR: %s",
run_result.getStdout(),
@@ -789,15 +786,16 @@ public class PythonSdkType extends SdkType {
return run_result.getStdoutLines();
}
- // Returns a piece of env good as additional env for getProcessOutput.
+ /**
+ * Returns a piece of env good as additional env for getProcessOutput.
+ */
@Nullable
- public static String[] getVirtualEnvAdditionalEnv(String bin_path) {
- File virtualenv_root = getVirtualEnvRoot(bin_path);
- String[] add_environment = null;
- if (virtualenv_root != null) {
- add_environment = new String[]{"PATH=" + virtualenv_root + File.pathSeparator};
+ public static Map<String, String> getVirtualEnvExtraEnv(@NotNull String binaryPath) {
+ final File root = getVirtualEnvRoot(binaryPath);
+ if (root != null) {
+ return ImmutableMap.of("PATH", root.toString());
}
- return add_environment;
+ return null;
}
@Nullable
diff --git a/python/src/com/jetbrains/python/sdk/PythonSdkUpdater.java b/python/src/com/jetbrains/python/sdk/PythonSdkUpdater.java
index b4b968fdb108..fb77cdb26f8f 100644
--- a/python/src/com/jetbrains/python/sdk/PythonSdkUpdater.java
+++ b/python/src/com/jetbrains/python/sdk/PythonSdkUpdater.java
@@ -32,7 +32,6 @@ import com.intellij.openapi.projectRoots.SdkModificator;
import com.intellij.openapi.projectRoots.SdkTypeId;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.startup.StartupActivity;
-import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.io.FileUtilRt;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
@@ -149,7 +148,7 @@ public class PythonSdkUpdater implements StartupActivity {
}
public static void updateSdk(@Nullable Project project, @Nullable Component ownerComponent, @NotNull final Sdk sdk, String skeletonsPath) throws InvalidSdkException {
- PySkeletonRefresher.refreshSkeletonsOfSdk(project, ownerComponent, skeletonsPath, new Ref<Boolean>(false), sdk); // NOTE: whole thing would need a rename
+ PySkeletonRefresher.refreshSkeletonsOfSdk(project, ownerComponent, skeletonsPath, sdk); // NOTE: whole thing would need a rename
if (!PySdkUtil.isRemote(sdk)) {
updateSysPath(sdk);
}
diff --git a/python/src/com/jetbrains/python/sdk/flavors/WinPythonSdkFlavor.java b/python/src/com/jetbrains/python/sdk/flavors/WinPythonSdkFlavor.java
index 9d22af8c03bf..3a9ac951509d 100644
--- a/python/src/com/jetbrains/python/sdk/flavors/WinPythonSdkFlavor.java
+++ b/python/src/com/jetbrains/python/sdk/flavors/WinPythonSdkFlavor.java
@@ -37,6 +37,8 @@ public class WinPythonSdkFlavor extends CPythonSdkFlavor {
"HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Python\\PythonCore", "python.exe",
"HKEY_LOCAL_MACHINE\\SOFTWARE\\IronPython", "ipy.exe");
+ private static Set<String> ourRegistryCache;
+
private WinPythonSdkFlavor() {
}
@@ -78,18 +80,25 @@ public class WinPythonSdkFlavor extends CPythonSdkFlavor {
}
public static void findInRegistry(Collection<String> candidates) {
- for (Map.Entry<String, String> entry : ourRegistryMap.entrySet()) {
- final String prefix = entry.getKey();
- final String exePath = entry.getValue();
- List<String> strings = WindowsRegistryUtil.readRegistryBranch(prefix);
- for (String string : strings) {
- final String path =
- WindowsRegistryUtil.readRegistryDefault(prefix + "\\" + string +
- "\\InstallPath");
- if (path != null) {
- File f = new File(path, exePath);
- if (f.exists()) {
- candidates.add(FileUtil.toSystemDependentName(f.getPath()));
+ fillRegistryCache();
+ candidates.addAll(ourRegistryCache);
+ }
+
+ private static void fillRegistryCache() {
+ if (ourRegistryCache == null) {
+ ourRegistryCache = new HashSet<String>();
+ for (Map.Entry<String, String> entry : ourRegistryMap.entrySet()) {
+ final String prefix = entry.getKey();
+ final String exePath = entry.getValue();
+ List<String> strings = WindowsRegistryUtil.readRegistryBranch(prefix);
+ for (String string : strings) {
+ final String path = WindowsRegistryUtil.readRegistryDefault(prefix + "\\" + string +
+ "\\InstallPath");
+ if (path != null) {
+ File f = new File(path, exePath);
+ if (f.exists()) {
+ ourRegistryCache.add(FileUtil.toSystemDependentName(f.getPath()));
+ }
}
}
}
diff --git a/python/src/com/jetbrains/python/sdk/skeletons/PySkeletonGenerator.java b/python/src/com/jetbrains/python/sdk/skeletons/PySkeletonGenerator.java
index 901472e6d2c3..7e099041e16a 100644
--- a/python/src/com/jetbrains/python/sdk/skeletons/PySkeletonGenerator.java
+++ b/python/src/com/jetbrains/python/sdk/skeletons/PySkeletonGenerator.java
@@ -15,6 +15,7 @@
*/
package com.jetbrains.python.sdk.skeletons;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.intellij.execution.process.ProcessOutput;
import com.intellij.openapi.application.ex.ApplicationManagerEx;
@@ -52,21 +53,12 @@ public class PySkeletonGenerator {
ENV_PATH_PARAM.put(IronPythonSdkFlavor.class, "IRONPYTHONPATH"); // TODO: Make strategy and move to PythonSdkFlavor?
}
-
protected static final Logger LOG = Logger.getInstance("#" + PySkeletonGenerator.class.getName());
-
-
protected static final int MINUTE = 60 * 1000;
-
protected static final String GENERATOR3 = "generator3.py";
- private static final String[] EMPTY_ENVS = new String[0];
private final String mySkeletonsPath;
- /**
- * Env variables to be added to skeleton generator
- */
- @NotNull
- private final String[] myEnvs;
+ @NotNull private final Map<String, String> myEnv;
public void finishSkeletonsGeneration() {
}
@@ -85,7 +77,6 @@ public class PySkeletonGenerator {
}
}
-
/**
* @param skeletonPath path where skeletons should be generated
* @param pySdk SDK
@@ -94,11 +85,11 @@ public class PySkeletonGenerator {
public PySkeletonGenerator(String skeletonPath, @NotNull final Sdk pySdk, @Nullable final String currentFolder) {
mySkeletonsPath = skeletonPath;
final PythonSdkFlavor flavor = PythonSdkFlavor.getFlavor(pySdk);
- if ((currentFolder != null) && (flavor != null) && ENV_PATH_PARAM.containsKey(flavor.getClass())) {
- myEnvs = new String[]{String.format("%s=%s", ENV_PATH_PARAM.get(flavor.getClass()), currentFolder)};
+ if (currentFolder != null && flavor != null && ENV_PATH_PARAM.containsKey(flavor.getClass())) {
+ myEnv = ImmutableMap.of(ENV_PATH_PARAM.get(flavor.getClass()), currentFolder);
}
else {
- myEnvs = EMPTY_ENVS;
+ myEnv = Collections.emptyMap();
}
}
@@ -171,23 +162,19 @@ public class PySkeletonGenerator {
if (modfilename != null) {
commandLine.add(modfilename);
}
- final List<String> envs = new ArrayList<String>(Arrays.asList(myEnvs));
- final String[] virtualEnvAdditionalEnv = PythonSdkType.getVirtualEnvAdditionalEnv(binaryPath);
- if (virtualEnvAdditionalEnv != null) {
- envs.addAll(Arrays.asList(virtualEnvAdditionalEnv));
- }
+ final Map<String, String> extraEnv = PythonSdkType.getVirtualEnvExtraEnv(binaryPath);
+ final Map<String, String> env = extraEnv != null ? PySdkUtil.mergeEnvVariables(myEnv, extraEnv) : myEnv;
- return getProcessOutput(parent_dir, ArrayUtil.toStringArray(commandLine), envs.toArray(new String[envs.size()]),
- MINUTE * 10
- );
+ return getProcessOutput(parent_dir, ArrayUtil.toStringArray(commandLine), env, MINUTE * 10);
}
- protected ProcessOutput getProcessOutput(String homePath, String[] commandLine, String[] env, int timeout) throws InvalidSdkException {
+ protected ProcessOutput getProcessOutput(String homePath, String[] commandLine, Map<String, String> extraEnv,
+ int timeout) throws InvalidSdkException {
return PySdkUtil.getProcessOutput(
homePath,
commandLine,
- env,
+ extraEnv,
timeout
);
}
@@ -207,7 +194,7 @@ public class PySkeletonGenerator {
"-d", mySkeletonsPath, // output dir
"-b", // for builtins
},
- PythonSdkType.getVirtualEnvAdditionalEnv(binaryPath), MINUTE * 5
+ PythonSdkType.getVirtualEnvExtraEnv(binaryPath), MINUTE * 5
);
runResult.checkSuccess(LOG);
LOG.info("Rebuilding builtin skeletons took " + (System.currentTimeMillis() - startTime) + " ms");
@@ -228,7 +215,7 @@ public class PySkeletonGenerator {
final ProcessOutput process = getProcessOutput(parentDir,
ArrayUtil.toStringArray(cmd),
- PythonSdkType.getVirtualEnvAdditionalEnv(homePath),
+ PythonSdkType.getVirtualEnvExtraEnv(homePath),
MINUTE * 4); // see PY-3898
LOG.info("Retrieving binary module list took " + (System.currentTimeMillis() - startTime) + " ms");
diff --git a/python/src/com/jetbrains/python/sdk/skeletons/PySkeletonRefresher.java b/python/src/com/jetbrains/python/sdk/skeletons/PySkeletonRefresher.java
index 4e4a43102202..b1e8ca19acf8 100644
--- a/python/src/com/jetbrains/python/sdk/skeletons/PySkeletonRefresher.java
+++ b/python/src/com/jetbrains/python/sdk/skeletons/PySkeletonRefresher.java
@@ -19,9 +19,6 @@ import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
import com.intellij.execution.ExecutionException;
-import com.intellij.notification.Notification;
-import com.intellij.notification.NotificationType;
-import com.intellij.notification.Notifications;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.diagnostic.Logger;
@@ -31,7 +28,6 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.util.Pair;
-import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
@@ -48,7 +44,6 @@ import com.jetbrains.python.PyNames;
import com.jetbrains.python.codeInsight.userSkeletons.PyUserSkeletonsUtil;
import com.jetbrains.python.packaging.PyExternalProcessException;
import com.jetbrains.python.packaging.PyPackageManager;
-import com.jetbrains.python.packaging.PyPackageManagerImpl;
import com.jetbrains.python.psi.resolve.PythonSdkPathCache;
import com.jetbrains.python.remote.PythonRemoteInterpreterManager;
import com.jetbrains.python.sdk.InvalidSdkException;
@@ -105,10 +100,6 @@ public class PySkeletonRefresher {
private PySkeletonGenerator mySkeletonsGenerator;
- public static void refreshSkeletonsOfSdk(@NotNull Project project, @NotNull Sdk sdk) throws InvalidSdkException {
- refreshSkeletonsOfSdk(project, null, PythonSdkType.findSkeletonsPath(sdk), new Ref<Boolean>(false), sdk);
- }
-
public static synchronized boolean isGeneratingSkeletons() {
return ourGeneratingCount > 0;
}
@@ -120,7 +111,6 @@ public class PySkeletonRefresher {
public static void refreshSkeletonsOfSdk(@Nullable Project project,
Component ownerComponent,
String skeletonsPath,
- @Nullable Ref<Boolean> migrationFlag,
@NotNull Sdk sdk)
throws InvalidSdkException {
final Map<String, List<String>> errors = new TreeMap<String, List<String>>();
@@ -137,7 +127,7 @@ public class PySkeletonRefresher {
changeGeneratingSkeletons(1);
try {
- List<String> sdkErrors = refresher.regenerateSkeletons(checker, migrationFlag);
+ List<String> sdkErrors = refresher.regenerateSkeletons(checker);
if (sdkErrors.size() > 0) {
String sdkName = sdk.getName();
List<String> knownErrors = errors.get(sdkName);
@@ -286,8 +276,7 @@ public class PySkeletonRefresher {
return mySkeletonsPath;
}
- public List<String> regenerateSkeletons(@Nullable SkeletonVersionChecker cachedChecker,
- @Nullable Ref<Boolean> migrationFlag) throws InvalidSdkException {
+ public List<String> regenerateSkeletons(@Nullable SkeletonVersionChecker cachedChecker) throws InvalidSdkException {
final List<String> errorList = new SmartList<String>();
final String homePath = mySdk.getHomePath();
final String skeletonsPath = getSkeletonsPath();
@@ -299,14 +288,13 @@ public class PySkeletonRefresher {
final String readablePath = FileUtil.getLocationRelativeToUserHome(homePath);
mySkeletonsGenerator.prepare();
-
myBlacklist = loadBlacklist();
indicate(PyBundle.message("sdk.gen.querying.$0", readablePath));
// get generator version and binary libs list in one go
- final PySkeletonGenerator.ListBinariesResult binaries =
- mySkeletonsGenerator.listBinaries(mySdk, calculateExtraSysPath(mySdk, getSkeletonsPath()));
+ final String extraSysPath = calculateExtraSysPath(mySdk, getSkeletonsPath());
+ final PySkeletonGenerator.ListBinariesResult binaries = mySkeletonsGenerator.listBinaries(mySdk, extraSysPath);
myGeneratorVersion = binaries.generatorVersion;
myPregeneratedSkeletons = findPregeneratedSkeletons();
@@ -325,77 +313,19 @@ public class PySkeletonRefresher {
final SkeletonHeader oldHeader = readSkeletonHeader(builtinsFile);
final boolean oldOrNonExisting = oldHeader == null || oldHeader.getVersion() == 0;
- if (migrationFlag != null && !migrationFlag.get() && oldOrNonExisting) {
- migrationFlag.set(true);
- Notifications.Bus.notify(
- new Notification(
- PythonSdkType.SKELETONS_TOPIC, PyBundle.message("sdk.gen.notify.converting.old.skels"),
- PyBundle.message("sdk.gen.notify.converting.text"),
- NotificationType.INFORMATION
- )
- );
- }
-
if (myPregeneratedSkeletons != null && oldOrNonExisting) {
- indicate("Unpacking pregenerated skeletons...");
- try {
- final VirtualFile jar = JarFileSystem.getInstance().getVirtualFileForJar(myPregeneratedSkeletons);
- if (jar != null) {
- ZipUtil.extract(new File(jar.getPath()),
- new File(getSkeletonsPath()), null);
- }
- }
- catch (IOException e) {
- LOG.info("Error unpacking pregenerated skeletons", e);
- }
+ unpackPreGeneratedSkeletons();
}
if (oldOrNonExisting) {
- final Sdk base = PythonSdkType.getInstance().getVirtualEnvBaseSdk(mySdk);
- if (base != null) {
- indicate("Copying base SDK skeletons for virtualenv...");
- final String baseSkeletonsPath = PythonSdkType.getSkeletonsPath(PathManager.getSystemPath(), base.getHomePath());
- final PySkeletonGenerator.ListBinariesResult baseBinaries =
- mySkeletonsGenerator.listBinaries(base, calculateExtraSysPath(base, baseSkeletonsPath));
- for (Map.Entry<String, PyBinaryItem> entry : binaries.modules.entrySet()) {
- final String module = entry.getKey();
- final PyBinaryItem binary = entry.getValue();
- final PyBinaryItem baseBinary = baseBinaries.modules.get(module);
- final File fromFile = getSkeleton(module, baseSkeletonsPath);
- if (baseBinaries.modules.containsKey(module) &&
- fromFile.exists() &&
- binary.length() == baseBinary.length()) { // Weak binary modules equality check
- final File toFile = fromFile.isDirectory() ?
- getPackageSkeleton(module, skeletonsPath) :
- getModuleSkeleton(module, skeletonsPath);
- try {
- FileUtil.copy(fromFile, toFile);
- }
- catch (IOException e) {
- LOG.info("Error copying base virtualenv SDK skeleton for " + module, e);
- }
- }
- }
- }
+ copyBaseSdkSkeletonsToVirtualEnv(skeletonsPath, binaries);
}
- final SkeletonHeader newHeader = readSkeletonHeader(builtinsFile);
- final boolean mustUpdateBuiltins = myPregeneratedSkeletons == null &&
- (newHeader == null || newHeader.getVersion() < myVersionChecker.getBuiltinVersion());
- if (mustUpdateBuiltins) {
- indicate(PyBundle.message("sdk.gen.updating.builtins.$0", readablePath));
- mySkeletonsGenerator.generateBuiltinSkeletons(mySdk);
- if (myProject != null) {
- PythonSdkPathCache.getInstance(myProject, mySdk).clearBuiltins();
- }
- }
+ final boolean builtinsUpdated = updateSkeletonsForBuiltins(readablePath, builtinsFile);
if (!binaries.modules.isEmpty()) {
-
indicate(PyBundle.message("sdk.gen.updating.$0", readablePath));
-
- List<UpdateResult> updateErrors = updateOrCreateSkeletons(binaries.modules); //Skeletons regeneration
-
+ final List<UpdateResult> updateErrors = updateOrCreateSkeletons(binaries.modules);
if (updateErrors.size() > 0) {
indicateMinor(BLACKLIST_FILE_NAME);
for (UpdateResult error : updateErrors) {
@@ -410,7 +340,6 @@ public class PySkeletonRefresher {
}
indicate(PyBundle.message("sdk.gen.reloading"));
-
mySkeletonsGenerator.refreshGeneratedSkeletons();
if (!oldOrNonExisting) {
@@ -419,14 +348,15 @@ public class PySkeletonRefresher {
}
if (PySdkUtil.isRemote(mySdk)) {
try {
- ((PyPackageManagerImpl)PyPackageManager.getInstance(mySdk)).loadPackages();
+ // Force loading packages
+ PyPackageManager.getInstance(mySdk).getPackages(false);
}
catch (PyExternalProcessException e) {
// ignore - already logged
}
}
- if ((mustUpdateBuiltins || PySdkUtil.isRemote(mySdk)) && myProject != null) {
+ if ((builtinsUpdated || PySdkUtil.isRemote(mySdk)) && myProject != null) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
@@ -438,6 +368,64 @@ public class PySkeletonRefresher {
return errorList;
}
+ private boolean updateSkeletonsForBuiltins(String readablePath, File builtinsFile) throws InvalidSdkException {
+ final SkeletonHeader newHeader = readSkeletonHeader(builtinsFile);
+ final boolean mustUpdateBuiltins = myPregeneratedSkeletons == null &&
+ (newHeader == null || newHeader.getVersion() < myVersionChecker.getBuiltinVersion());
+ if (mustUpdateBuiltins) {
+ indicate(PyBundle.message("sdk.gen.updating.builtins.$0", readablePath));
+ mySkeletonsGenerator.generateBuiltinSkeletons(mySdk);
+ if (myProject != null) {
+ PythonSdkPathCache.getInstance(myProject, mySdk).clearBuiltins();
+ }
+ }
+ return mustUpdateBuiltins;
+ }
+
+ private void copyBaseSdkSkeletonsToVirtualEnv(String skeletonsPath, PySkeletonGenerator.ListBinariesResult binaries)
+ throws InvalidSdkException {
+ final Sdk base = PythonSdkType.getInstance().getVirtualEnvBaseSdk(mySdk);
+ if (base != null) {
+ indicate("Copying base SDK skeletons for virtualenv...");
+ final String baseSkeletonsPath = PythonSdkType.getSkeletonsPath(PathManager.getSystemPath(), base.getHomePath());
+ final PySkeletonGenerator.ListBinariesResult baseBinaries =
+ mySkeletonsGenerator.listBinaries(base, calculateExtraSysPath(base, baseSkeletonsPath));
+ for (Map.Entry<String, PyBinaryItem> entry : binaries.modules.entrySet()) {
+ final String module = entry.getKey();
+ final PyBinaryItem binary = entry.getValue();
+ final PyBinaryItem baseBinary = baseBinaries.modules.get(module);
+ final File fromFile = getSkeleton(module, baseSkeletonsPath);
+ if (baseBinaries.modules.containsKey(module) &&
+ fromFile.exists() &&
+ binary.length() == baseBinary.length()) { // Weak binary modules equality check
+ final File toFile = fromFile.isDirectory() ?
+ getPackageSkeleton(module, skeletonsPath) :
+ getModuleSkeleton(module, skeletonsPath);
+ try {
+ FileUtil.copy(fromFile, toFile);
+ }
+ catch (IOException e) {
+ LOG.info("Error copying base virtualenv SDK skeleton for " + module, e);
+ }
+ }
+ }
+ }
+ }
+
+ private void unpackPreGeneratedSkeletons() throws InvalidSdkException {
+ indicate("Unpacking pregenerated skeletons...");
+ try {
+ final VirtualFile jar = JarFileSystem.getInstance().getVirtualFileForJar(myPregeneratedSkeletons);
+ if (jar != null) {
+ ZipUtil.extract(new File(jar.getPath()),
+ new File(getSkeletonsPath()), null);
+ }
+ }
+ catch (IOException e) {
+ LOG.info("Error unpacking pregenerated skeletons", e);
+ }
+ }
+
@Nullable
public static SkeletonHeader readSkeletonHeader(@NotNull File file) {
try {
@@ -835,7 +823,7 @@ public class PySkeletonRefresher {
return null;
}
LOG.info("Pregenerated skeletons root is " + root);
- final String versionString = mySdk.getVersionString();
+ @NonNls final String versionString = mySdk.getVersionString();
if (versionString == null) {
return null;
}
diff --git a/python/src/com/jetbrains/python/statistics/PyPackageUsagesCollector.java b/python/src/com/jetbrains/python/statistics/PyPackageUsagesCollector.java
index f8b4adde5b33..8e029e042aa0 100644
--- a/python/src/com/jetbrains/python/statistics/PyPackageUsagesCollector.java
+++ b/python/src/com/jetbrains/python/statistics/PyPackageUsagesCollector.java
@@ -25,7 +25,7 @@ import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.jetbrains.python.packaging.PyPIPackageUtil;
-import com.jetbrains.python.packaging.PyPackageManagerImpl;
+import com.jetbrains.python.packaging.PyPackageManager;
import com.jetbrains.python.packaging.PyRequirement;
import com.jetbrains.python.sdk.PythonSdkType;
import org.jetbrains.annotations.NotNull;
@@ -46,12 +46,12 @@ public class PyPackageUsagesCollector extends AbstractApplicationUsagesCollector
public Set<UsageDescriptor> getProjectUsages(@NotNull Project project) throws CollectUsagesException {
final Set<UsageDescriptor> result = new HashSet<UsageDescriptor>();
for(final Module m: ModuleManager.getInstance(project).getModules()) {
- Sdk pythonSdk = PythonSdkType.findPythonSdk(m);
+ final Sdk pythonSdk = PythonSdkType.findPythonSdk(m);
if (pythonSdk != null) {
ApplicationManager.getApplication().runReadAction(new Runnable() {
@Override
public void run() {
- List<PyRequirement> requirements = PyPackageManagerImpl.getRequirements(m);
+ List<PyRequirement> requirements = PyPackageManager.getInstance(pythonSdk).getRequirements(m);
if (requirements != null) {
Collection<String> packages = new HashSet<String>(PyPIPackageUtil.INSTANCE.getPackageNames());
for (PyRequirement requirement : requirements) {
diff --git a/python/src/com/jetbrains/python/structureView/PyStructureViewElement.java b/python/src/com/jetbrains/python/structureView/PyStructureViewElement.java
index 93c44f7f2a17..de9f7bf5a5ca 100644
--- a/python/src/com/jetbrains/python/structureView/PyStructureViewElement.java
+++ b/python/src/com/jetbrains/python/structureView/PyStructureViewElement.java
@@ -23,7 +23,6 @@ import com.intellij.openapi.editor.colors.TextAttributesKey;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.ui.LayeredIcon;
-import com.intellij.util.Function;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.psi.*;
import icons.PythonIcons;
@@ -33,9 +32,6 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.*;
-import static com.intellij.openapi.util.text.StringUtil.join;
-import static com.intellij.openapi.util.text.StringUtil.notNullize;
-
/**
* Handles nodes in Structure View.
* @author yole
@@ -237,32 +233,15 @@ public class PyStructureViewElement implements StructureViewTreeElement {
@NotNull
@Override
public ItemPresentation getPresentation() {
+ final ItemPresentation presentation = myElement.getPresentation();
return new ColoredItemPresentation() {
+ @Nullable
+ @Override
public String getPresentableText() {
- final String unnamed = "<unnamed>";
- if (myElement instanceof PyFunction) {
- PyParameterList argList = ((PyFunction) myElement).getParameterList();
- StringBuilder result = new StringBuilder(notNullize(myElement.getName(), unnamed));
- result.append(argList.getPresentableText(true));
- return result.toString();
- }
- else if (myElement instanceof PyClass && myElement.isValid()) {
- PyClass c = (PyClass) myElement;
- StringBuilder result = new StringBuilder(notNullize(c.getName(), unnamed));
- PyExpression[] superClassExpressions = c.getSuperClassExpressions();
- if (superClassExpressions.length > 0) {
- result.append("(");
- result.append(join(Arrays.asList(superClassExpressions), new Function<PyExpression, String>() {
- public String fun(PyExpression expr) {
- String name = expr.getText();
- return notNullize(name, unnamed);
- }
- }, ", "));
- result.append(")");
- }
- return result.toString();
+ if (myElement instanceof PyFile) {
+ return myElement.getName();
}
- return notNullize(myElement.getName(), unnamed);
+ return presentation != null ? presentation.getPresentableText() : PyNames.UNNAMED_ELEMENT;
}
@Nullable
diff --git a/python/src/com/jetbrains/python/testing/PyRerunFailedTestsAction.java b/python/src/com/jetbrains/python/testing/PyRerunFailedTestsAction.java
index 0b922514e52e..01c8ac68540c 100644
--- a/python/src/com/jetbrains/python/testing/PyRerunFailedTestsAction.java
+++ b/python/src/com/jetbrains/python/testing/PyRerunFailedTestsAction.java
@@ -28,33 +28,29 @@ import com.intellij.execution.testframework.actions.AbstractRerunFailedTestsActi
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.ComponentContainer;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.search.GlobalSearchScope;
import com.jetbrains.python.run.AbstractPythonRunConfiguration;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
-/*
- * User: ktisha
- */
public class PyRerunFailedTestsAction extends AbstractRerunFailedTestsAction {
-
protected PyRerunFailedTestsAction(@NotNull ComponentContainer componentContainer) {
super(componentContainer);
}
@Override
@Nullable
- public MyRunProfile getRunProfile() {
+ protected MyRunProfile getRunProfile(@NotNull ExecutionEnvironment environment) {
final TestFrameworkRunningModel model = getModel();
- if (model == null) return null;
- final AbstractPythonRunConfiguration configuration = (AbstractPythonRunConfiguration)model.getProperties().getConfiguration();
- return new MyTestRunProfile(configuration);
+ if (model == null) {
+ return null;
+ }
+ return new MyTestRunProfile((AbstractPythonRunConfiguration)model.getProperties().getConfiguration());
}
-
private class MyTestRunProfile extends MyRunProfile {
public MyTestRunProfile(RunConfigurationBase configuration) {
@@ -71,6 +67,19 @@ public class PyRerunFailedTestsAction extends AbstractRerunFailedTestsAction {
@Override
public RunProfileState getState(@NotNull Executor executor, @NotNull ExecutionEnvironment env) throws ExecutionException {
final AbstractPythonRunConfiguration configuration = ((AbstractPythonRunConfiguration)getPeer());
+
+ // If configuration wants to take care about rerun itself
+ if (configuration instanceof TestRunConfigurationReRunResponsible) {
+ // TODO: Extract method
+ final Set<PsiElement> failedTestElements = new HashSet<PsiElement>();
+ for (final AbstractTestProxy proxy : getFailedTests(getProject())) {
+ final Location<?> location = proxy.getLocation(getProject(), GlobalSearchScope.allScope(getProject()));
+ if (location != null) {
+ failedTestElements.add(location.getPsiElement());
+ }
+ }
+ return ((TestRunConfigurationReRunResponsible)configuration).rerunTests(executor, env, failedTestElements);
+ }
return new FailedPythonTestCommandLineStateBase(configuration, env,
(PythonTestCommandLineStateBase)configuration.getState(executor, env));
}
diff --git a/python/src/com/jetbrains/python/testing/PythonTestCommandLineStateBase.java b/python/src/com/jetbrains/python/testing/PythonTestCommandLineStateBase.java
index 1a5aafe59051..c73a488dc7f5 100644
--- a/python/src/com/jetbrains/python/testing/PythonTestCommandLineStateBase.java
+++ b/python/src/com/jetbrains/python/testing/PythonTestCommandLineStateBase.java
@@ -63,6 +63,7 @@ public abstract class PythonTestCommandLineStateBase extends PythonCommandLineSt
myConfiguration = configuration;
}
+ @Override
@NotNull
protected ConsoleView createAndAttachConsole(Project project, ProcessHandler processHandler, Executor executor)
throws ExecutionException {
@@ -89,6 +90,7 @@ public abstract class PythonTestCommandLineStateBase extends PythonCommandLineSt
return new PythonTRunnerConsoleProperties(myConfiguration, executor, false);
}
+ @Override
public GeneralCommandLine generateCommandLine() throws ExecutionException {
GeneralCommandLine cmd = super.generateCommandLine();
@@ -135,7 +137,7 @@ public abstract class PythonTestCommandLineStateBase extends PythonCommandLineSt
PyRerunFailedTestsAction rerunFailedTestsAction = new PyRerunFailedTestsAction(console);
if (console instanceof SMTRunnerConsoleView) {
- rerunFailedTestsAction.init(((BaseTestsOutputConsoleView)console).getProperties(), getEnvironment());
+ rerunFailedTestsAction.init(((BaseTestsOutputConsoleView)console).getProperties());
rerunFailedTestsAction.setModelProvider(new Getter<TestFrameworkRunningModel>() {
@Override
public TestFrameworkRunningModel get() {
diff --git a/python/src/com/jetbrains/python/testing/TestRunConfigurationReRunResponsible.java b/python/src/com/jetbrains/python/testing/TestRunConfigurationReRunResponsible.java
new file mode 100644
index 000000000000..a8e9e1f8d5e4
--- /dev/null
+++ b/python/src/com/jetbrains/python/testing/TestRunConfigurationReRunResponsible.java
@@ -0,0 +1,30 @@
+package com.jetbrains.python.testing;
+
+import com.intellij.execution.ExecutionException;
+import com.intellij.execution.Executor;
+import com.intellij.execution.configurations.RunProfileState;
+import com.intellij.execution.runners.ExecutionEnvironment;
+import com.intellij.psi.PsiElement;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Collection;
+
+/**
+ * Configuration that handles rerun failed tests itself.
+ *
+ * @author Ilya.Kazakevich
+ */
+public interface TestRunConfigurationReRunResponsible {
+ /**
+ * Rerun failed tests
+ * @param executor test executor
+ * @param environment test environment
+ * @param failedTests a pack of psi elements, indicating failed tests (to retrn)
+ * @return state to run or null if no rerun actions found (i.e. no errors in failedTest, empty etc)
+ * @throws ExecutionException failed to run
+ */
+ @Nullable
+ RunProfileState rerunTests(@NotNull final Executor executor, @NotNull final ExecutionEnvironment environment,
+ @NotNull Collection<PsiElement> failedTests) throws ExecutionException;
+}
diff --git a/python/src/com/jetbrains/python/testing/VFSTestFrameworkListener.java b/python/src/com/jetbrains/python/testing/VFSTestFrameworkListener.java
index 9d763e2ce286..64adf2093028 100644
--- a/python/src/com/jetbrains/python/testing/VFSTestFrameworkListener.java
+++ b/python/src/com/jetbrains/python/testing/VFSTestFrameworkListener.java
@@ -35,7 +35,6 @@ import com.intellij.util.ui.update.Update;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.packaging.PyExternalProcessException;
import com.jetbrains.python.packaging.PyPackageManager;
-import com.jetbrains.python.packaging.PyPackageManagerImpl;
import com.jetbrains.python.sdk.PySdkUtil;
import com.jetbrains.python.sdk.PythonSdkType;
import org.jetbrains.annotations.NotNull;
@@ -131,9 +130,9 @@ public class VFSTestFrameworkListener implements ApplicationComponent {
LOG.info("Searching test runner in empty sdk");
return null;
}
- final PyPackageManagerImpl packageManager = (PyPackageManagerImpl)PyPackageManager.getInstance(sdk);
+ final PyPackageManager packageManager = PyPackageManager.getInstance(sdk);
try {
- return packageManager.findInstalledPackage(testPackageName) != null;
+ return packageManager.findPackage(testPackageName, false) != null;
}
catch (PyExternalProcessException e) {
LOG.info("Can't load package list " + e.getMessage());
diff --git a/python/src/com/jetbrains/python/testing/pytest/PyTestConfigurationProducer.java b/python/src/com/jetbrains/python/testing/pytest/PyTestConfigurationProducer.java
index f988dbd315e6..8dc27d4fd995 100644
--- a/python/src/com/jetbrains/python/testing/pytest/PyTestConfigurationProducer.java
+++ b/python/src/com/jetbrains/python/testing/pytest/PyTestConfigurationProducer.java
@@ -31,7 +31,6 @@ import com.intellij.webcore.packaging.PackageVersionComparator;
import com.jetbrains.python.packaging.PyExternalProcessException;
import com.jetbrains.python.packaging.PyPackage;
import com.jetbrains.python.packaging.PyPackageManager;
-import com.jetbrains.python.packaging.PyPackageManagerImpl;
import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.PyFile;
import com.jetbrains.python.psi.PyFunction;
@@ -97,9 +96,9 @@ public class PyTestConfigurationProducer extends PythonTestConfigurationProducer
if (pyFunction != null) {
keywords = pyFunction.getName();
if (pyClass != null) {
- final PyPackageManagerImpl packageManager = (PyPackageManagerImpl)PyPackageManager.getInstance(sdk);
+ final PyPackageManager packageManager = PyPackageManager.getInstance(sdk);
try {
- final PyPackage pytestPackage = packageManager.findInstalledPackage("pytest");
+ final PyPackage pytestPackage = packageManager.findPackage("pytest", false);
if (pytestPackage != null && PackageVersionComparator.VERSION_COMPARATOR.compare(pytestPackage.getVersion(), "2.3.3") >= 0) {
keywords = pyClass.getName() + " and " + keywords;
}
diff --git a/python/src/com/jetbrains/python/validation/Pep8ExternalAnnotator.java b/python/src/com/jetbrains/python/validation/Pep8ExternalAnnotator.java
index a7faa6ebb98f..22bb1d308d2c 100644
--- a/python/src/com/jetbrains/python/validation/Pep8ExternalAnnotator.java
+++ b/python/src/com/jetbrains/python/validation/Pep8ExternalAnnotator.java
@@ -15,6 +15,7 @@
*/
package com.jetbrains.python.validation;
+import com.google.common.collect.ImmutableMap;
import com.intellij.codeHighlighting.HighlightDisplayLevel;
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
import com.intellij.codeInsight.intention.IntentionAction;
@@ -173,7 +174,7 @@ public class Pep8ExternalAnnotator extends ExternalAnnotator<Pep8ExternalAnnotat
options.add("-");
ProcessOutput output = PySdkUtil.getProcessOutput(new File(collectedInfo.interpreterPath).getParent(),
ArrayUtil.toStringArray(options),
- new String[] { "PYTHONUNBUFFERED=1" },
+ ImmutableMap.of("PYTHONBUFFERED", "1"),
10000,
collectedInfo.fileText.getBytes(), false);
diff --git a/python/src/com/jetbrains/python/validation/StringLiteralQuotesAnnotator.java b/python/src/com/jetbrains/python/validation/StringLiteralQuotesAnnotator.java
index 0666e8319caa..997123351d36 100644
--- a/python/src/com/jetbrains/python/validation/StringLiteralQuotesAnnotator.java
+++ b/python/src/com/jetbrains/python/validation/StringLiteralQuotesAnnotator.java
@@ -18,8 +18,10 @@ package com.jetbrains.python.validation;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
+import com.jetbrains.python.PyBundle;
import com.jetbrains.python.psi.PyStringLiteralExpression;
import com.jetbrains.python.psi.impl.PyStringLiteralExpressionImpl;
+import org.jetbrains.annotations.NotNull;
import java.util.List;
@@ -29,17 +31,16 @@ import java.util.List;
* @author dcheryasov
*/
public class StringLiteralQuotesAnnotator extends PyAnnotator {
- public static final String MISSING_Q = "Missing closing quote";
private static final String TRIPLE_QUOTES = "\"\"\"";
private static final String TRIPLE_APOS = "'''";
public void visitPyStringLiteralExpression(final PyStringLiteralExpression node) {
- List<ASTNode> stringNodes = node.getStringNodes();
+ final List<ASTNode> stringNodes = node.getStringNodes();
for (ASTNode stringNode : stringNodes) {
- boolean foundError;
- String nodeText = stringNode.getText();
- int index = PyStringLiteralExpressionImpl.getPrefixLength(nodeText);
- String unprefixed = nodeText.substring(index);
+ final String nodeText = stringNode.getText();
+ final int index = PyStringLiteralExpressionImpl.getPrefixLength(nodeText);
+ final String unprefixed = nodeText.substring(index);
+ final boolean foundError;
if (StringUtil.startsWith(unprefixed, TRIPLE_QUOTES)) {
foundError = checkTripleQuotedString(stringNode, unprefixed, TRIPLE_QUOTES);
}
@@ -49,23 +50,33 @@ public class StringLiteralQuotesAnnotator extends PyAnnotator {
else {
foundError = checkQuotedString(stringNode, unprefixed);
}
- if (foundError) break;
+ if (foundError) {
+ break;
+ }
}
}
- private boolean checkQuotedString(ASTNode stringNode, String nodeText) {
- char firstQuote = nodeText.charAt(0);
- int lastChar = nodeText.length()-1;
- if (lastChar == 0 || nodeText.charAt(lastChar) != firstQuote ||
- (nodeText.charAt(lastChar-1) == '\\' && (lastChar == 1 || nodeText.charAt(lastChar-2) != '\\'))) {
- getHolder().createErrorAnnotation(stringNode, MISSING_Q + " [" + firstQuote + "]");
+ private boolean checkQuotedString(@NotNull ASTNode stringNode, @NotNull String nodeText) {
+ final char firstQuote = nodeText.charAt(0);
+ final char lastChar = nodeText.charAt(nodeText.length() - 1);
+ int precedingBackslashCount = 0;
+ for (int i = nodeText.length() - 2; i >= 0; i--) {
+ if (nodeText.charAt(i) == '\\') {
+ precedingBackslashCount++;
+ }
+ else {
+ break;
+ }
+ }
+ if (nodeText.length() == 1 || lastChar != firstQuote || precedingBackslashCount % 2 != 0) {
+ getHolder().createErrorAnnotation(stringNode, PyBundle.message("ANN.missing.closing.quote", firstQuote));
return true;
}
return false;
}
- private boolean checkTripleQuotedString(ASTNode stringNode, String text, final String quotes) {
- if (text.length() < 6 || !text.endsWith(quotes)) {
+ private boolean checkTripleQuotedString(@NotNull ASTNode stringNode, @NotNull String text, @NotNull String quotes) {
+ if (text.length() < 6 || !text.endsWith(quotes)) {
int startOffset = StringUtil.trimTrailing(stringNode.getText()).lastIndexOf('\n');
if (startOffset < 0) {
startOffset = stringNode.getTextRange().getStartOffset();
@@ -73,8 +84,8 @@ public class StringLiteralQuotesAnnotator extends PyAnnotator {
else {
startOffset = stringNode.getTextRange().getStartOffset() + startOffset + 1;
}
- TextRange highlightRange = new TextRange(startOffset, stringNode.getTextRange().getEndOffset());
- getHolder().createErrorAnnotation(highlightRange, "Missing closing triple quotes");
+ final TextRange highlightRange = new TextRange(startOffset, stringNode.getTextRange().getEndOffset());
+ getHolder().createErrorAnnotation(highlightRange, PyBundle.message("ANN.missing.closing.triple.quotes"));
return true;
}
return false;
diff --git a/python/testData/codeInsight/smartEnter/withOnlyColonMissing.py b/python/testData/codeInsight/smartEnter/withOnlyColonMissing.py
new file mode 100644
index 000000000000..7fc16ea3bb68
--- /dev/null
+++ b/python/testData/codeInsight/smartEnter/withOnlyColonMissing.py
@@ -0,0 +1 @@
+with open('file.txt') as f<caret> \ No newline at end of file
diff --git a/python/testData/codeInsight/smartEnter/withOnlyColonMissing_after.py b/python/testData/codeInsight/smartEnter/withOnlyColonMissing_after.py
new file mode 100644
index 000000000000..09a090ef65d3
--- /dev/null
+++ b/python/testData/codeInsight/smartEnter/withOnlyColonMissing_after.py
@@ -0,0 +1,2 @@
+with open('file.txt') as f:
+ <caret> \ No newline at end of file
diff --git a/python/testData/hierarchy/call/Static/ArgumentList/ArgumentList_callee_verification.xml b/python/testData/hierarchy/call/Static/ArgumentList/ArgumentList_callee_verification.xml
new file mode 100644
index 000000000000..28d3684cdb10
--- /dev/null
+++ b/python/testData/hierarchy/call/Static/ArgumentList/ArgumentList_callee_verification.xml
@@ -0,0 +1 @@
+<node text="target_func() (hierarchy.call.Static.ArgumentList.file_1)" base="true"/> \ No newline at end of file
diff --git a/python/testData/hierarchy/call/Static/ArgumentList/ArgumentList_caller_verification.xml b/python/testData/hierarchy/call/Static/ArgumentList/ArgumentList_caller_verification.xml
new file mode 100644
index 000000000000..28d3684cdb10
--- /dev/null
+++ b/python/testData/hierarchy/call/Static/ArgumentList/ArgumentList_caller_verification.xml
@@ -0,0 +1 @@
+<node text="target_func() (hierarchy.call.Static.ArgumentList.file_1)" base="true"/> \ No newline at end of file
diff --git a/python/testData/hierarchy/call/Static/ArgumentList/file_1.py b/python/testData/hierarchy/call/Static/ArgumentList/file_1.py
new file mode 100644
index 000000000000..ea497204d2ca
--- /dev/null
+++ b/python/testData/hierarchy/call/Static/ArgumentList/file_1.py
@@ -0,0 +1,8 @@
+def target_func():
+ pass
+
+def func1(f):
+ f()
+
+def func2(f):
+ return f \ No newline at end of file
diff --git a/python/testData/hierarchy/call/Static/ArgumentList/main.py b/python/testData/hierarchy/call/Static/ArgumentList/main.py
new file mode 100644
index 000000000000..b479ea6f9d3a
--- /dev/null
+++ b/python/testData/hierarchy/call/Static/ArgumentList/main.py
@@ -0,0 +1,8 @@
+from file_1 import *
+
+target_<caret>func()
+func1(target_func)
+func1(target_func())
+func2(target_func)
+func2(target_func())
+
diff --git a/python/testData/hierarchy/call/Static/Constructor/Constructor_callee_verification.xml b/python/testData/hierarchy/call/Static/Constructor/Constructor_callee_verification.xml
new file mode 100644
index 000000000000..1b720a99aee9
--- /dev/null
+++ b/python/testData/hierarchy/call/Static/Constructor/Constructor_callee_verification.xml
@@ -0,0 +1,8 @@
+<node text="A.__init__(self) (hierarchy.call.Static.Constructor.main)" base="true">
+ <node text="invoke1(p) (hierarchy.call.Static.Constructor.main)">
+ <node text="A.method1(self) (hierarchy.call.Static.Constructor.main)"/>
+ </node>
+ <node text="invoke2(p) (hierarchy.call.Static.Constructor.main)">
+ <node text="A.method2(self) (hierarchy.call.Static.Constructor.main)"/>
+ </node>
+</node> \ No newline at end of file
diff --git a/python/testData/hierarchy/call/Static/Constructor/Constructor_caller_verification.xml b/python/testData/hierarchy/call/Static/Constructor/Constructor_caller_verification.xml
new file mode 100644
index 000000000000..b872e20e6c7b
--- /dev/null
+++ b/python/testData/hierarchy/call/Static/Constructor/Constructor_caller_verification.xml
@@ -0,0 +1,6 @@
+<node text="A.__init__(self) (hierarchy.call.Static.Constructor.main)" base="true">
+ <node text="invokeA() (hierarchy.call.Static.Constructor.main)">
+ <node text="C.bar(self) (hierarchy.call.Static.Constructor.main)"/>
+ </node>
+ <node text="C.bar(self) (hierarchy.call.Static.Constructor.main)"/>
+</node> \ No newline at end of file
diff --git a/python/testData/hierarchy/call/Static/Constructor/main.py b/python/testData/hierarchy/call/Static/Constructor/main.py
new file mode 100644
index 000000000000..1c2e14776c25
--- /dev/null
+++ b/python/testData/hierarchy/call/Static/Constructor/main.py
@@ -0,0 +1,32 @@
+class A():
+ def __init__(self):
+ invoke1(self)
+ invoke2(self)
+
+ def method1(self):
+ pass
+
+ def method2(self):
+ pass
+
+def invoke1(p):
+ p.method1()
+
+
+def invoke2(p):
+ p.method2()
+
+
+def invokeA():
+ a = A()
+ a.method1()
+ a.method2()
+
+ def new_class_func():
+ class C():
+ def bar(self):
+ invokeA(A())
+ return C()
+
+a = A()
+A.__init_<caret>_(a) \ No newline at end of file
diff --git a/python/testData/hierarchy/call/Static/DefaultValue/DefaultValue_callee_verification.xml b/python/testData/hierarchy/call/Static/DefaultValue/DefaultValue_callee_verification.xml
new file mode 100644
index 000000000000..23fc966f8913
--- /dev/null
+++ b/python/testData/hierarchy/call/Static/DefaultValue/DefaultValue_callee_verification.xml
@@ -0,0 +1 @@
+<node text="target_func() (hierarchy.call.Static.DefaultValue.main)" base="true"/> \ No newline at end of file
diff --git a/python/testData/hierarchy/call/Static/DefaultValue/DefaultValue_caller_verification.xml b/python/testData/hierarchy/call/Static/DefaultValue/DefaultValue_caller_verification.xml
new file mode 100644
index 000000000000..2cb93be11635
--- /dev/null
+++ b/python/testData/hierarchy/call/Static/DefaultValue/DefaultValue_caller_verification.xml
@@ -0,0 +1,4 @@
+<node text="target_func() (hierarchy.call.Static.DefaultValue.main)" base="true">
+ <node text="func2() (hierarchy.call.Static.DefaultValue.main)"/>
+ <node text="func4() (hierarchy.call.Static.DefaultValue.main)"/>
+</node> \ No newline at end of file
diff --git a/python/testData/hierarchy/call/Static/DefaultValue/main.py b/python/testData/hierarchy/call/Static/DefaultValue/main.py
new file mode 100644
index 000000000000..223642493ef4
--- /dev/null
+++ b/python/testData/hierarchy/call/Static/DefaultValue/main.py
@@ -0,0 +1,30 @@
+def target_func():
+ pass
+
+
+def func1():
+ def inner_func1(x=target_func):
+ pass
+
+ return inner_func1(target_func)
+
+
+def func2():
+ def inner_func2(x=target_func()):
+ pass
+
+ return inner_func2(target_func)
+
+
+def func3(x=target_func()):
+ pass
+
+
+def func4():
+ def inner_func4(x=target_func):
+ pass
+
+ return inner_func4(target_func())
+
+
+target_<caret>func() \ No newline at end of file
diff --git a/python/testData/hierarchy/call/Static/Inheritance/Inheritance_callee_verification.xml b/python/testData/hierarchy/call/Static/Inheritance/Inheritance_callee_verification.xml
new file mode 100644
index 000000000000..cf65c63a4d04
--- /dev/null
+++ b/python/testData/hierarchy/call/Static/Inheritance/Inheritance_callee_verification.xml
@@ -0,0 +1 @@
+<node text="A.target_func(self) (hierarchy.call.Static.Inheritance.main)" base="true"/> \ No newline at end of file
diff --git a/python/testData/hierarchy/call/Static/Inheritance/Inheritance_caller_verification.xml b/python/testData/hierarchy/call/Static/Inheritance/Inheritance_caller_verification.xml
new file mode 100644
index 000000000000..a81d537dcc27
--- /dev/null
+++ b/python/testData/hierarchy/call/Static/Inheritance/Inheritance_caller_verification.xml
@@ -0,0 +1,4 @@
+<node text="A.target_func(self) (hierarchy.call.Static.Inheritance.main)" base="true">
+ <node text="C.func(self, a) (hierarchy.call.Static.Inheritance.main)"/>
+ <node text="foo2(b) (hierarchy.call.Static.Inheritance.main)"/>
+</node> \ No newline at end of file
diff --git a/python/testData/hierarchy/call/Static/Inheritance/main.py b/python/testData/hierarchy/call/Static/Inheritance/main.py
new file mode 100644
index 000000000000..89c37de9bceb
--- /dev/null
+++ b/python/testData/hierarchy/call/Static/Inheritance/main.py
@@ -0,0 +1,36 @@
+
+class A(object):
+ def target_func(self):
+ pass
+
+
+class B(A):
+ pass
+
+
+class C(object):
+ def func(self, a):
+ a.target_func()
+
+
+def foo1(b):
+ f = b.target_func
+
+
+def foo2(b):
+ b.target_func()
+
+
+def bar1(*args):
+ pass
+
+
+def bar2(*args):
+ pass
+
+
+b = B()
+foo1(b)
+foo2(b)
+bar1(b.target_<caret>func)
+bar2(b.target_func()) \ No newline at end of file
diff --git a/python/testData/hierarchy/call/Static/InnerFunction/InnerFunction_callee_verification.xml b/python/testData/hierarchy/call/Static/InnerFunction/InnerFunction_callee_verification.xml
new file mode 100644
index 000000000000..551a5bd0fdf0
--- /dev/null
+++ b/python/testData/hierarchy/call/Static/InnerFunction/InnerFunction_callee_verification.xml
@@ -0,0 +1,5 @@
+<node text="target_func() (hierarchy.call.Static.InnerFunction.main)" base="true">
+ <node text="foo() (hierarchy.call.Static.InnerFunction.main)">
+ <node text="bar() (hierarchy.call.Static.InnerFunction.main)"/>
+ </node>
+</node> \ No newline at end of file
diff --git a/python/testData/hierarchy/call/Static/InnerFunction/InnerFunction_caller_verification.xml b/python/testData/hierarchy/call/Static/InnerFunction/InnerFunction_caller_verification.xml
new file mode 100644
index 000000000000..f01b7f50e287
--- /dev/null
+++ b/python/testData/hierarchy/call/Static/InnerFunction/InnerFunction_caller_verification.xml
@@ -0,0 +1 @@
+<node text="target_func() (hierarchy.call.Static.InnerFunction.main)" base="true"/> \ No newline at end of file
diff --git a/python/testData/hierarchy/call/Static/InnerFunction/main.py b/python/testData/hierarchy/call/Static/InnerFunction/main.py
new file mode 100644
index 000000000000..7ffc14aaf745
--- /dev/null
+++ b/python/testData/hierarchy/call/Static/InnerFunction/main.py
@@ -0,0 +1,9 @@
+def bar():
+ pass
+
+def target_func():
+ def foo():
+ return bar()
+ foo()
+
+target_<caret>func() \ No newline at end of file
diff --git a/python/testData/hierarchy/call/Static/Lambda/Lambda_callee_verification.xml b/python/testData/hierarchy/call/Static/Lambda/Lambda_callee_verification.xml
new file mode 100644
index 000000000000..c1b05951f7d4
--- /dev/null
+++ b/python/testData/hierarchy/call/Static/Lambda/Lambda_callee_verification.xml
@@ -0,0 +1,8 @@
+<node text="target_func(x=func1, y=func2(), z=lambda: func3, w=lambda: func4()) (hierarchy.call.Static.Lambda.main)" base="true">
+ <node text="func8() (hierarchy.call.Static.Lambda.file_1)"/>
+ <node text="func13() (hierarchy.call.Static.Lambda.file_1)"/>
+ <node text="func15() (hierarchy.call.Static.Lambda.file_1)"/>
+ <node text="inner(ix=func7, iy=func8(), iz=lambda: func9, iw=lambda: func10()) (hierarchy.call.Static.Lambda.main)">
+ <node text="func11() (hierarchy.call.Static.Lambda.file_1)"/>
+ </node>
+</node> \ No newline at end of file
diff --git a/python/testData/hierarchy/call/Static/Lambda/Lambda_caller_verification.xml b/python/testData/hierarchy/call/Static/Lambda/Lambda_caller_verification.xml
new file mode 100644
index 000000000000..d54b9674b47d
--- /dev/null
+++ b/python/testData/hierarchy/call/Static/Lambda/Lambda_caller_verification.xml
@@ -0,0 +1 @@
+<node text="target_func(x=func1, y=func2(), z=lambda: func3, w=lambda: func4()) (hierarchy.call.Static.Lambda.main)" base="true"/> \ No newline at end of file
diff --git a/python/testData/hierarchy/call/Static/Lambda/file_1.py b/python/testData/hierarchy/call/Static/Lambda/file_1.py
new file mode 100644
index 000000000000..bf1185212963
--- /dev/null
+++ b/python/testData/hierarchy/call/Static/Lambda/file_1.py
@@ -0,0 +1,18 @@
+def func1(): pass
+def func2(): pass
+def func3(): pass
+def func4(): pass
+def func5(): pass
+def func6(): pass
+def func7(): pass
+def func8(): pass
+def func9(): pass
+def func10(): pass
+def func11(): pass
+def func12(): pass
+def func13(): pass
+def func14(): pass
+def func15(): pass
+def func16(): pass
+def func17(): pass
+def func18(): pass
diff --git a/python/testData/hierarchy/call/Static/Lambda/main.py b/python/testData/hierarchy/call/Static/Lambda/main.py
new file mode 100644
index 000000000000..7dab14e27566
--- /dev/null
+++ b/python/testData/hierarchy/call/Static/Lambda/main.py
@@ -0,0 +1,18 @@
+from file_1 import *
+
+
+def target_func(x=func1, y=func2(), z=lambda: func3, w=lambda: func4()):
+ p1 = lambda: func5()
+ p2 = lambda: func6
+ p1(), p2()
+ def inner(ix=func7, iy=func8(), iz=lambda: func9, iw=lambda: func10()):
+ func11()
+ ip = lambda: func12()
+ ip()
+ func13()
+ inner(func14, func15(), lambda: func16, lambda: func17())
+
+ return func18
+
+
+target_<caret>func() \ No newline at end of file
diff --git a/python/testData/hierarchy/call/Static/NestedCall/NestedCall_callee_verification.xml b/python/testData/hierarchy/call/Static/NestedCall/NestedCall_callee_verification.xml
new file mode 100644
index 000000000000..4e1813bf0bd7
--- /dev/null
+++ b/python/testData/hierarchy/call/Static/NestedCall/NestedCall_callee_verification.xml
@@ -0,0 +1,12 @@
+<node text="target_func() (hierarchy.call.Static.NestedCall.main)" base="true">
+ <node text="func5(*args) (hierarchy.call.Static.NestedCall.file_1)"/>
+ <node text="func3(*args) (hierarchy.call.Static.NestedCall.file_1)"/>
+ <node text="func6(*args) (hierarchy.call.Static.NestedCall.file_1)"/>
+ <node text="func7(*args) (hierarchy.call.Static.NestedCall.file_1)"/>
+ <node text="func2(*args) (hierarchy.call.Static.NestedCall.file_1)"/>
+ <node text="func1(*args) (hierarchy.call.Static.NestedCall.file_1)"/>
+ <node text="func10(*args) (hierarchy.call.Static.NestedCall.file_1)"/>
+ <node text="inner(*args) (hierarchy.call.Static.NestedCall.main)">
+ <node text="func1(*args) (hierarchy.call.Static.NestedCall.file_1)"/>
+ </node>
+</node> \ No newline at end of file
diff --git a/python/testData/hierarchy/call/Static/NestedCall/NestedCall_caller_verification.xml b/python/testData/hierarchy/call/Static/NestedCall/NestedCall_caller_verification.xml
new file mode 100644
index 000000000000..ea843209ce23
--- /dev/null
+++ b/python/testData/hierarchy/call/Static/NestedCall/NestedCall_caller_verification.xml
@@ -0,0 +1 @@
+<node text="target_func() (hierarchy.call.Static.NestedCall.main)" base="true"/> \ No newline at end of file
diff --git a/python/testData/hierarchy/call/Static/NestedCall/file_1.py b/python/testData/hierarchy/call/Static/NestedCall/file_1.py
new file mode 100644
index 000000000000..3e89b6b290d0
--- /dev/null
+++ b/python/testData/hierarchy/call/Static/NestedCall/file_1.py
@@ -0,0 +1,10 @@
+def func1(*args): pass
+def func2(*args): pass
+def func3(*args): pass
+def func4(*args): pass
+def func5(*args): pass
+def func6(*args): pass
+def func7(*args): pass
+def func8(*args): pass
+def func9(*args): pass
+def func10(*args): pass \ No newline at end of file
diff --git a/python/testData/hierarchy/call/Static/NestedCall/main.py b/python/testData/hierarchy/call/Static/NestedCall/main.py
new file mode 100644
index 000000000000..aca993a9d6a1
--- /dev/null
+++ b/python/testData/hierarchy/call/Static/NestedCall/main.py
@@ -0,0 +1,10 @@
+from file_1 import *
+
+def target_func():
+ def inner(*args):
+ return func1()
+
+ return inner(func1(func2(func3(func4, func5()), func6(), (((func7)))()), func8), func9, func10())
+
+
+target_<caret>func() \ No newline at end of file
diff --git a/python/testData/hierarchy/call/Static/OverriddenMethod/OverriddenMethod_callee_verification.xml b/python/testData/hierarchy/call/Static/OverriddenMethod/OverriddenMethod_callee_verification.xml
new file mode 100644
index 000000000000..04af9fdd87ed
--- /dev/null
+++ b/python/testData/hierarchy/call/Static/OverriddenMethod/OverriddenMethod_callee_verification.xml
@@ -0,0 +1,3 @@
+<node text="B.target_func(self, p) (hierarchy.call.Static.OverriddenMethod.main)" base="true">
+ <node text="A.another_func(self) (hierarchy.call.Static.OverriddenMethod.file_1)"/>
+</node> \ No newline at end of file
diff --git a/python/testData/hierarchy/call/Static/OverriddenMethod/OverriddenMethod_caller_verification.xml b/python/testData/hierarchy/call/Static/OverriddenMethod/OverriddenMethod_caller_verification.xml
new file mode 100644
index 000000000000..ddf9369f2766
--- /dev/null
+++ b/python/testData/hierarchy/call/Static/OverriddenMethod/OverriddenMethod_caller_verification.xml
@@ -0,0 +1,5 @@
+<node text="B.target_func(self, p) (hierarchy.call.Static.OverriddenMethod.main)" base="true">
+ <node text="C.func1(self, a) (hierarchy.call.Static.OverriddenMethod.main)"/>
+ <node text="bar1(a) (hierarchy.call.Static.OverriddenMethod.main)"/>
+ <node text="C.func2(self) (hierarchy.call.Static.OverriddenMethod.main)"/>
+</node> \ No newline at end of file
diff --git a/python/testData/hierarchy/call/Static/OverriddenMethod/file_1.py b/python/testData/hierarchy/call/Static/OverriddenMethod/file_1.py
new file mode 100644
index 000000000000..e1e4fb90b949
--- /dev/null
+++ b/python/testData/hierarchy/call/Static/OverriddenMethod/file_1.py
@@ -0,0 +1,8 @@
+
+class A(object):
+ def target_func(self, p):
+ pass
+
+ def another_func(self):
+ pass
+
diff --git a/python/testData/hierarchy/call/Static/OverriddenMethod/main.py b/python/testData/hierarchy/call/Static/OverriddenMethod/main.py
new file mode 100644
index 000000000000..288d638e0fea
--- /dev/null
+++ b/python/testData/hierarchy/call/Static/OverriddenMethod/main.py
@@ -0,0 +1,29 @@
+from file_1 import A
+
+
+class B(A):
+ def target_func(self, p):
+ p.another_func()
+
+
+class C(object):
+ def func1(self, a):
+ a.target_func(A())
+
+ def func2(self):
+ a = A()
+ b = B()
+ a.target_func(b)
+
+
+def bar1(a):
+ a.target_func(a)
+
+
+def bar2(a, b):
+ atf, btf = a.target_func, b.target_func
+
+
+bar1(A())
+bar2(A(), B())
+B().target_<caret>func(A()) \ No newline at end of file
diff --git a/python/testData/hierarchy/call/Static/Parentheses/Parentheses_callee_verification.xml b/python/testData/hierarchy/call/Static/Parentheses/Parentheses_callee_verification.xml
new file mode 100644
index 000000000000..662bc7a74da8
--- /dev/null
+++ b/python/testData/hierarchy/call/Static/Parentheses/Parentheses_callee_verification.xml
@@ -0,0 +1,3 @@
+<node text="target_func() (hierarchy.call.Static.Parentheses.file_1)" base="true">
+ <node text="nothing(x) (hierarchy.call.Static.Parentheses.main)"/>
+</node> \ No newline at end of file
diff --git a/python/testData/hierarchy/call/Static/Parentheses/Parentheses_caller_verification.xml b/python/testData/hierarchy/call/Static/Parentheses/Parentheses_caller_verification.xml
new file mode 100644
index 000000000000..36b8e32e9363
--- /dev/null
+++ b/python/testData/hierarchy/call/Static/Parentheses/Parentheses_caller_verification.xml
@@ -0,0 +1,3 @@
+<node text="target_func() (hierarchy.call.Static.Parentheses.file_1)" base="true">
+ <node text="foo(x=bar()) (hierarchy.call.Static.Parentheses.file_1)"/>
+</node> \ No newline at end of file
diff --git a/python/testData/hierarchy/call/Static/Parentheses/file_1.py b/python/testData/hierarchy/call/Static/Parentheses/file_1.py
new file mode 100644
index 000000000000..ed3de6593a59
--- /dev/null
+++ b/python/testData/hierarchy/call/Static/Parentheses/file_1.py
@@ -0,0 +1,20 @@
+import main
+
+def target_func():
+ main.nothing(None)
+
+
+def nothing(x):
+ pass
+
+
+def foo(x=bar()):
+ ((target_func))()
+
+
+def bar():
+ main.nothing((target_func))
+
+
+def another():
+ ((((target_func), 1))(), 2)() \ No newline at end of file
diff --git a/python/testData/hierarchy/call/Static/Parentheses/main.py b/python/testData/hierarchy/call/Static/Parentheses/main.py
new file mode 100644
index 000000000000..37fe5bf0819d
--- /dev/null
+++ b/python/testData/hierarchy/call/Static/Parentheses/main.py
@@ -0,0 +1,7 @@
+from file_1 import target_func
+
+def nothing(x):
+ pass
+
+
+target_<caret>func() \ No newline at end of file
diff --git a/python/testData/hierarchy/call/Static/Simple/Simple_callee_verification.xml b/python/testData/hierarchy/call/Static/Simple/Simple_callee_verification.xml
new file mode 100644
index 000000000000..c009281e2fa2
--- /dev/null
+++ b/python/testData/hierarchy/call/Static/Simple/Simple_callee_verification.xml
@@ -0,0 +1,3 @@
+<node text="target_func() (hierarchy.call.Static.Simple.main)" base="true">
+ <node text="func1() (hierarchy.call.Static.Simple.main)"/>
+</node> \ No newline at end of file
diff --git a/python/testData/hierarchy/call/Static/Simple/Simple_caller_verification.xml b/python/testData/hierarchy/call/Static/Simple/Simple_caller_verification.xml
new file mode 100644
index 000000000000..a0f06c09b00a
--- /dev/null
+++ b/python/testData/hierarchy/call/Static/Simple/Simple_caller_verification.xml
@@ -0,0 +1,3 @@
+<node text="target_func() (hierarchy.call.Static.Simple.main)" base="true">
+ <node text="func2() (hierarchy.call.Static.Simple.main)"/>
+</node> \ No newline at end of file
diff --git a/python/testData/hierarchy/call/Static/Simple/main.py b/python/testData/hierarchy/call/Static/Simple/main.py
new file mode 100644
index 000000000000..9073f3df5d87
--- /dev/null
+++ b/python/testData/hierarchy/call/Static/Simple/main.py
@@ -0,0 +1,10 @@
+def func1():
+ pass
+
+def func2():
+ target_func()
+
+def target_func():
+ func1()
+
+target_<caret>func()
diff --git a/python/testData/highlighting/multipleEscapedBackslashes.py b/python/testData/highlighting/multipleEscapedBackslashes.py
new file mode 100644
index 000000000000..4eb30abdcdb4
--- /dev/null
+++ b/python/testData/highlighting/multipleEscapedBackslashes.py
@@ -0,0 +1,2 @@
+S1 = 'This literal contains even number of backslashes\\\\\\'
+S2 = <error descr="Missing closing quote [']">'This literal contains odd number of backslashes\\\\\\\'</error> \ No newline at end of file
diff --git a/python/testData/inspections/DefaultArgumentEmptyList.py b/python/testData/inspections/DefaultArgumentEmptyList.py
index 55748eb449d5..a351c5134c90 100644
--- a/python/testData/inspections/DefaultArgumentEmptyList.py
+++ b/python/testData/inspections/DefaultArgumentEmptyList.py
@@ -1 +1 @@
-def foo(args=<warning descr="Default argument value is mutable">[<caret>]</warning>):<EOLError descr="Indent expected"></EOLError> \ No newline at end of file
+def bar(args=<warning descr="Default argument value is mutable">[<caret>]</warning>):<EOLError descr="Indent expected"></EOLError> \ No newline at end of file
diff --git a/python/testData/inspections/DefaultArgumentEmptyList_after.py b/python/testData/inspections/DefaultArgumentEmptyList_after.py
index 2de1bb88ef92..ada9baaa7865 100644
--- a/python/testData/inspections/DefaultArgumentEmptyList_after.py
+++ b/python/testData/inspections/DefaultArgumentEmptyList_after.py
@@ -1,3 +1,3 @@
-def foo(args=None):
+def bar(args=None):
if not args:
args = [] \ No newline at end of file
diff --git a/python/testData/mover/outsideFromDict.py b/python/testData/mover/outsideFromDict.py
new file mode 100644
index 000000000000..52f81fd16a8e
--- /dev/null
+++ b/python/testData/mover/outsideFromDict.py
@@ -0,0 +1,5 @@
+a = {
+ 1:1,
+ # te<caret>st
+ 2:2
+}
diff --git a/python/testData/mover/outsideFromDict_afterDown.py b/python/testData/mover/outsideFromDict_afterDown.py
new file mode 100644
index 000000000000..551adfcd7894
--- /dev/null
+++ b/python/testData/mover/outsideFromDict_afterDown.py
@@ -0,0 +1,5 @@
+a = {
+ 1:1,
+ 2:2
+ # te<caret>st
+}
diff --git a/python/testData/mover/outsideFromDict_afterUp.py b/python/testData/mover/outsideFromDict_afterUp.py
new file mode 100644
index 000000000000..36f665bfc69f
--- /dev/null
+++ b/python/testData/mover/outsideFromDict_afterUp.py
@@ -0,0 +1,5 @@
+a = {
+ # te<caret>st
+ 1:1,
+ 2:2
+}
diff --git a/python/testData/mover/sameLevelAsDict.py b/python/testData/mover/sameLevelAsDict.py
new file mode 100644
index 000000000000..fd5b54ec4e82
--- /dev/null
+++ b/python/testData/mover/sameLevelAsDict.py
@@ -0,0 +1,9 @@
+a = {
+ 'c': 99999
+}
+print "Hello, there."
+a = {
+ 'b': 1,
+ 'c': 2
+}
+print <caret>a['c'] \ No newline at end of file
diff --git a/python/testData/mover/sameLevelAsDict_afterDown.py b/python/testData/mover/sameLevelAsDict_afterDown.py
new file mode 100644
index 000000000000..602da928bab7
--- /dev/null
+++ b/python/testData/mover/sameLevelAsDict_afterDown.py
@@ -0,0 +1,9 @@
+a = {
+ 'c': 99999
+}
+print "Hello, there."
+a = {
+ 'b': 1,
+ 'c': 2
+}
+print a['c'] \ No newline at end of file
diff --git a/python/testData/mover/sameLevelAsDict_afterUp.py b/python/testData/mover/sameLevelAsDict_afterUp.py
new file mode 100644
index 000000000000..c4817e7a6474
--- /dev/null
+++ b/python/testData/mover/sameLevelAsDict_afterUp.py
@@ -0,0 +1,9 @@
+a = {
+ 'c': 99999
+}
+print "Hello, there."
+print a['c']
+a = {
+ 'b': 1,
+ 'c': 2
+}
diff --git a/python/testSrc/com/jetbrains/env/python/PyPackagingTest.java b/python/testSrc/com/jetbrains/env/python/PyPackagingTest.java
index 54afb702322b..8dcc2ec69f6f 100644
--- a/python/testSrc/com/jetbrains/env/python/PyPackagingTest.java
+++ b/python/testSrc/com/jetbrains/env/python/PyPackagingTest.java
@@ -43,7 +43,7 @@ public class PyPackagingTest extends PyEnvTestCase {
final Sdk sdk = createTempSdk(sdkHome, SdkCreationType.EMPTY_SDK);
List<PyPackage> packages = null;
try {
- packages = ((PyPackageManagerImpl)PyPackageManager.getInstance(sdk)).getPackages();
+ packages = PyPackageManager.getInstance(sdk).getPackages(false);
}
catch (PyExternalProcessException e) {
final int retcode = e.getRetcode();
@@ -74,13 +74,13 @@ public class PyPackagingTest extends PyEnvTestCase {
}
final File tempDir = FileUtil.createTempDirectory(getTestName(false), null);
final File venvDir = new File(tempDir, "venv");
- final String venvSdkHome = ((PyPackageManagerImpl)PyPackageManagerImpl.getInstance(sdk)).createVirtualEnv(venvDir.toString(),
- false);
+ final String venvSdkHome = PyPackageManager.getInstance(sdk).createVirtualEnv(venvDir.toString(),
+ false);
final Sdk venvSdk = createTempSdk(venvSdkHome, SdkCreationType.EMPTY_SDK);
assertNotNull(venvSdk);
assertTrue(PythonSdkType.isVirtualEnv(venvSdk));
assertInstanceOf(PythonSdkFlavor.getPlatformIndependentFlavor(venvSdk.getHomePath()), VirtualEnvSdkFlavor.class);
- final List<PyPackage> packages = ((PyPackageManagerImpl)PyPackageManagerImpl.getInstance(venvSdk)).getPackages();
+ final List<PyPackage> packages = PyPackageManager.getInstance(venvSdk).getPackages(false);
final PyPackage setuptools = findPackage("setuptools", packages);
assertNotNull(setuptools);
assertEquals("setuptools", setuptools.getName());
@@ -109,15 +109,15 @@ public class PyPackagingTest extends PyEnvTestCase {
try {
final File tempDir = FileUtil.createTempDirectory(getTestName(false), null);
final File venvDir = new File(tempDir, "venv");
- final String venvSdkHome = ((PyPackageManagerImpl)PyPackageManager.getInstance(sdk)).createVirtualEnv(venvDir.getPath(), false);
+ final String venvSdkHome = PyPackageManager.getInstance(sdk).createVirtualEnv(venvDir.getPath(), false);
final Sdk venvSdk = createTempSdk(venvSdkHome, SdkCreationType.EMPTY_SDK);
assertNotNull(venvSdk);
- final PyPackageManagerImpl manager = (PyPackageManagerImpl)PyPackageManager.getInstance(venvSdk);
- final List<PyPackage> packages1 = manager.getPackages();
+ final PyPackageManager manager = PyPackageManager.getInstance(venvSdk);
+ final List<PyPackage> packages1 = manager.getPackages(false);
// TODO: Install Markdown from a local file
manager.install(list(PyRequirement.fromString("Markdown<2.2"),
new PyRequirement("httplib2")), Collections.<String>emptyList());
- final List<PyPackage> packages2 = manager.getPackages();
+ final List<PyPackage> packages2 = manager.getPackages(false);
final PyPackage markdown2 = findPackage("Markdown", packages2);
assertNotNull(markdown2);
assertTrue(markdown2.isInstalled());
@@ -126,7 +126,7 @@ public class PyPackagingTest extends PyEnvTestCase {
assertEquals("pip", pip1.getName());
assertEquals(PyPackageManagerImpl.PIP_VERSION, pip1.getVersion());
manager.uninstall(list(pip1));
- final List<PyPackage> packages3 = manager.getPackages();
+ final List<PyPackage> packages3 = manager.getPackages(false);
final PyPackage pip2 = findPackage("pip", packages3);
assertNull(pip2);
}
diff --git a/python/testSrc/com/jetbrains/env/python/PythonDebuggerTest.java b/python/testSrc/com/jetbrains/env/python/PythonDebuggerTest.java
index 4372715371eb..e29ab4cfdc8b 100644
--- a/python/testSrc/com/jetbrains/env/python/PythonDebuggerTest.java
+++ b/python/testSrc/com/jetbrains/env/python/PythonDebuggerTest.java
@@ -13,7 +13,7 @@ import com.jetbrains.python.console.pydev.PydevCompletionVariant;
import com.jetbrains.python.debugger.PyDebuggerException;
import com.jetbrains.python.debugger.PyExceptionBreakpointProperties;
import com.jetbrains.python.debugger.PyExceptionBreakpointType;
-import com.jetbrains.python.debugger.pydev.ProcessDebugger;
+import com.jetbrains.python.debugger.pydev.PyDebugCallback;
import com.jetbrains.python.sdk.flavors.PythonSdkFlavor;
import java.util.List;
@@ -52,8 +52,12 @@ public class PythonDebuggerTest extends PyEnvTestCase {
});
}
- public void testDebugger() {
- runPythonTest(new PyUnitTestTask("", "test_debug.py") {
+ public void testPydevTests_Debugger() {
+ unittests("tests_python/test_debugger.py");
+ }
+
+ private void unittests(final String script) {
+ runPythonTest(new PyUnitTestTask("", script) {
@Override
protected String getTestDataPath() {
return PythonHelpersLocator.getPythonCommunityPath() + "/helpers/pydev";
@@ -63,9 +67,18 @@ public class PythonDebuggerTest extends PyEnvTestCase {
public void after() {
allTestsPassed();
}
+
+ @Override
+ protected int getTestTimeout() {
+ return 600000;
+ }
});
}
+ public void testDebug() { //TODO: merge it into pydev tests
+ unittests("test_debug.py");
+ }
+
public void testConditionalBreakpoint() throws Exception {
runPythonTest(new PyDebuggerTask("/debug", "test1.py") {
@Override
@@ -128,7 +141,7 @@ public class PythonDebuggerTest extends PyEnvTestCase {
}
private void consoleExec(String command) {
- myDebugProcess.consoleExec(command, new ProcessDebugger.DebugCallback<String>() {
+ myDebugProcess.consoleExec(command, new PyDebugCallback<String>() {
@Override
public void ok(String value) {
diff --git a/python/testSrc/com/jetbrains/env/ut/PyUnitTestTask.java b/python/testSrc/com/jetbrains/env/ut/PyUnitTestTask.java
index 01401ca1ca9a..550ca6690cfd 100644
--- a/python/testSrc/com/jetbrains/env/ut/PyUnitTestTask.java
+++ b/python/testSrc/com/jetbrains/env/ut/PyUnitTestTask.java
@@ -1,8 +1,11 @@
package com.jetbrains.env.ut;
import com.google.common.collect.Lists;
-import com.intellij.execution.*;
+import com.intellij.execution.RunManager;
+import com.intellij.execution.RunManagerEx;
+import com.intellij.execution.RunnerAndConfigurationSettings;
import com.intellij.execution.configurations.ConfigurationFactory;
+import com.intellij.execution.configurations.RunConfiguration;
import com.intellij.execution.executors.DefaultRunExecutor;
import com.intellij.execution.process.ProcessAdapter;
import com.intellij.execution.process.ProcessEvent;
@@ -29,20 +32,37 @@ import com.jetbrains.python.sdk.flavors.PythonSdkFlavor;
import com.jetbrains.python.testing.AbstractPythonTestRunConfiguration;
import com.jetbrains.python.testing.PythonTestConfigurationType;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import org.junit.Assert;
/**
+ * Tasks to run unit test configurations.
+ * You should extend it either implementing {@link #after()} and {@link #before()} or implement {@link #runTestOn(String)}
+ * yourself and use {@link #runConfiguration(com.intellij.execution.configurations.ConfigurationFactory, String, com.intellij.openapi.project.Project)}
+ * or {@link #runConfiguration(com.intellij.execution.RunnerAndConfigurationSettings, com.intellij.execution.configurations.RunConfiguration)} .
+ * Use {@link #myDescriptor} and {@link #myConsoleView} to check output
+ *
* @author traff
*/
public abstract class PyUnitTestTask extends PyExecutionFixtureTestTask {
protected ProcessHandler myProcessHandler;
private boolean shouldPrintOutput = false;
- private SMTestProxy.SMRootTestProxy myTestProxy;
- private boolean mySetUp = false;
- private SMTRunnerConsoleView myConsoleView;
- private RunContentDescriptor myDescriptor;
+ /**
+ * Test root node
+ */
+ protected SMTestProxy.SMRootTestProxy myTestProxy;
+ /**
+ * Output test console
+ */
+ protected SMTRunnerConsoleView myConsoleView;
+ /**
+ * Test run descriptor
+ */
+ protected RunContentDescriptor myDescriptor;
+
private StringBuilder myOutput;
+ private boolean mySetUp = false;
public PyUnitTestTask() {
}
@@ -83,30 +103,30 @@ public abstract class PyUnitTestTask extends PyExecutionFixtureTestTask {
@Override
public void tearDown() throws Exception {
UIUtil.invokeAndWaitIfNeeded(new Runnable() {
- @Override
- public void run() {
- try {
- if (mySetUp) {
- if (myConsoleView != null) {
- Disposer.dispose(myConsoleView);
- myConsoleView = null;
- }
- if (myDescriptor != null) {
- Disposer.dispose(myDescriptor);
- myDescriptor = null;
- }
-
-
- PyUnitTestTask.super.tearDown();
-
- mySetUp = false;
- }
- }
- catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
- }
+ @Override
+ public void run() {
+ try {
+ if (mySetUp) {
+ if (myConsoleView != null) {
+ Disposer.dispose(myConsoleView);
+ myConsoleView = null;
+ }
+ if (myDescriptor != null) {
+ Disposer.dispose(myDescriptor);
+ myDescriptor = null;
+ }
+
+
+ PyUnitTestTask.super.tearDown();
+
+ mySetUp = false;
+ }
+ }
+ catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
);
}
@@ -151,10 +171,30 @@ public abstract class PyUnitTestTask extends PyExecutionFixtureTestTask {
}
}.execute();
- final ExecutionEnvironment environment = ExecutionEnvironmentBuilder.create(DefaultRunExecutor.getRunExecutorInstance(), settings).build();
+ runConfiguration(settings, config);
+ }
+
+ /**
+ * Run configuration.
+ *
+ * @param settings settings (if have any, null otherwise)
+ * @param config configuration to run
+ * @throws Exception
+ */
+ protected void runConfiguration(@Nullable final RunnerAndConfigurationSettings settings,
+ @NotNull final RunConfiguration config) throws Exception {
+ final ExecutionEnvironment environment;
+ if (settings == null) {
+ environment = ExecutionEnvironmentBuilder.create(DefaultRunExecutor.getRunExecutorInstance(), config).build();
+ }
+ else {
+ environment = ExecutionEnvironmentBuilder.create(DefaultRunExecutor.getRunExecutorInstance(), settings).build();
+ }
//noinspection ConstantConditions
+
Assert.assertTrue(environment.getRunner().canRun(DefaultRunExecutor.EXECUTOR_ID, config));
+
before();
final com.intellij.util.concurrency.Semaphore s = new com.intellij.util.concurrency.Semaphore();
@@ -177,7 +217,7 @@ public abstract class PyUnitTestTask extends PyExecutionFixtureTestTask {
myOutput.append(event.getText());
}
});
- myConsoleView = (com.intellij.execution.testframework.sm.runner.ui.SMTRunnerConsoleView)descriptor.getExecutionConsole();
+ myConsoleView = (SMTRunnerConsoleView)descriptor.getExecutionConsole();
myTestProxy = myConsoleView.getResultsViewer().getTestsRootNode();
myConsoleView.getResultsViewer().addEventsListener(new TestResultsViewer.SMEventsAdapter() {
@Override
@@ -194,7 +234,7 @@ public abstract class PyUnitTestTask extends PyExecutionFixtureTestTask {
}
});
- Assert.assertTrue(s.waitFor(60000));
+ Assert.assertTrue(s.waitFor(getTestTimeout()));
XDebuggerTestUtil.waitForSwing();
@@ -207,6 +247,10 @@ public abstract class PyUnitTestTask extends PyExecutionFixtureTestTask {
disposeProcess(myProcessHandler);
}
+ protected int getTestTimeout() {
+ return 60000;
+ }
+
protected void configure(AbstractPythonTestRunConfiguration config) {
}
diff --git a/python/testSrc/com/jetbrains/python/PySmartEnterTest.java b/python/testSrc/com/jetbrains/python/PySmartEnterTest.java
index 09e0317051a0..e58988010645 100644
--- a/python/testSrc/com/jetbrains/python/PySmartEnterTest.java
+++ b/python/testSrc/com/jetbrains/python/PySmartEnterTest.java
@@ -184,4 +184,9 @@ public class PySmartEnterTest extends PyTestCase {
public void testWithExpressionMissing() {
doTest();
}
+
+ // PY-12877
+ public void testWithOnlyColonMissing() {
+ doTest();
+ }
}
diff --git a/python/testSrc/com/jetbrains/python/PyStatementMoverTest.java b/python/testSrc/com/jetbrains/python/PyStatementMoverTest.java
index 3539150731b6..220c08ef2d24 100644
--- a/python/testSrc/com/jetbrains/python/PyStatementMoverTest.java
+++ b/python/testSrc/com/jetbrains/python/PyStatementMoverTest.java
@@ -260,6 +260,14 @@ public class PyStatementMoverTest extends PyTestCase {
doTest();
}
+ public void testOutsideFromDict() {
+ doTest();
+ }
+
+ public void testSameLevelAsDict() {
+ doTest();
+ }
+
public void testWith() { // PY-5202
try {
setLanguageLevel(LanguageLevel.PYTHON27);
diff --git a/python/testSrc/com/jetbrains/python/PythonHighlightingTest.java b/python/testSrc/com/jetbrains/python/PythonHighlightingTest.java
index e1fa67de63e4..73ab49e28659 100644
--- a/python/testSrc/com/jetbrains/python/PythonHighlightingTest.java
+++ b/python/testSrc/com/jetbrains/python/PythonHighlightingTest.java
@@ -174,6 +174,10 @@ public class PythonHighlightingTest extends PyTestCase {
doTest(true, false);
}
+ public void testMultipleEscapedBackslashes() {
+ doTest(true, false);
+ }
+
public void testUnsupportedFeaturesInPython3() {
doTest(LanguageLevel.PYTHON30, true, false);
}
diff --git a/python/testSrc/com/jetbrains/python/PythonKeywordCompletionTest.java b/python/testSrc/com/jetbrains/python/PythonKeywordCompletionTest.java
index 109a1bddd19b..e64f02ad16c3 100644
--- a/python/testSrc/com/jetbrains/python/PythonKeywordCompletionTest.java
+++ b/python/testSrc/com/jetbrains/python/PythonKeywordCompletionTest.java
@@ -199,6 +199,17 @@ public class PythonKeywordCompletionTest extends PyTestCase {
assertContainsElements(doTestByText("for x i<caret>n y:\n pass]"), "in");
}
+ // PY-11375
+ public void testYieldExpression() {
+ assertContainsElements(doTestByText("def gen(): x = <caret>"), "yield");
+ assertDoesntContain(doTestByText("def gen(): x = 1 + <caret>"), "yield");
+ assertContainsElements(doTestByText("def gen(): x = 1 + (<caret>"), "yield");
+ assertContainsElements(doTestByText("def gen(): x **= <caret>"), "yield");
+ assertDoesntContain(doTestByText("def gen(): func(<caret>)"), "yield");
+ assertContainsElements(doTestByText("def gen(): func((<caret>"), "yield");
+ assertDoesntContain(doTestByText("def gen(): x = y<caret> = 42"), "yield");
+ }
+
public void testExceptAfterElse() {
assertDoesntContain(doTestByText("try:\n" +
" pass\n" +
diff --git a/python/testSrc/com/jetbrains/python/fixtures/PyTestCase.java b/python/testSrc/com/jetbrains/python/fixtures/PyTestCase.java
index 8a237b7dfb01..3528d7c6517d 100644
--- a/python/testSrc/com/jetbrains/python/fixtures/PyTestCase.java
+++ b/python/testSrc/com/jetbrains/python/fixtures/PyTestCase.java
@@ -18,8 +18,14 @@ package com.jetbrains.python.fixtures;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ex.QuickFixWrapper;
+import com.intellij.execution.actions.ConfigurationContext;
+import com.intellij.execution.actions.ConfigurationFromContext;
+import com.intellij.execution.actions.RunConfigurationProducer;
+import com.intellij.execution.configurations.RunConfiguration;
import com.intellij.find.findUsages.CustomUsageSearcher;
import com.intellij.find.findUsages.FindUsagesOptions;
+import com.intellij.ide.DataManager;
+import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.module.Module;
@@ -56,6 +62,7 @@ import com.jetbrains.python.PythonTestUtil;
import com.jetbrains.python.psi.LanguageLevel;
import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.PyFile;
+import com.jetbrains.python.psi.PyUtil;
import com.jetbrains.python.psi.impl.PyFileImpl;
import com.jetbrains.python.psi.impl.PythonLanguageLevelPusher;
import org.jetbrains.annotations.NotNull;
@@ -64,7 +71,6 @@ import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.List;
/**
* @author yole
@@ -92,12 +98,12 @@ public abstract class PyTestCase extends UsefulTestCase {
IdeaTestFixtureFactory factory = IdeaTestFixtureFactory.getFixtureFactory();
TestFixtureBuilder<IdeaProjectTestFixture> fixtureBuilder = factory.createLightFixtureBuilder(getProjectDescriptor());
final IdeaProjectTestFixture fixture = fixtureBuilder.getFixture();
- myFixture = IdeaTestFixtureFactory.getFixtureFactory().createCodeInsightFixture(fixture,
- new LightTempDirTestFixtureImpl(true));
- myFixture.setUp();
+ myFixture = IdeaTestFixtureFactory.getFixtureFactory().createCodeInsightFixture(fixture,
+ new LightTempDirTestFixtureImpl(true));
+ myFixture.setUp();
- myFixture.setTestDataPath(getTestDataPath());
- }
+ myFixture.setTestDataPath(getTestDataPath());
+ }
protected String getTestDataPath() {
return PythonTestUtil.getTestDataPath();
@@ -148,8 +154,9 @@ public abstract class PyTestCase extends UsefulTestCase {
/**
* Searches for quickfix itetion by its class
+ *
* @param clazz quick fix class
- * @param <T> quick fix class
+ * @param <T> quick fix class
* @return quick fix or null if nothing found
*/
@Nullable
@@ -170,8 +177,8 @@ public abstract class PyTestCase extends UsefulTestCase {
}
- protected static void assertNotParsed(PyFile file) {
- assertNull(PARSED_ERROR_MSG, ((PyFileImpl)file).getTreeElement());
+ protected static void assertNotParsed(PyFile file) {
+ assertNull(PARSED_ERROR_MSG, ((PyFileImpl)file).getTreeElement());
}
/**
@@ -184,15 +191,23 @@ public abstract class PyTestCase extends UsefulTestCase {
}
/**
+ * @see #moveByText(com.intellij.testFramework.fixtures.CodeInsightTestFixture, String)
+ */
+ protected void moveByText(@NotNull final String testToFind) {
+ moveByText(myFixture, testToFind);
+ }
+
+ /**
* Finds some text and moves cursor to it (if found)
*
+ * @param fixture test fixture
* @param testToFind text to find
* @throws AssertionError if element not found
*/
- protected void moveByText(@NotNull final String testToFind) {
- final PsiElement element = myFixture.findElementByText(testToFind, PsiElement.class);
+ public static void moveByText(@NotNull final CodeInsightTestFixture fixture, @NotNull final String testToFind) {
+ final PsiElement element = fixture.findElementByText(testToFind, PsiElement.class);
assert element != null : "No element found by text: " + testToFind;
- myFixture.getEditor().getCaretModel().moveToOffset(element.getTextOffset());
+ fixture.getEditor().getCaretModel().moveToOffset(element.getTextOffset());
}
/**
@@ -263,4 +278,31 @@ public abstract class PyTestCase extends UsefulTestCase {
public static String getHelpersPath() {
return new File(PythonHelpersLocator.getPythonCommunityPath(), "helpers").getPath();
}
+
+ /**
+ * Creates run configuration from right click menu
+ *
+ * @param fixture test fixture
+ * @param expectedClass expected class of run configuration
+ * @param <C> expected class of run configuration
+ * @return configuration (if created) or null (otherwise)
+ */
+ @Nullable
+ public static <C extends RunConfiguration> C createRunConfigurationFromContext(
+ @NotNull final CodeInsightTestFixture fixture,
+ @NotNull final Class<C> expectedClass) {
+ final DataContext context = DataManager.getInstance().getDataContext(fixture.getEditor().getComponent());
+ for (final RunConfigurationProducer<?> producer : RunConfigurationProducer.EP_NAME.getExtensions()) {
+ final ConfigurationFromContext fromContext = producer.createConfigurationFromContext(ConfigurationContext.getFromContext(context));
+ if (fromContext == null) {
+ continue;
+ }
+ final C result = PyUtil.as(fromContext.getConfiguration(), expectedClass);
+ if (result != null) {
+ return result;
+ }
+ }
+ return null;
+ }
}
+
diff --git a/python/testSrc/com/jetbrains/python/hierarchy/PyCallHierarchyTest.java b/python/testSrc/com/jetbrains/python/hierarchy/PyCallHierarchyTest.java
new file mode 100644
index 000000000000..f9f7e226f913
--- /dev/null
+++ b/python/testSrc/com/jetbrains/python/hierarchy/PyCallHierarchyTest.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2000-2014 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.hierarchy;
+
+import com.intellij.codeInsight.TargetElementUtilBase;
+import com.intellij.ide.hierarchy.HierarchyBrowserBaseEx;
+import com.intellij.ide.hierarchy.HierarchyNodeDescriptor;
+import com.intellij.ide.hierarchy.HierarchyTreeStructure;
+import com.intellij.psi.PsiElement;
+import com.jetbrains.python.fixtures.PyTestCase;
+import com.jetbrains.python.hierarchy.call.PyCalleeFunctionTreeStructure;
+import com.jetbrains.python.hierarchy.call.PyCallerFunctionTreeStructure;
+import com.jetbrains.python.psi.PyFunction;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author novokrest
+ */
+public class PyCallHierarchyTest extends PyTestCase {
+ private static final String CALLER_VERIFICATION_SUFFIX = "_caller_verification.xml";
+ private static final String CALLEE_VERIFICATION_SUFFIX = "_callee_verification.xml";
+
+ public static String dump(final HierarchyTreeStructure treeStructure, @Nullable HierarchyNodeDescriptor descriptor) {
+ StringBuilder s = new StringBuilder();
+ dump(treeStructure, descriptor, 0, s);
+ return s.toString();
+ }
+
+ private static void dump(final HierarchyTreeStructure treeStructure,
+ @Nullable HierarchyNodeDescriptor descriptor,
+ int level,
+ StringBuilder b) {
+ if (level > 10) {
+ for(int i = 0; i<level; i++) b.append(" ");
+ b.append("<Probably infinite part skipped>\n");
+ return;
+ }
+ if(descriptor==null) descriptor = (HierarchyNodeDescriptor)treeStructure.getRootElement();
+ for(int i = 0; i<level; i++) b.append(" ");
+ descriptor.update();
+ b.append("<node text=\"").append(descriptor.getHighlightedText().getText()).append("\"")
+ .append(treeStructure.getBaseDescriptor() == descriptor ? " base=\"true\"" : "");
+
+ final Object[] children = treeStructure.getChildElements(descriptor);
+ if(children.length>0) {
+ b.append(">\n");
+ for (Object o : children) {
+ HierarchyNodeDescriptor d = (HierarchyNodeDescriptor)o;
+ dump(treeStructure, d, level + 1, b);
+ }
+ for(int i = 0; i<level; i++) b.append(" ");
+ b.append("</node>\n");
+ } else {
+ b.append("/>\n");
+ }
+ }
+
+ private String getBasePath() {
+ return "hierarchy/call/Static/" + getTestName(false);
+ }
+
+ private void configureByFiles(String ... fileNames) {
+ String[] filePaths = new String[fileNames.length];
+ int i = 0;
+ for (String fileName: fileNames) {
+ filePaths[i] = getBasePath() + "/" + fileName;
+ i++;
+ }
+ myFixture.configureByFiles(filePaths);
+ }
+
+ private String getVerificationFilePath(final String suffix) {
+ return getTestDataPath() + "/" + getBasePath() + "/" + getTestName(false) + suffix;
+ }
+
+ private String getVerificationCallerFilePath() {
+ return getVerificationFilePath(CALLER_VERIFICATION_SUFFIX);
+ }
+
+ private String getVerificationCalleeFilePath() {
+ return getVerificationFilePath(CALLEE_VERIFICATION_SUFFIX);
+ }
+
+ private void checkHierarchyTreeStructure(PyFunction function) throws Exception {
+ final PyCallerFunctionTreeStructure callerStructure = new PyCallerFunctionTreeStructure(myFixture.getProject(), function,
+ HierarchyBrowserBaseEx.SCOPE_PROJECT);
+ assertSameLinesWithFile(getVerificationCallerFilePath(), dump(callerStructure, null));
+ final PyCalleeFunctionTreeStructure calleeStructure = new PyCalleeFunctionTreeStructure(myFixture.getProject(), function,
+ HierarchyBrowserBaseEx.SCOPE_PROJECT);
+ assertSameLinesWithFile(getVerificationCalleeFilePath(), dump(calleeStructure, null));
+ }
+
+ private void doTestCallHierarchy(String ... fileNames) throws Exception {
+ configureByFiles(fileNames);
+
+ final PsiElement targetElement = TargetElementUtilBase
+ .findTargetElement(myFixture.getEditor(),
+ TargetElementUtilBase.ELEMENT_NAME_ACCEPTED | TargetElementUtilBase.REFERENCED_ELEMENT_ACCEPTED);
+ assert targetElement != null : "Cannot find referenced element";
+ assert targetElement instanceof PyFunction : "Referenced element is not PyFunction";
+
+ PyFunction function = (PyFunction) targetElement;
+ checkHierarchyTreeStructure(function);
+ }
+
+ public void testSimple() throws Exception {
+ doTestCallHierarchy("main.py");
+ }
+
+ public void testArgumentList() throws Exception {
+ doTestCallHierarchy("main.py", "file_1.py");
+ }
+
+ public void testDefaultValue() throws Exception {
+ doTestCallHierarchy("main.py");
+ }
+
+ public void testLambda() throws Exception {
+ doTestCallHierarchy("main.py", "file_1.py");
+ }
+
+ public void testNestedCall() throws Exception {
+ doTestCallHierarchy("main.py", "file_1.py");
+ }
+
+ public void testInheritance() throws Exception {
+ doTestCallHierarchy("main.py");
+ }
+
+ public void testOverriddenMethod() throws Exception {
+ doTestCallHierarchy("main.py", "file_1.py");
+ }
+
+ public void testInnerFunction() throws Exception {
+ doTestCallHierarchy("main.py");
+ }
+
+ public void testConstructor() throws Exception {
+ doTestCallHierarchy("main.py");
+ }
+
+ public void testParentheses() throws Exception {
+ doTestCallHierarchy("main.py", "file_1.py");
+ }
+} \ No newline at end of file
diff --git a/python/testSrc/com/jetbrains/python/refactoring/PyInlineLocalTest.java b/python/testSrc/com/jetbrains/python/refactoring/PyInlineLocalTest.java
index 9a764b94169d..cf6ad38e075d 100644
--- a/python/testSrc/com/jetbrains/python/refactoring/PyInlineLocalTest.java
+++ b/python/testSrc/com/jetbrains/python/refactoring/PyInlineLocalTest.java
@@ -20,6 +20,7 @@ import com.intellij.openapi.util.Comparing;
import com.intellij.psi.PsiElement;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
+import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.jetbrains.python.PythonLanguage;
import com.jetbrains.python.fixtures.PyTestCase;
import com.jetbrains.python.refactoring.inline.PyInlineLocalHandler;
@@ -97,8 +98,19 @@ public class PyInlineLocalTest extends PyTestCase {
// PY-12409
public void testResultExceedsRightMargin() {
final CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(myFixture.getProject());
- settings.WRAP_LONG_LINES = true;
+ final CommonCodeStyleSettings commonSettings = settings.getCommonSettings(PythonLanguage.getInstance());
+
+ final int oldRightMargin = settings.getRightMargin(PythonLanguage.getInstance());
+ final boolean oldWrapLongLines = commonSettings.WRAP_LONG_LINES;
+
settings.setRightMargin(PythonLanguage.getInstance(), 80);
- doTest();
+ commonSettings.WRAP_LONG_LINES = true;
+ try {
+ doTest();
+ }
+ finally {
+ commonSettings.WRAP_LONG_LINES = oldWrapLongLines;
+ settings.setRightMargin(PythonLanguage.getInstance(), oldRightMargin);
+ }
}
}
diff --git a/python/testSrc/com/jetbrains/python/sdkTools/PyTestSdkTools.java b/python/testSrc/com/jetbrains/python/sdkTools/PyTestSdkTools.java
index 2d97e747f00b..0b5cdadbbc43 100644
--- a/python/testSrc/com/jetbrains/python/sdkTools/PyTestSdkTools.java
+++ b/python/testSrc/com/jetbrains/python/sdkTools/PyTestSdkTools.java
@@ -136,7 +136,7 @@ public final class PyTestSdkTools {
final SkeletonVersionChecker checker = new SkeletonVersionChecker(0);
final PySkeletonRefresher refresher = new PySkeletonRefresher(project, null, sdk, skeletonsPath, null, null);
- final List<String> errors = refresher.regenerateSkeletons(checker, null);
+ final List<String> errors = refresher.regenerateSkeletons(checker);
Assert.assertThat("Errors found", errors, Matchers.empty());
}
}
diff --git a/resources-en/src/messages/CompilerBundle.properties b/resources-en/src/messages/CompilerBundle.properties
index be7367512247..638cac1b8972 100644
--- a/resources-en/src/messages/CompilerBundle.properties
+++ b/resources-en/src/messages/CompilerBundle.properties
@@ -22,7 +22,7 @@ message.ant.files.generated.ok=Ant build files successfully generated:\n{0}
error.ant.files.generate.failed=Failed to generate ant build script: {0}
error.ant.files.backup.failed=Failed to backup file {0}
generate.ant.build.dialog.cyclic.modules.table.title=Cyclic Module Dependencies
-generate.ant.build.dialog.cyclic.modules.table.description=Some modules have cyclic dependencies.\nIn order to generate ant build script, please select the \"main\" (representative) module for each dependency cycle.\nThe source code for all modules in the cycle will be compiled into the main module's output folders;\nAll modules in the cycle will use the JDK assigned to the main module;\nAny jar archives created will be named after the name of the main module.
+generate.ant.build.dialog.cyclic.modules.table.description=Some modules have cyclic dependencies.\nIn order to generate ant build script, please select the \"main\" (representative) module for each dependency cycle.\nThe source code for all modules in the cycle will be compiled into the main module's output folders;\nAll modules in the cycle will use the JDK assigned to the main module;\nAny JAR files created will be named after the name of the main module.
generate.ant.build.dialog.cyclic.modules.table.number.column.header=Cycle
generate.ant.build.dialog.cyclic.modules.table.name.column.header=Main Module
action.make.selected.modules.text=Make Selected _Modules
diff --git a/resources-en/src/messages/DebuggerBundle.properties b/resources-en/src/messages/DebuggerBundle.properties
index ac623acc1fbe..5168323e961a 100644
--- a/resources-en/src/messages/DebuggerBundle.properties
+++ b/resources-en/src/messages/DebuggerBundle.properties
@@ -27,6 +27,10 @@ title.customize.data.views=Customize Data Views
title.evaluating=Evaluating...
error.modification.watchpoints.not.supported=Target VM does not support modification watchpoints
error.native.method.exception=None of the frames through and including frame may be native
+error.executing.finally=Error while executing finally blocks: {0}
+warning.finally.block.detected=Non-empty finally blocks detected:
+button.drop.anyway=Drop frame anyway
+button.execute.finally=Execute finally blocks and drop frame
action.remove.watch.text={0,choice, 1#Remove Watch|2#Remove Watches}
progress.evaluating=Evaluating {0}
action.resume.thread.text.resume=Resume
@@ -110,6 +114,8 @@ evaluation.error.cannot.resolve.class=Cannot resolve class ''{0}''
evaluation.error.invalid.array.dimension.expression=Invalid expression for array dimension: {0}
evaluation.error.multi.dimensional.arrays.creation.not.supported=Creation of multi-dimensional arrays not supported
evaluation.error.anonymous.class.evaluation.not.supported=Anonymous class evaluation is not supported
+evaluation.error.lambda.evaluation.not.supported=Lambdas evaluation is not supported
+evaluation.error.method.reference.evaluation.not.supported=Method reference evaluation is not supported
evaluation.error.no.static.field=No such static field: ''{0}''
evaluation.error.no.instance.field=No such instance field: ''{0}''
evaluation.error.class.or.array.expected=Class or array type expected while evaluating field ''{0}''
@@ -221,6 +227,10 @@ label.debugger.general.configurable.skip.constructors=Skip &constructors
label.debugger.general.configurable.skip.classLoaders=Skip class l&oaders
label.debugger.general.configurable.skip.simple.getters=Skip simple &getters
label.debugger.general.configurable.step.filters.list.header=Do not step &into the classes
+label.debugger.general.configurable.evaluate.finally.on.pop=Evaluate finally blocks on pop frame:
+label.debugger.general.configurable.evaluate.finally.always=&Always
+label.debugger.general.configurable.evaluate.finally.never=N&ever
+label.debugger.general.configurable.evaluate.finally.ask=As&k
label.threads.view.configurable.show.source.file.name=Show source file name
label.threads.view.configurable.show.class.name=Show class name
label.threads.view.configurable.show.line.number=Show &line number
@@ -438,4 +448,5 @@ action.kill.process.text=Kill Process
action.kill.process.description=Forcibly terminate debugged application
evaluation.error.unknown.method.return.type=Cannot resolve method return type: {0}
rule.name.group.by.class=Group by class
-rule.name.group.by.package=Group by package \ No newline at end of file
+rule.name.group.by.package=Group by package
+error.context.has.changed=Context has changed, operation is not possible \ No newline at end of file
diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml
index dafbbba9d5b8..ac35522d1010 100644
--- a/resources/src/META-INF/IdeaPlugin.xml
+++ b/resources/src/META-INF/IdeaPlugin.xml
@@ -1224,6 +1224,8 @@
<!-- <configurationType implementation="com.intellij.execution.applet.AppletConfigurationType"/>
<configurationProducer implementation="com.intellij.execution.applet.AppletConfigurationProducer"/> -->
<configurationType implementation="com.intellij.execution.application.ApplicationConfigurationType"/>
+ <configurationType implementation="com.intellij.execution.jar.JarApplicationConfigurationType"/>
+ <runConfigurationProducer implementation="com.intellij.execution.jar.JarApplicationConfigurationProducer"/>
<runConfigurationProducer implementation="com.intellij.execution.application.ApplicationConfigurationProducer"/>
<configurationType implementation="com.intellij.execution.remote.RemoteConfigurationType"/>
@@ -1452,6 +1454,7 @@
<dom.uiControlsProvider implementation="com.intellij.util.xml.impl.JavaDomApplicationComponent"/>
<programRunner id="defaultDebugRunner" implementation="com.intellij.debugger.impl.GenericDebuggerRunner" order="last"/>
+ <programRunner implementation="com.intellij.execution.jar.JarApplicationDebuggerRunner"/>
<generation.topLevelFactory language="JAVA" implementationClass="com.intellij.psi.impl.JavaFactoryProvider"/>
@@ -1543,6 +1546,7 @@
implementation="com.intellij.codeInsight.ExternalAnnotationsNonProjectFileWritingAccessExtension"/>
<lang.inspectionSuppressor language="JAVA" implementationClass="com.intellij.codeInspection.SuppressManagerImpl"/>
<refactoring.moveInnerClassUsagesHandler language="JAVA" implementationClass="com.intellij.refactoring.move.moveInner.MoveInnerClassJavaUsagesHandler" id="java"/>
+ <actionPromoter implementation="com.intellij.execution.testframework.TestTreeViewActionsPromoter"/>
</extensions>
<actions>
diff --git a/resources/src/componentSets/IdeaComponents.xml b/resources/src/componentSets/IdeaComponents.xml
index 6faf2c022ed4..48a63411bc60 100644
--- a/resources/src/componentSets/IdeaComponents.xml
+++ b/resources/src/componentSets/IdeaComponents.xml
@@ -28,7 +28,6 @@
<xi:include href="/componentSets/WindowManagement.xml" xpointer="xpointer(/components/*)"/>
<xi:include href="/componentSets/Lang.xml" xpointer="xpointer(/components/*)"/>
<xi:include href="/componentSets/ProjectView.xml" xpointer="xpointer(/components/*)"/>
- <xi:include href="Toolwindows.xml" xpointer="xpointer(/components/*)"/>
<xi:include href="/componentSets/Editor.xml" xpointer="xpointer(/components/*)"/>
<xi:include href="Misc.xml" xpointer="xpointer(/components/*)"/>
<xi:include href="Compiler.xml" xpointer="xpointer(/components/*)"/>
diff --git a/resources/src/componentSets/Toolwindows.xml b/resources/src/componentSets/Toolwindows.xml
deleted file mode 100644
index 4558cbfc6006..000000000000
--- a/resources/src/componentSets/Toolwindows.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<components>
- <project-components>
- <component>
- <implementation-class>com.intellij.ide.palette.impl.PaletteManager</implementation-class>
- </component>
- </project-components>
-</components>
diff --git a/resources/src/idea/JavaActions.xml b/resources/src/idea/JavaActions.xml
index 81a791f42208..31f6d9ad84f4 100644
--- a/resources/src/idea/JavaActions.xml
+++ b/resources/src/idea/JavaActions.xml
@@ -153,7 +153,6 @@
</action>
<group id="JavaDebuggerActions">
- <action id="Debugger.AdjustArrayRange" class="com.intellij.debugger.actions.AdjustArrayRangeAction"/>
<action id="Debugger.Inspect" class="com.intellij.debugger.actions.InspectAction"/>
<action id="Debugger.CustomizeContextView" class="com.intellij.debugger.actions.CustomizeContextViewAction">
<add-to-group group-id="XDebugger.Variables.Tree.Popup" anchor="last"/>
@@ -178,6 +177,9 @@
<action id="Debugger.ViewAsGroup" class="com.intellij.debugger.actions.ViewAsGroup">
<add-to-group group-id="XDebugger.ValueGroup" anchor="last"/>
</action>
+ <action id="Debugger.AdjustArrayRange" class="com.intellij.debugger.actions.AdjustArrayRangeAction">
+ <add-to-group group-id="XDebugger.ValueGroup" anchor="last"/>
+ </action>
<!--<action id="Debugger.SetValue" class="com.intellij.debugger.actions.SetValueAction"/>-->
<!--<action id="Debugger.ShowAsHex" class="com.intellij.debugger.actions.ShowAsHexAction" text="Show as Hex"/>-->
<action id="Debugger.ShowFrame" class="com.intellij.debugger.actions.ShowFrameAction"/>
diff --git a/resources/src/idea/RichPlatformActions.xml b/resources/src/idea/RichPlatformActions.xml
index 324f2fe29c6e..9ca96101df82 100644
--- a/resources/src/idea/RichPlatformActions.xml
+++ b/resources/src/idea/RichPlatformActions.xml
@@ -28,7 +28,7 @@
<xi:include href="/idea/ExternalSystemActions.xml" xpointer="xpointer(/component/*)"/>
<actions>
- <action id="RerunFailedTests" class="com.intellij.execution.testframework.actions.AbstractRerunFailedTestsAction"
+ <action id="RerunFailedTests" class="com.intellij.execution.testframework.actions.RerunFailedTestsAction"
icon="AllIcons.RunConfigurations.RerunFailedTests"/>
<action id="FileChooser.GotoModule" class="com.intellij.openapi.fileChooser.actions.GotoModuleDirectory"
diff --git a/resources/src/idea/RichPlatformPlugin.xml b/resources/src/idea/RichPlatformPlugin.xml
index 444336338b1a..485d07839866 100644
--- a/resources/src/idea/RichPlatformPlugin.xml
+++ b/resources/src/idea/RichPlatformPlugin.xml
@@ -76,9 +76,6 @@
<extensionPoint name="compileServer.plugin" beanClass="com.intellij.compiler.server.CompileServerPlugin"/>
<extensionPoint name="buildProcess.parametersProvider" area="IDEA_PROJECT" interface="com.intellij.compiler.server.BuildProcessParametersProvider"/>
-
- <extensionPoint name="paletteItemProvider" area="IDEA_PROJECT" interface="com.intellij.ide.palette.PaletteItemProvider"/>
-
<extensionPoint name="attachSourcesProvider" interface="com.intellij.codeInsight.AttachSourcesProvider"/>
<extensionPoint name="java.compiler" area="IDEA_PROJECT"
diff --git a/resources/src/idea/RunManager.xml b/resources/src/idea/RunManager.xml
index 3377352115c5..327545ebc4ca 100644
--- a/resources/src/idea/RunManager.xml
+++ b/resources/src/idea/RunManager.xml
@@ -24,7 +24,7 @@
<option name="MAIN_CLASS_NAME" />
<option name="VM_PARAMETERS" value="-ea"/>
<option name="PARAMETERS" />
- <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
+ <option name="WORKING_DIRECTORY" value="$MODULE_DIR$" />
</configuration>
<configuration name="&lt;template&gt;" type="TestNG" default="true" selected="false">
diff --git a/spellchecker/src/com/intellij/spellchecker/quickfixes/DictionarySuggestionProvider.java b/spellchecker/src/com/intellij/spellchecker/quickfixes/DictionarySuggestionProvider.java
index d358990af876..08086e1a6326 100644
--- a/spellchecker/src/com/intellij/spellchecker/quickfixes/DictionarySuggestionProvider.java
+++ b/spellchecker/src/com/intellij/spellchecker/quickfixes/DictionarySuggestionProvider.java
@@ -20,6 +20,7 @@ import com.intellij.psi.PsiNamedElement;
import com.intellij.psi.codeStyle.SuggestedNameInfo;
import com.intellij.refactoring.rename.PreferrableNameSuggestionProvider;
import com.intellij.spellchecker.SpellCheckerManager;
+import com.intellij.util.containers.ContainerUtil;
import java.util.Set;
@@ -54,7 +55,7 @@ public class DictionarySuggestionProvider extends PreferrableNameSuggestionProvi
SpellCheckerManager manager = SpellCheckerManager.getInstance(element.getProject());
- result.addAll(manager.getSuggestions(text));
+ ContainerUtil.addAllNotNull(result, manager.getSuggestions(text));
return SuggestedNameInfo.NULL_INFO;
}
}
diff --git a/spellchecker/src/com/intellij/spellchecker/state/CachedDictionaryState.java b/spellchecker/src/com/intellij/spellchecker/state/CachedDictionaryState.java
index eb84d239336f..08956f481d9c 100644
--- a/spellchecker/src/com/intellij/spellchecker/state/CachedDictionaryState.java
+++ b/spellchecker/src/com/intellij/spellchecker/state/CachedDictionaryState.java
@@ -20,9 +20,8 @@ import com.intellij.spellchecker.dictionary.EditableDictionary;
@State(
name = "CachedDictionaryState",
- roamingType = RoamingType.DISABLED,
- storages = {@Storage(
- file = StoragePathMacros.APP_CONFIG + "/cachedDictionary.xml")})
+ storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/cachedDictionary.xml", roamingType = RoamingType.DISABLED)}
+)
public class CachedDictionaryState extends DictionaryState implements PersistentStateComponent<DictionaryState> {
public static final String DEFAULT_NAME = "cached";
@@ -42,4 +41,4 @@ public class CachedDictionaryState extends DictionaryState implements Persistent
}
super.loadState(state);
}
-} \ No newline at end of file
+}
diff --git a/updater/src/com/intellij/updater/Runner.java b/updater/src/com/intellij/updater/Runner.java
index d0143a946b0c..56a331b5ebc8 100755
--- a/updater/src/com/intellij/updater/Runner.java
+++ b/updater/src/com/intellij/updater/Runner.java
@@ -175,8 +175,8 @@ public class Runner {
optionalFiles,
ui);
- logger.info("Packing jar file: " + outPatchJar );
- ui.startProcess("Packing jar file '" + outPatchJar + "'...");
+ logger.info("Packing JAR file: " + outPatchJar );
+ ui.startProcess("Packing JAR file '" + outPatchJar + "'...");
FileOutputStream fileOut = new FileOutputStream(outPatchJar);
try {
@@ -326,8 +326,8 @@ public class Runner {
private static File resolveJarFile() throws IOException {
URL url = Runner.class.getResource("");
- if (url == null) throw new IOException("Cannot resolve jar file path");
- if (!"jar".equals(url.getProtocol())) throw new IOException("Patch file is not a 'jar' file");
+ if (url == null) throw new IOException("Cannot resolve JAR file path");
+ if (!"jar".equals(url.getProtocol())) throw new IOException("Patch file is not a JAR file");
String path = url.getPath();
diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/DomInvocationHandler.java b/xml/dom-impl/src/com/intellij/util/xml/impl/DomInvocationHandler.java
index 88bc70044268..a0529b60a8fc 100644
--- a/xml/dom-impl/src/com/intellij/util/xml/impl/DomInvocationHandler.java
+++ b/xml/dom-impl/src/com/intellij/util/xml/impl/DomInvocationHandler.java
@@ -170,7 +170,10 @@ public abstract class DomInvocationHandler<T extends AbstractDomChildDescription
@Override
public void run() {
ensureXmlElementExists();
- final DomGenericInfoEx genericInfo = getGenericInfo();
+ final DomInvocationHandler otherInvocationHandler = DomManagerImpl.getDomInvocationHandler(other);
+ assert otherInvocationHandler != null : other;
+
+ final DomGenericInfoEx genericInfo = otherInvocationHandler.getGenericInfo();
for (final AttributeChildDescriptionImpl description : genericInfo.getAttributeChildrenDescriptions()) {
description.getDomAttributeValue(DomInvocationHandler.this).setStringValue(description.getDomAttributeValue(other).getStringValue());
}
@@ -197,7 +200,7 @@ public abstract class DomInvocationHandler<T extends AbstractDomChildDescription
}
}
- final String stringValue = DomManagerImpl.getDomInvocationHandler(other).getValue();
+ final String stringValue = otherInvocationHandler.getValue();
if (StringUtil.isNotEmpty(stringValue)) {
setValue(stringValue);
}
@@ -659,12 +662,12 @@ public abstract class DomInvocationHandler<T extends AbstractDomChildDescription
return new AttributeChildInvocationHandler(evaluatedXmlName, description, myManager, strategy, stub);
}
final XmlTag tag = getXmlTag();
-
+
if (tag != null) {
// TODO: this seems ugly
String ns = evaluatedXmlName.getNamespace(tag, getFile());
final XmlAttribute attribute = tag.getAttribute(description.getXmlName().getLocalName(), ns.equals(tag.getNamespace())? null:ns);
-
+
if (attribute != null) {
PsiUtilCore.ensureValid(attribute);
AttributeChildInvocationHandler semElement =
diff --git a/xml/dom-impl/src/com/intellij/util/xml/impl/IndexedElementInvocationHandler.java b/xml/dom-impl/src/com/intellij/util/xml/impl/IndexedElementInvocationHandler.java
index b77a838eb0ec..9a90fbf0fcec 100644
--- a/xml/dom-impl/src/com/intellij/util/xml/impl/IndexedElementInvocationHandler.java
+++ b/xml/dom-impl/src/com/intellij/util/xml/impl/IndexedElementInvocationHandler.java
@@ -44,7 +44,7 @@ public class IndexedElementInvocationHandler extends DomInvocationHandler<FixedC
final DomParentStrategy strategy,
final DomManagerImpl manager,
@Nullable ElementStub stub) {
- super(description.getType(), strategy, tagName, description, manager, strategy.getXmlElement() != null, stub);
+ super(description.getType(), strategy, tagName, description, manager, strategy.isPhysical(), stub);
myIndex = index;
}
diff --git a/xml/dom-impl/src/com/intellij/util/xml/stubs/StubParentStrategy.java b/xml/dom-impl/src/com/intellij/util/xml/stubs/StubParentStrategy.java
index b827c6221746..951c6f576249 100644
--- a/xml/dom-impl/src/com/intellij/util/xml/stubs/StubParentStrategy.java
+++ b/xml/dom-impl/src/com/intellij/util/xml/stubs/StubParentStrategy.java
@@ -20,6 +20,7 @@ import com.intellij.psi.xml.XmlElement;
import com.intellij.psi.xml.XmlFile;
import com.intellij.psi.xml.XmlTag;
import com.intellij.util.xml.impl.*;
+import com.intellij.xml.util.XmlUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -32,6 +33,11 @@ import java.util.List;
public class StubParentStrategy implements DomParentStrategy {
private final static Logger LOG = Logger.getInstance(StubParentStrategy.class);
+ protected final DomStub myStub;
+
+ public StubParentStrategy(@NotNull DomStub stub) {
+ myStub = stub;
+ }
public static StubParentStrategy createAttributeStrategy(@Nullable AttributeStub stub, @NotNull final DomStub parent) {
if (stub == null) {
@@ -59,12 +65,6 @@ public class StubParentStrategy implements DomParentStrategy {
}
}
- protected final DomStub myStub;
-
- public StubParentStrategy(@NotNull DomStub stub) {
- myStub = stub;
- }
-
@Override
public DomInvocationHandler getParentHandler() {
DomStub parentStub = myStub.getParentStub();
@@ -82,7 +82,14 @@ public class StubParentStrategy implements DomParentStrategy {
// for custom elements, namespace information is lost
// todo: propagate ns info through DomChildDescriptions
- XmlTag[] tags = parentTag.getSubTags();
+ XmlTag[] tags;
+ try {
+ XmlUtil.BUILDING_DOM_STUBS.set(true);
+ tags = parentTag.getSubTags();
+ }
+ finally {
+ XmlUtil.BUILDING_DOM_STUBS.set(false);
+ }
int i = 0;
String nameToFind = myStub.getName();
diff --git a/xml/dom-tests/tests/com/intellij/util/xml/stubs/DomStubTest.java b/xml/dom-tests/tests/com/intellij/util/xml/stubs/DomStubTest.java
index d0c2174c01d0..a31bc6650aac 100644
--- a/xml/dom-tests/tests/com/intellij/util/xml/stubs/DomStubTest.java
+++ b/xml/dom-tests/tests/com/intellij/util/xml/stubs/DomStubTest.java
@@ -52,6 +52,19 @@ public abstract class DomStubTest extends LightCodeInsightFixtureTestCase {
}
};
+ public static ElementStub getRootStub(@TestDataFile String filePath, JavaCodeInsightTestFixture fixture) {
+ PsiFile psiFile = fixture.configureByFile(filePath);
+
+ StubTreeLoader loader = StubTreeLoader.getInstance();
+ VirtualFile file = psiFile.getVirtualFile();
+ assertTrue(loader.canHaveStub(file));
+ ObjectStubTree stubTree = loader.readFromVFile(fixture.getProject(), file);
+ assertNotNull(stubTree);
+ ElementStub root = (ElementStub)stubTree.getRoot();
+ assertNotNull(root);
+ return root;
+ }
+
@Override
public void setUp() throws Exception {
super.setUp();
@@ -67,19 +80,6 @@ public abstract class DomStubTest extends LightCodeInsightFixtureTestCase {
return getRootStub(filePath, myFixture);
}
- public static ElementStub getRootStub(@TestDataFile String filePath, JavaCodeInsightTestFixture fixture) {
- PsiFile psiFile = fixture.configureByFile(filePath);
-
- StubTreeLoader loader = StubTreeLoader.getInstance();
- VirtualFile file = psiFile.getVirtualFile();
- assertTrue(loader.canHaveStub(file));
- ObjectStubTree stubTree = loader.readFromVFile(fixture.getProject(), file);
- assertNotNull(stubTree);
- ElementStub root = (ElementStub)stubTree.getRoot();
- assertNotNull(root);
- return root;
- }
-
protected void doBuilderTest(@TestDataFile String file, String stubText) {
ElementStub stub = getRootStub(file);
assertEquals(stubText, DebugUtil.stubTreeToString(stub));
@@ -99,7 +99,7 @@ public abstract class DomStubTest extends LightCodeInsightFixtureTestCase {
XmlFile file = (XmlFile)((PsiManagerEx)getPsiManager()).getFileManager().findFile(virtualFile);
assertFalse(file.getNode().isParsed());
ObjectStubTree tree = StubTreeLoader.getInstance().readOrBuild(getProject(), virtualFile, file);
- assertNotNull(tree);
+ assertNotNull("Can't build stubs for " + path, tree);
((PsiManagerImpl)getPsiManager()).cleanupForNextTest();
diff --git a/xml/impl/src/com/intellij/application/options/editor/WebEditorOptionsForm.form b/xml/impl/src/com/intellij/application/options/editor/WebEditorOptionsForm.form
index bccba832488c..c24cc51f68f9 100644
--- a/xml/impl/src/com/intellij/application/options/editor/WebEditorOptionsForm.form
+++ b/xml/impl/src/com/intellij/application/options/editor/WebEditorOptionsForm.form
@@ -8,7 +8,7 @@
<properties/>
<border type="none"/>
<children>
- <grid id="247ce" layout-manager="GridLayoutManager" row-count="5" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
+ <grid id="247ce" layout-manager="GridLayoutManager" row-count="6" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="8" fill="2" indent="0" use-parent-layout="false"/>
@@ -24,7 +24,7 @@
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
- <text value="Automatically insert closing tag"/>
+ <text value="Insert closing tag on tag completion"/>
</properties>
</component>
<component id="9f825" class="javax.swing.JCheckBox" binding="myAutomaticallyInsertRequiredAttributesCheckBox" default-binding="true">
@@ -32,7 +32,7 @@
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
- <text value="Automatically insert required attributes"/>
+ <text value="Insert required attributes on tag completion"/>
</properties>
</component>
<component id="4bf74" class="javax.swing.JCheckBox" binding="myAutomaticallyStartAttributeAfterCheckBox" default-binding="true">
@@ -41,7 +41,7 @@
</constraints>
<properties>
<selected value="false"/>
- <text value="Automatically start attribute"/>
+ <text value="Start attribute on tag completion"/>
</properties>
</component>
<component id="c21d3" class="javax.swing.JCheckBox" binding="myAutomaticallyInsertRequiredSubTagsCheckBox" default-binding="true">
@@ -49,7 +49,7 @@
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
- <text value="Automatically insert required subtags"/>
+ <text value="Insert required subtags on tag completion"/>
</properties>
</component>
<component id="8169b" class="com.intellij.ui.components.JBCheckBox" binding="myAddQuotasForAttributeValue">
@@ -57,7 +57,16 @@
<grid row="4" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
- <text value="Automatically add quotes for attribute value"/>
+ <text value="Add quotes for attribute value on typing '='"/>
+ </properties>
+ </component>
+ <component id="76e81" class="com.intellij.ui.components.JBCheckBox" binding="myAutoCloseTagCheckBox">
+ <constraints>
+ <grid row="5" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
+ </constraints>
+ <properties>
+ <horizontalAlignment value="2"/>
+ <text value="Auto-close tag on typing '&lt;/'"/>
</properties>
</component>
</children>
diff --git a/xml/impl/src/com/intellij/application/options/editor/WebEditorOptionsProvider.java b/xml/impl/src/com/intellij/application/options/editor/WebEditorOptionsProvider.java
index 1341f95acd16..2202cc561c96 100644
--- a/xml/impl/src/com/intellij/application/options/editor/WebEditorOptionsProvider.java
+++ b/xml/impl/src/com/intellij/application/options/editor/WebEditorOptionsProvider.java
@@ -33,6 +33,7 @@ public class WebEditorOptionsProvider implements EditorOptionsProvider {
private JCheckBox myAutomaticallyStartAttributeAfterCheckBox;
private JBCheckBox mySelectWholeCssIdentifierOnDoubleClick;
private JBCheckBox myAddQuotasForAttributeValue;
+ private JBCheckBox myAutoCloseTagCheckBox;
@Override
@@ -58,7 +59,8 @@ public class WebEditorOptionsProvider implements EditorOptionsProvider {
xmlEditorOptions.isAutomaticallyStartAttribute() != myAutomaticallyStartAttributeAfterCheckBox.isSelected() ||
xmlEditorOptions.isSelectWholeCssIdentifierOnDoubleClick() != mySelectWholeCssIdentifierOnDoubleClick.isSelected() ||
xmlEditorOptions.isAutomaticallyInsertRequiredSubTags() != myAutomaticallyInsertRequiredSubTagsCheckBox.isSelected() ||
- xmlEditorOptions.isInsertQuotesForAttributeValue() != myAddQuotasForAttributeValue.isSelected();
+ xmlEditorOptions.isInsertQuotesForAttributeValue() != myAddQuotasForAttributeValue.isSelected() ||
+ xmlEditorOptions.isAutoCloseTag() != myAutoCloseTagCheckBox.isSelected();
}
@Override
@@ -70,6 +72,7 @@ public class WebEditorOptionsProvider implements EditorOptionsProvider {
xmlEditorOptions.setAutomaticallyStartAttribute(myAutomaticallyStartAttributeAfterCheckBox.isSelected());
xmlEditorOptions.setSelectWholeCssIdentifierOnDoubleClick(mySelectWholeCssIdentifierOnDoubleClick.isSelected());
xmlEditorOptions.setInsertQuotesForAttributeValue(myAddQuotasForAttributeValue.isSelected());
+ xmlEditorOptions.setAutoCloseTag(myAutoCloseTagCheckBox.isSelected());
}
@Override
@@ -81,6 +84,7 @@ public class WebEditorOptionsProvider implements EditorOptionsProvider {
myAutomaticallyStartAttributeAfterCheckBox.setSelected(xmlEditorOptions.isAutomaticallyStartAttribute());
mySelectWholeCssIdentifierOnDoubleClick.setSelected(xmlEditorOptions.isSelectWholeCssIdentifierOnDoubleClick());
myAddQuotasForAttributeValue.setSelected(xmlEditorOptions.isInsertQuotesForAttributeValue());
+ myAutoCloseTagCheckBox.setSelected(xmlEditorOptions.isAutoCloseTag());
}
@Override
diff --git a/xml/impl/src/com/intellij/codeInsight/editorActions/XmlEqTypedHandler.java b/xml/impl/src/com/intellij/codeInsight/editorActions/XmlEqTypedHandler.java
index 656a061b9b4a..bd0d76c42d38 100644
--- a/xml/impl/src/com/intellij/codeInsight/editorActions/XmlEqTypedHandler.java
+++ b/xml/impl/src/com/intellij/codeInsight/editorActions/XmlEqTypedHandler.java
@@ -38,7 +38,7 @@ public class XmlEqTypedHandler extends TypedHandlerDelegate {
PsiElement at = file.findElementAt(editor.getCaretModel().getOffset() - 1);
PsiElement atParent = at != null ? at.getParent() : null;
if(atParent instanceof XmlAttribute && ((XmlAttribute)atParent).getValueElement() == null) {
- needToInsertQuotes = atParent instanceof XmlAttribute && ((XmlAttribute)atParent).getValueElement() == null;
+ needToInsertQuotes = ((XmlAttribute)atParent).getValueElement() == null;
}
}
}
diff --git a/xml/impl/src/com/intellij/codeInsight/editorActions/XmlSlashTypedHandler.java b/xml/impl/src/com/intellij/codeInsight/editorActions/XmlSlashTypedHandler.java
index c5e0ff307a94..729e6062c626 100644
--- a/xml/impl/src/com/intellij/codeInsight/editorActions/XmlSlashTypedHandler.java
+++ b/xml/impl/src/com/intellij/codeInsight/editorActions/XmlSlashTypedHandler.java
@@ -15,6 +15,7 @@
*/
package com.intellij.codeInsight.editorActions;
+import com.intellij.application.options.editor.WebEditorOptions;
import com.intellij.lang.ASTNode;
import com.intellij.lang.xml.XMLLanguage;
import com.intellij.openapi.editor.Editor;
@@ -71,6 +72,7 @@ public class XmlSlashTypedHandler extends TypedHandlerDelegate {
@Override
public Result charTyped(final char c, final Project project, @NotNull final Editor editor, @NotNull final PsiFile editedFile) {
+ if (!WebEditorOptions.getInstance().isAutoCloseTag()) return Result.CONTINUE;
if ((editedFile.getLanguage() instanceof XMLLanguage || editedFile.getViewProvider().getBaseLanguage() instanceof XMLLanguage) && c == '/') {
PsiDocumentManager.getInstance(project).commitAllDocuments();
diff --git a/xml/impl/src/com/intellij/codeInsight/template/emmet/EmmetParser.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/EmmetParser.java
index 6bc71f9f8549..aa7e62cbcd54 100644
--- a/xml/impl/src/com/intellij/codeInsight/template/emmet/EmmetParser.java
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/EmmetParser.java
@@ -80,6 +80,10 @@ public abstract class EmmetParser {
ZenCodingNode mul = parseMul();
ZenCodingToken operationToken = getToken();
+ if (operationToken == ZenCodingTokens.OPENING_R_BRACKET) {
+ mul = new MoreOperationNode(notNullNode(mul), parseExpression());
+ operationToken = getToken();
+ }
if (!(operationToken instanceof OperationToken)) {
return mul;
}
@@ -132,7 +136,7 @@ public abstract class EmmetParser {
@Nullable
private ZenCodingNode parseMul() {
- ZenCodingNode exp = parseExpressionInBraces();
+ ZenCodingNode exp = parseExpression();
if (exp == null) {
return null;
}
@@ -153,7 +157,7 @@ public abstract class EmmetParser {
}
@Nullable
- private ZenCodingNode parseExpressionInBraces() {
+ private ZenCodingNode parseExpression() {
ZenCodingToken token = getToken();
if (token == ZenCodingTokens.OPENING_R_BRACKET) {
advance();
diff --git a/xml/impl/src/com/intellij/codeInsight/template/emmet/XmlEmmetParser.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/XmlEmmetParser.java
index 4ab715a404bf..01ddc3ca563f 100644
--- a/xml/impl/src/com/intellij/codeInsight/template/emmet/XmlEmmetParser.java
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/XmlEmmetParser.java
@@ -202,7 +202,7 @@ public class XmlEmmetParser extends EmmetParser {
int loremWordsCount = DEFAULT_LOREM_LENGTH;
if (matcher.groupCount() > 1) {
String group = matcher.group(2);
- loremWordsCount = group.isEmpty() ? DEFAULT_LOREM_LENGTH : Integer.parseInt(group);
+ loremWordsCount = group == null || group.isEmpty() ? DEFAULT_LOREM_LENGTH : Integer.parseInt(group);
}
final List<Couple<String>> attrList = parseSelectors();
diff --git a/xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/MoreOperationNode.java b/xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/MoreOperationNode.java
index 0a1bea140d6b..56d440abc538 100644
--- a/xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/MoreOperationNode.java
+++ b/xml/impl/src/com/intellij/codeInsight/template/emmet/nodes/MoreOperationNode.java
@@ -89,8 +89,12 @@ public class MoreOperationNode extends ZenCodingNode {
}
return result;
}
- List<GenerationNode> leftGenNodes = myLeftOperand.expand(numberInIteration, totalIterations, surroundedText, callback, insertSurroundedTextAtTheEnd,
- parent);
+ List<GenerationNode> leftGenNodes = myLeftOperand.expand(numberInIteration, totalIterations, surroundedText, callback, insertSurroundedTextAtTheEnd, parent);
+
+ if (leftGenNodes.isEmpty()) {
+ return myRightOperand.expand(numberInIteration, totalIterations, surroundedText, callback, insertSurroundedTextAtTheEnd, parent);
+ }
+
for (GenerationNode leftGenNode : leftGenNodes) {
myRightOperand.expand(numberInIteration,totalIterations , surroundedText, callback, insertSurroundedTextAtTheEnd, leftGenNode);
}
diff --git a/xml/impl/src/com/intellij/xml/arrangement/XmlArrangementVisitor.java b/xml/impl/src/com/intellij/xml/arrangement/XmlArrangementVisitor.java
index 7f118e889588..4055b9cffb9f 100644
--- a/xml/impl/src/com/intellij/xml/arrangement/XmlArrangementVisitor.java
+++ b/xml/impl/src/com/intellij/xml/arrangement/XmlArrangementVisitor.java
@@ -74,7 +74,7 @@ public class XmlArrangementVisitor extends XmlElementVisitor {
@Nullable String name,
@Nullable String namespace,
boolean canBeMatched) {
- if (!isWithinBounds(range)) {
+ if (range.getStartOffset() == 0 && range.getEndOffset() == 0 || !isWithinBounds(range)) {
return null;
}
final DefaultArrangementEntry current = getCurrent();
diff --git a/xml/impl/src/com/intellij/xml/refactoring/SchemaPrefixRenameHandler.java b/xml/impl/src/com/intellij/xml/refactoring/SchemaPrefixRenameHandler.java
index bc4ba667afa4..2c1f5a781fcb 100644
--- a/xml/impl/src/com/intellij/xml/refactoring/SchemaPrefixRenameHandler.java
+++ b/xml/impl/src/com/intellij/xml/refactoring/SchemaPrefixRenameHandler.java
@@ -15,7 +15,6 @@
*/
package com.intellij.xml.refactoring;
-import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
@@ -35,12 +34,6 @@ import java.util.Collection;
*/
public class SchemaPrefixRenameHandler extends VariableInplaceRenameHandler {
- @Override
- protected boolean isAvailable(PsiElement element, Editor editor, PsiFile file) {
- PossiblePrefixReference ref = getReference(file, editor);
- return ref != null && ref.resolve() instanceof SchemaPrefix;
- }
-
@Nullable
private static PossiblePrefixReference getReference(PsiFile file, Editor editor) {
if (file != null && editor != null) {
@@ -55,6 +48,12 @@ public class SchemaPrefixRenameHandler extends VariableInplaceRenameHandler {
}
@Override
+ protected boolean isAvailable(PsiElement element, Editor editor, PsiFile file) {
+ PossiblePrefixReference ref = getReference(file, editor);
+ return ref != null && ref.resolve() instanceof SchemaPrefix;
+ }
+
+ @Override
protected VariableInplaceRenamer createRenamer(@NotNull PsiElement elementToRename, Editor editor) {
PossiblePrefixReference reference = getReference(elementToRename.getContainingFile(), editor);
if (reference != null) {
@@ -71,12 +70,6 @@ public class SchemaPrefixRenameHandler extends VariableInplaceRenameHandler {
};
}
}
- if (ApplicationManager.getApplication().isUnitTestMode()) {
- System.out.println("Reference: " + reference);
- if (reference != null) {
- System.out.println("Resolved: " + reference.resolve());
- }
- }
return null;
}
}
diff --git a/xml/impl/src/com/intellij/xml/refactoring/XmlInlineHandler.java b/xml/impl/src/com/intellij/xml/refactoring/XmlInlineHandler.java
index bd3b6b0c8c80..865805796322 100644
--- a/xml/impl/src/com/intellij/xml/refactoring/XmlInlineHandler.java
+++ b/xml/impl/src/com/intellij/xml/refactoring/XmlInlineHandler.java
@@ -3,22 +3,23 @@ package com.intellij.xml.refactoring;
import com.intellij.lang.refactoring.InlineHandler;
import com.intellij.openapi.editor.Editor;
import com.intellij.psi.PsiElement;
+import org.jetbrains.annotations.NotNull;
/**
* @author Eugene.Kudelevsky
*/
public class XmlInlineHandler implements InlineHandler {
@Override
- public Settings prepareInlineElement(PsiElement element, Editor editor, boolean invokedOnReference) {
+ public Settings prepareInlineElement(@NotNull PsiElement element, Editor editor, boolean invokedOnReference) {
return null;
}
@Override
- public void removeDefinition(PsiElement element, Settings settings) {
+ public void removeDefinition(@NotNull PsiElement element, @NotNull Settings settings) {
}
@Override
- public Inliner createInliner(PsiElement element, Settings settings) {
+ public Inliner createInliner(@NotNull PsiElement element, @NotNull Settings settings) {
return null;
}
}
diff --git a/xml/impl/src/org/jetbrains/io/fastCgi/FastCgiChannelHandler.java b/xml/impl/src/org/jetbrains/io/fastCgi/FastCgiChannelHandler.java
index d24078221b30..4a83b637500e 100644
--- a/xml/impl/src/org/jetbrains/io/fastCgi/FastCgiChannelHandler.java
+++ b/xml/impl/src/org/jetbrains/io/fastCgi/FastCgiChannelHandler.java
@@ -92,7 +92,14 @@ public class FastCgiChannelHandler extends SimpleChannelInboundHandlerAdapter<Fa
String value = builder.toString();
if (key.equalsIgnoreCase("status")) {
- response.setStatus(HttpResponseStatus.valueOf(Integer.parseInt(value.substring(0, value.indexOf(' ')))));
+ int index = value.indexOf(' ');
+ if (index == -1) {
+ LOG.warn("Cannot parse status: " + value);
+ response.setStatus(HttpResponseStatus.OK);
+ }
+ else {
+ response.setStatus(HttpResponseStatus.valueOf(Integer.parseInt(value.substring(0, index))));
+ }
}
else if (!(key.startsWith("http") || key.startsWith("HTTP"))) {
response.headers().add(key, value);
diff --git a/xml/relaxng/src/org/intellij/html/RelaxedHtmlFromRngElementDescriptor.java b/xml/relaxng/src/org/intellij/html/RelaxedHtmlFromRngElementDescriptor.java
index 08ada22129d9..b287e6b50777 100644
--- a/xml/relaxng/src/org/intellij/html/RelaxedHtmlFromRngElementDescriptor.java
+++ b/xml/relaxng/src/org/intellij/html/RelaxedHtmlFromRngElementDescriptor.java
@@ -69,6 +69,9 @@ public class RelaxedHtmlFromRngElementDescriptor implements XmlElementDescriptor
@Override
public XmlAttributeDescriptor getAttributeDescriptor(XmlAttribute attribute) {
+ XmlAttributeDescriptor descriptor = myDelegate.getAttributeDescriptor(attribute);
+ if (descriptor != null) return descriptor;
+
return getAttributeDescriptor(attribute.getName(), attribute.getParent());
}
diff --git a/xml/relaxng/src/org/intellij/plugins/relaxNG/convert/ConvertSchemaSettingsImpl.java b/xml/relaxng/src/org/intellij/plugins/relaxNG/convert/ConvertSchemaSettingsImpl.java
index 56fe4c92f733..3161c522b586 100644
--- a/xml/relaxng/src/org/intellij/plugins/relaxNG/convert/ConvertSchemaSettingsImpl.java
+++ b/xml/relaxng/src/org/intellij/plugins/relaxNG/convert/ConvertSchemaSettingsImpl.java
@@ -131,7 +131,7 @@ public class ConvertSchemaSettingsImpl implements ConvertSchemaSettings {
final int indent = styleSettings.getIndentSize(type);
myIndent.setText(String.valueOf(indent));
- myLineLength.setText(String.valueOf(styleSettings.RIGHT_MARGIN));
+ myLineLength.setText(String.valueOf(styleSettings.getDefaultRightMargin()));
final SchemaType outputType = getOutputType();
myLineLength.setEnabled(outputType == SchemaType.DTD || outputType == SchemaType.RNC);
diff --git a/xml/relaxng/src/resources/html5-schema/html5-svg-mathml.rnc b/xml/relaxng/src/resources/html5-schema/html5-svg-mathml.rnc
index fe154b8f57bf..095868dee70a 100644
--- a/xml/relaxng/src/resources/html5-schema/html5-svg-mathml.rnc
+++ b/xml/relaxng/src/resources/html5-schema/html5-svg-mathml.rnc
@@ -1,7 +1,7 @@
namespace svg = "http://www.w3.org/2000/svg"
namespace math = "http://www.w3.org/1998/Math/MathML"
-include "svg11/svg11-tiny-inc.rnc"
+include "svg11/svg11-inc.rnc"
include "mml3/mathml3-inc.rnc"
common.elem.phrasing |= svg
diff --git a/xml/relaxng/src/resources/html5-schema/xhtml5-svg-mathml.rnc b/xml/relaxng/src/resources/html5-schema/xhtml5-svg-mathml.rnc
index 74f188644741..98d6fbd597e4 100644
--- a/xml/relaxng/src/resources/html5-schema/xhtml5-svg-mathml.rnc
+++ b/xml/relaxng/src/resources/html5-schema/xhtml5-svg-mathml.rnc
@@ -2,7 +2,7 @@ namespace svg = "http://www.w3.org/2000/svg"
namespace math = "http://www.w3.org/1998/Math/MathML"
namespace rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-include "svg11/svg11-tiny-inc.rnc"
+include "svg11/svg11-inc.rnc"
include "inkscape/inkscape.rnc"
include "mml3/mathml3-inc.rnc"
include "rdf/rdf.rnc"
diff --git a/xml/relaxng/src/resources/patches/0007_html5_svg_tiny.patch b/xml/relaxng/src/resources/patches/0007_html5_svg_tiny.patch
deleted file mode 100644
index 6a3cc10cc8e2..000000000000
--- a/xml/relaxng/src/resources/patches/0007_html5_svg_tiny.patch
+++ /dev/null
@@ -1,11 +0,0 @@
---- /Users/denofevil/Code/sandbox/checker/validator/schema/html5-svg-mathml.rnc 2014-01-24 12:18:54.000000000 +0400
-+++ html5-svg-mathml.rnc 2014-01-25 15:32:10.000000000 +0400
-@@ -1,7 +1,7 @@
- namespace svg = "http://www.w3.org/2000/svg"
- namespace math = "http://www.w3.org/1998/Math/MathML"
-
--include "svg11/svg11-inc.rnc"
-+include "svg11/svg11-tiny-inc.rnc"
- include "mml3/mathml3-inc.rnc"
-
- common.elem.phrasing |= svg
diff --git a/xml/relaxng/src/resources/patches/0008_xhtml5_svg_tiny.patch b/xml/relaxng/src/resources/patches/0008_xhtml5_svg_tiny.patch
deleted file mode 100644
index 773c8969c177..000000000000
--- a/xml/relaxng/src/resources/patches/0008_xhtml5_svg_tiny.patch
+++ /dev/null
@@ -1,11 +0,0 @@
---- /Users/denofevil/Code/sandbox/checker/validator/schema/xhtml5-svg-mathml.rnc 2014-01-24 12:18:54.000000000 +0400
-+++ xhtml5-svg-mathml.rnc 2014-01-25 15:50:41.000000000 +0400
-@@ -2,7 +2,7 @@
- namespace math = "http://www.w3.org/1998/Math/MathML"
- namespace rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-
--include "svg11/svg11-inc.rnc"
-+include "svg11/svg11-tiny-inc.rnc"
- include "inkscape/inkscape.rnc"
- include "mml3/mathml3-inc.rnc"
- include "rdf/rdf.rnc"
diff --git a/xml/xml-analysis-impl/src/com/intellij/application/options/editor/WebEditorOptions.java b/xml/xml-analysis-impl/src/com/intellij/application/options/editor/WebEditorOptions.java
index c658068ae88e..a5222d701c35 100644
--- a/xml/xml-analysis-impl/src/com/intellij/application/options/editor/WebEditorOptions.java
+++ b/xml/xml-analysis-impl/src/com/intellij/application/options/editor/WebEditorOptions.java
@@ -44,6 +44,7 @@ public class WebEditorOptions implements PersistentStateComponent<WebEditorOptio
private boolean myAutomaticallyInsertClosingTag = true;
private boolean myAutomaticallyInsertRequiredAttributes = true;
private boolean myAutomaticallyInsertRequiredSubTags = true;
+ private boolean myAutoCloseTag = true;
private boolean myAutomaticallyStartAttribute = true;
private boolean myInsertQuotesForAttributeValue = true;
@@ -51,30 +52,30 @@ public class WebEditorOptions implements PersistentStateComponent<WebEditorOptio
private int myTagTreeHighlightingLevelCount = 6;
private int myTagTreeHighlightingOpacity = 10;
- public static WebEditorOptions getInstance() {
- return ServiceManager.getService(WebEditorOptions.class);
- }
-
public WebEditorOptions() {
setTagTreeHighlightingEnabled(!ApplicationManager.getApplication().isUnitTestMode());
}
- public void setBreadcrumbsEnabled(boolean b) {
- myBreadcrumbsEnabled = b;
+ public static WebEditorOptions getInstance() {
+ return ServiceManager.getService(WebEditorOptions.class);
}
public boolean isBreadcrumbsEnabled() {
return myBreadcrumbsEnabled;
}
- public void setBreadcrumbsEnabledInXml(boolean b) {
- myBreadcrumbsEnabledInXml = b;
+ public void setBreadcrumbsEnabled(boolean b) {
+ myBreadcrumbsEnabled = b;
}
public boolean isBreadcrumbsEnabledInXml() {
return myBreadcrumbsEnabledInXml;
}
+ public void setBreadcrumbsEnabledInXml(boolean b) {
+ myBreadcrumbsEnabledInXml = b;
+ }
+
public boolean isShowCssInlineColorPreview() {
return myShowCssInlineColorPreview;
}
@@ -121,30 +122,30 @@ public class WebEditorOptions implements PersistentStateComponent<WebEditorOptio
myAutomaticallyInsertRequiredSubTags = automaticallyInsertRequiredSubTags;
}
- public void setTagTreeHighlightingLevelCount(int tagTreeHighlightingLevelCount) {
- myTagTreeHighlightingLevelCount = tagTreeHighlightingLevelCount;
- }
-
public int getTagTreeHighlightingLevelCount() {
return myTagTreeHighlightingLevelCount;
}
- public void setTagTreeHighlightingOpacity(int tagTreeHighlightingOpacity) {
- myTagTreeHighlightingOpacity = tagTreeHighlightingOpacity;
+ public void setTagTreeHighlightingLevelCount(int tagTreeHighlightingLevelCount) {
+ myTagTreeHighlightingLevelCount = tagTreeHighlightingLevelCount;
}
public int getTagTreeHighlightingOpacity() {
return myTagTreeHighlightingOpacity;
}
- public void setTagTreeHighlightingEnabled(boolean tagTreeHighlightingEnabled) {
- myTagTreeHighlightingEnabled = tagTreeHighlightingEnabled;
+ public void setTagTreeHighlightingOpacity(int tagTreeHighlightingOpacity) {
+ myTagTreeHighlightingOpacity = tagTreeHighlightingOpacity;
}
public boolean isTagTreeHighlightingEnabled() {
return myTagTreeHighlightingEnabled;
}
+ public void setTagTreeHighlightingEnabled(boolean tagTreeHighlightingEnabled) {
+ myTagTreeHighlightingEnabled = tagTreeHighlightingEnabled;
+ }
+
@Override
@NotNull
public File[] getExportFiles() {
@@ -193,4 +194,12 @@ public class WebEditorOptions implements PersistentStateComponent<WebEditorOptio
public void setInsertQuotesForAttributeValue(boolean insertQuotesForAttributeValue) {
myInsertQuotesForAttributeValue = insertQuotesForAttributeValue;
}
+
+ public boolean isAutoCloseTag() {
+ return myAutoCloseTag;
+ }
+
+ public void setAutoCloseTag(boolean autoCloseTag) {
+ myAutoCloseTag = autoCloseTag;
+ }
}
diff --git a/xml/xml-analysis-impl/src/com/intellij/xml/util/XmlRefCountHolder.java b/xml/xml-analysis-impl/src/com/intellij/xml/util/XmlRefCountHolder.java
index a5f70c2227dc..a9f91bce7d8b 100644
--- a/xml/xml-analysis-impl/src/com/intellij/xml/util/XmlRefCountHolder.java
+++ b/xml/xml-analysis-impl/src/com/intellij/xml/util/XmlRefCountHolder.java
@@ -105,10 +105,24 @@ public class XmlRefCountHolder {
myId2AttributeListMap.put(id, list);
}
else if (!soft) {
+ final boolean html = HtmlUtil.isHtmlFile(attributeValue);
+ final boolean html5 = HtmlUtil.isHtml5Context(attributeValue);
+
// mark as duplicate
List<XmlAttributeValue> notSoft = ContainerUtil.mapNotNull(list, new NullableFunction<Pair<XmlAttributeValue, Boolean>, XmlAttributeValue>() {
@Override
public XmlAttributeValue fun(Pair<XmlAttributeValue, Boolean> pair) {
+ if (html5 && !"id".equalsIgnoreCase(((XmlAttribute)pair.first.getParent()).getName())) {
+ // according to HTML 5 (http://www.w3.org/TR/html5/dom.html#the-id-attribute) spec
+ // only id attribute is unique identifier
+ return null;
+ }
+ if (html && pair.first.getParent().getParent() == attributeValue.getParent().getParent()) {
+ // according to HTML 4 (http://www.w3.org/TR/html401/struct/global.html#adef-id,
+ // http://www.w3.org/TR/html401/struct/links.html#h-12.2.3) spec id and name occupy
+ // same namespace, but having same values on one tag is ok
+ return null;
+ }
return pair.second ? null : pair.first;
}
});
diff --git a/xml/xml-psi-impl/resources/standardSchemas/xlink.dtd b/xml/xml-psi-impl/resources/standardSchemas/xlink.dtd
new file mode 100644
index 000000000000..1a8f153e55db
--- /dev/null
+++ b/xml/xml-psi-impl/resources/standardSchemas/xlink.dtd
@@ -0,0 +1,66 @@
+<!ELEMENT simple ANY>
+<!ATTLIST simple
+ xlink:type (simple) #FIXED "simple"
+ xlink:href CDATA #IMPLIED
+ xlink:role CDATA #IMPLIED
+ xlink:arcrole CDATA #IMPLIED
+ xlink:title CDATA #IMPLIED
+ xlink:show (new
+ |replace
+ |embed
+ |other
+ |none) #IMPLIED
+ xlink:actuate (onLoad
+ |onRequest
+ |other
+ |none) #IMPLIED>
+
+<!ELEMENT extended ((title|resource|locator|arc)*)>
+<!ATTLIST extended
+ xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink"
+ xlink:type (extended) #FIXED "extended"
+ xlink:role CDATA #IMPLIED
+ xlink:title CDATA #IMPLIED>
+
+<!ELEMENT title ANY>
+<!-- xml:lang is not required, but provides much of the motivation
+ for title elements in addition to attributes, and so is provided
+ here for convenience -->
+<!ATTLIST title
+ xlink:type (title) #FIXED "title"
+ xml:lang CDATA #IMPLIED>
+
+<!ELEMENT resource ANY>
+<!ATTLIST resource
+ xlink:type (resource) #FIXED "resource"
+ xlink:role CDATA #IMPLIED
+ xlink:title CDATA #IMPLIED
+ xlink:label NMTOKEN #IMPLIED>
+
+<!ELEMENT locator (title*)>
+<!-- label is not required, but locators have no particular XLink
+ function if they are not labeled -->
+<!ATTLIST locator
+ xlink:type (locator) #FIXED "locator"
+ xlink:href CDATA #REQUIRED
+ xlink:role CDATA #IMPLIED
+ xlink:title CDATA #IMPLIED
+ xlink:label NMTOKEN #IMPLIED>
+
+<!ELEMENT arc (title*)>
+<!-- from and to have default behavior when values are missing -->
+<!ATTLIST arc
+ xlink:type (arc) #FIXED "arc"
+ xlink:arcrole CDATA #IMPLIED
+ xlink:title CDATA #IMPLIED
+ xlink:show (new
+ |replace
+ |embed
+ |other
+ |none) #IMPLIED
+ xlink:actuate (onLoad
+ |onRequest
+ |other
+ |none) #IMPLIED
+ xlink:from NMTOKEN #IMPLIED
+ xlink:to NMTOKEN #IMPLIED> \ No newline at end of file
diff --git a/xml/xml-psi-impl/src/com/intellij/javaee/ExternalResourceManagerExImpl.java b/xml/xml-psi-impl/src/com/intellij/javaee/ExternalResourceManagerExImpl.java
index d030ccf9f189..13cfa9e13d2a 100644
--- a/xml/xml-psi-impl/src/com/intellij/javaee/ExternalResourceManagerExImpl.java
+++ b/xml/xml-psi-impl/src/com/intellij/javaee/ExternalResourceManagerExImpl.java
@@ -24,7 +24,10 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.*;
+import com.intellij.openapi.util.AtomicNotNullLazyValue;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.util.NotNullLazyKey;
+import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
@@ -46,9 +49,9 @@ import java.net.URL;
import java.util.*;
@State(name = "ExternalResourceManagerImpl",
- storages = {@Storage( file = StoragePathMacros.APP_CONFIG + "/other.xml")})
-public class ExternalResourceManagerExImpl extends ExternalResourceManagerEx implements JDOMExternalizable {
- static final Logger LOG = Logger.getInstance("#com.intellij.j2ee.openapi.impl.ExternalResourceManagerImpl");
+ storages = {@Storage(file = StoragePathMacros.APP_CONFIG + "/other.xml")})
+public class ExternalResourceManagerExImpl extends ExternalResourceManagerEx implements PersistentStateComponent<Element> {
+ static final Logger LOG = Logger.getInstance(ExternalResourceManagerExImpl.class);
@NonNls public static final String J2EE_1_3 = "http://java.sun.com/dtd/";
@NonNls public static final String J2EE_1_2 = "http://java.sun.com/j2ee/dtds/";
@@ -92,7 +95,6 @@ public class ExternalResourceManagerExImpl extends ExternalResourceManagerEx imp
}
private final List<ExternalResourceListener> myListeners = ContainerUtil.createLockFreeCopyOnWriteList();
- private final PathMacrosImpl myPathMacros;
@NonNls private static final String RESOURCE_ELEMENT = "resource";
@NonNls private static final String URL_ATTR = "url";
@NonNls private static final String LOCATION_ATTR = "location";
@@ -100,10 +102,6 @@ public class ExternalResourceManagerExImpl extends ExternalResourceManagerEx imp
@NonNls private static final String HTML_DEFAULT_DOCTYPE_ELEMENT = "default-html-doctype";
private static final String DEFAULT_VERSION = null;
- public ExternalResourceManagerExImpl(@NotNull PathMacrosImpl pathMacros) {
- myPathMacros = pathMacros;
- }
-
@Override
public boolean isStandardResource(VirtualFile file) {
VirtualFile parent = file.getParent();
@@ -374,39 +372,11 @@ public class ExternalResourceManagerExImpl extends ExternalResourceManagerEx imp
return getProjectResources(project).getModificationCount();
}
- @Override
- public void readExternal(Element element) {
- final ExpandMacroToPathMap macroExpands = new ExpandMacroToPathMap();
- myPathMacros.addMacroExpands(macroExpands);
- macroExpands.substitute(element, SystemInfo.isFileSystemCaseSensitive);
-
- incModificationCount();
- for (final Object o1 : element.getChildren(RESOURCE_ELEMENT)) {
- Element e = (Element)o1;
- addSilently(e.getAttributeValue(URL_ATTR), DEFAULT_VERSION, e.getAttributeValue(LOCATION_ATTR).replace('/', File.separatorChar));
- }
-
- for (final Object o : element.getChildren(IGNORED_RESOURCE_ELEMENT)) {
- Element e = (Element)o;
- addIgnoredSilently(e.getAttributeValue(URL_ATTR));
- }
-
- Element child = element.getChild(HTML_DEFAULT_DOCTYPE_ELEMENT);
- if (child != null) {
- String text = child.getText();
- if (FileUtil.toSystemIndependentName(text).endsWith(".jar!/resources/html5-schema/html5.rnc")) {
- text = HTML5_DOCTYPE_ELEMENT;
- }
- myDefaultHtmlDoctype = text;
- }
- Element catalogElement = element.getChild(CATALOG_PROPERTIES_ELEMENT);
- if (catalogElement != null) {
- myCatalogPropertiesFile = catalogElement.getTextTrim();
- }
- }
+ @Nullable
@Override
- public void writeExternal(Element element) {
+ public Element getState() {
+ Element element = new Element("state");
final String[] urls = getAvailableUrls();
for (String url : urls) {
if (url == null) continue;
@@ -440,9 +410,42 @@ public class ExternalResourceManagerExImpl extends ExternalResourceManagerEx imp
final ReplacePathToMacroMap macroReplacements = new ReplacePathToMacroMap();
PathMacrosImpl.getInstanceEx().addMacroReplacements(macroReplacements);
macroReplacements.substitute(element, SystemInfo.isFileSystemCaseSensitive);
+ return element;
}
@Override
+ public void loadState(Element element) {
+ final ExpandMacroToPathMap macroExpands = new ExpandMacroToPathMap();
+ PathMacrosImpl.getInstanceEx().addMacroExpands(macroExpands);
+ macroExpands.substitute(element, SystemInfo.isFileSystemCaseSensitive);
+
+ incModificationCount();
+ for (final Object o1 : element.getChildren(RESOURCE_ELEMENT)) {
+ Element e = (Element)o1;
+ addSilently(e.getAttributeValue(URL_ATTR), DEFAULT_VERSION, e.getAttributeValue(LOCATION_ATTR).replace('/', File.separatorChar));
+ }
+
+ for (final Object o : element.getChildren(IGNORED_RESOURCE_ELEMENT)) {
+ Element e = (Element)o;
+ addIgnoredSilently(e.getAttributeValue(URL_ATTR));
+ }
+
+ Element child = element.getChild(HTML_DEFAULT_DOCTYPE_ELEMENT);
+ if (child != null) {
+ String text = child.getText();
+ if (FileUtil.toSystemIndependentName(text).endsWith(".jar!/resources/html5-schema/html5.rnc")) {
+ text = HTML5_DOCTYPE_ELEMENT;
+ }
+ myDefaultHtmlDoctype = text;
+ }
+ Element catalogElement = element.getChild(CATALOG_PROPERTIES_ELEMENT);
+ if (catalogElement != null) {
+ myCatalogPropertiesFile = catalogElement.getTextTrim();
+ }
+ }
+
+
+ @Override
public void addExternalResourceListener(ExternalResourceListener listener) {
myListeners.add(listener);
}
@@ -465,7 +468,7 @@ public class ExternalResourceManagerExImpl extends ExternalResourceManagerEx imp
private static final NotNullLazyKey<ExternalResourceManagerExImpl, Project> INSTANCE_CACHE = ServiceManager.createLazyKey(ExternalResourceManagerExImpl.class);
- private ExternalResourceManagerExImpl getProjectResources(Project project) {
+ private static ExternalResourceManagerExImpl getProjectResources(Project project) {
return INSTANCE_CACHE.getValue(project);
}
diff --git a/xml/xml-psi-impl/src/com/intellij/javaee/InternalResourceProvider.java b/xml/xml-psi-impl/src/com/intellij/javaee/InternalResourceProvider.java
index 673540ef38e8..38777922ee35 100644
--- a/xml/xml-psi-impl/src/com/intellij/javaee/InternalResourceProvider.java
+++ b/xml/xml-psi-impl/src/com/intellij/javaee/InternalResourceProvider.java
@@ -63,5 +63,6 @@ public class InternalResourceProvider implements StandardResourceProvider{
// svg and mathML
impl.addIgnoredResource(HtmlUtil.MATH_ML_NAMESPACE);
impl.addIgnoredResource(HtmlUtil.SVG_NAMESPACE);
+ impl.addInternalResource("http://www.w3.org/1999/xlink", "xlink.dtd");
}
}
diff --git a/xml/xml-psi-impl/src/com/intellij/javaee/ProjectResources.java b/xml/xml-psi-impl/src/com/intellij/javaee/ProjectResources.java
index 916090996e7c..4b9541b0ebe2 100644
--- a/xml/xml-psi-impl/src/com/intellij/javaee/ProjectResources.java
+++ b/xml/xml-psi-impl/src/com/intellij/javaee/ProjectResources.java
@@ -16,42 +16,21 @@
package com.intellij.javaee;
import com.intellij.application.options.PathMacrosImpl;
-import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
import com.intellij.openapi.components.StoragePathMacros;
-import com.intellij.openapi.util.JDOMExternalizable;
-import com.intellij.openapi.util.JDOMExternalizableAdapter;
-import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import java.util.Collections;
import java.util.Map;
/**
-* @author Dmitry Avdeev
-*/
-@State(name = "ProjectResources", storages = {@Storage( file = StoragePathMacros.PROJECT_FILE)})
-public class ProjectResources extends ExternalResourceManagerExImpl implements PersistentStateComponent<Element>, JDOMExternalizable {
- private final JDOMExternalizableAdapter myAdapter;
-
- public ProjectResources(@NotNull PathMacrosImpl pathMacros) {
- super(pathMacros);
- myAdapter = new JDOMExternalizableAdapter(this, "ProjectResources");
- }
-
+ * @author Dmitry Avdeev
+ */
+@State(name = "ProjectResources", storages = {@Storage(file = StoragePathMacros.PROJECT_FILE)})
+public class ProjectResources extends ExternalResourceManagerExImpl {
@Override
protected Map<String, Map<String, Resource>> computeStdResources() {
- return Collections.emptyMap();
- }
-
- @Override
- public Element getState() {
- return myAdapter.getState();
- }
-
- @Override
- public void loadState(Element state) {
- myAdapter.loadState(state);
+ return Collections.emptyMap();
}
}
diff --git a/xml/xml-psi-impl/src/com/intellij/lexer/HtmlHighlightingLexer.java b/xml/xml-psi-impl/src/com/intellij/lexer/HtmlHighlightingLexer.java
index eeae1d318e15..1d20283aa708 100644
--- a/xml/xml-psi-impl/src/com/intellij/lexer/HtmlHighlightingLexer.java
+++ b/xml/xml-psi-impl/src/com/intellij/lexer/HtmlHighlightingLexer.java
@@ -15,74 +15,41 @@
*/
package com.intellij.lexer;
-import com.intellij.lang.*;
+import com.intellij.lang.HtmlInlineScriptTokenTypesProvider;
+import com.intellij.lang.HtmlScriptContentProvider;
+import com.intellij.lang.Language;
+import com.intellij.lang.LanguageHtmlInlineScriptTokenTypesProvider;
import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.fileTypes.*;
+import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.openapi.fileTypes.PlainTextLanguage;
+import com.intellij.openapi.fileTypes.SyntaxHighlighter;
+import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.xml.XmlTokenType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import java.util.HashMap;
+import java.util.Map;
+
public class HtmlHighlightingLexer extends BaseHtmlLexer {
private static final Logger LOG = Logger.getInstance("#com.intellij.lexer.HtmlHighlightingLexer");
private static final int EMBEDDED_LEXER_ON = 0x1 << BASE_STATE_SHIFT;
private static final int EMBEDDED_LEXER_STATE_SHIFT = BASE_STATE_SHIFT + 1;
-
- private Lexer embeddedLexer;
- private Lexer styleLexer;
- private Lexer scriptLexer;
- protected Lexer elLexer;
- private boolean hasNoEmbeddments;
- private final FileType ourStyleFileType;// = FileTypeManager.getInstance().getStdFileType("CSS");
private static final FileType ourInlineScriptFileType;
-
-
static {
// At the moment only JS.
HtmlInlineScriptTokenTypesProvider provider =
LanguageHtmlInlineScriptTokenTypesProvider.getInlineScriptProvider(Language.findLanguageByID("JavaScript"));
ourInlineScriptFileType = provider != null ? provider.getFileType() : null;
}
-
- public class XmlEmbeddmentHandler implements TokenHandler {
- @Override
- public void handleElement(Lexer lexer) {
- if (!hasSeenStyle() && !hasSeenScript() || hasNoEmbeddments) return;
- final IElementType tokenType = lexer.getTokenType();
-
- if (tokenType == XmlTokenType.XML_ATTRIBUTE_VALUE_TOKEN && hasSeenAttribute() ||
- tokenType == XmlTokenType.XML_DATA_CHARACTERS && hasSeenTag() ||
- tokenType == XmlTokenType.XML_COMMENT_CHARACTERS && hasSeenTag()
- ) {
- setEmbeddedLexer();
-
- if (embeddedLexer != null) {
- embeddedLexer.start(
- getBufferSequence(),
- HtmlHighlightingLexer.super.getTokenStart(),
- skipToTheEndOfTheEmbeddment(),
- embeddedLexer instanceof EmbedmentLexer ? ((EmbedmentLexer)embeddedLexer).getEmbeddedInitialState(tokenType) : 0
- );
-
- if (embeddedLexer.getTokenType() == null) {
- // no content for embeddment
- embeddedLexer = null;
- }
- }
- }
- }
- }
-
- public class ElEmbeddmentHandler implements TokenHandler {
- @Override
- public void handleElement(Lexer lexer) {
- setEmbeddedLexer();
- if (embeddedLexer != null) {
- embeddedLexer.start(getBufferSequence(), HtmlHighlightingLexer.super.getTokenStart(), HtmlHighlightingLexer.super.getTokenEnd());
- }
- }
- }
+ private final FileType ourStyleFileType;// = FileTypeManager.getInstance().getStdFileType("CSS");
+ protected Lexer elLexer;
+ private Lexer embeddedLexer;
+ private Lexer styleLexer;
+ private Map<String, Lexer> scriptLexers = new HashMap<String, Lexer>();
+ private boolean hasNoEmbeddments;
public HtmlHighlightingLexer() {
this(null);
@@ -114,7 +81,7 @@ public class HtmlHighlightingLexer extends BaseHtmlLexer {
}
else {
embeddedLexer = null;
- scriptLexer = null;
+ scriptLexers.clear();
}
}
@@ -122,14 +89,20 @@ public class HtmlHighlightingLexer extends BaseHtmlLexer {
Lexer newLexer = null;
if (hasSeenStyle()) {
if (styleLexer == null) {
- styleLexer = ourStyleFileType == null
- ? null
- : SyntaxHighlighterFactory.getSyntaxHighlighter(ourStyleFileType, null, null).getHighlightingLexer();
+ if (ourStyleFileType == null) {
+ styleLexer = null;
+ }
+ else {
+ SyntaxHighlighter highlighter = SyntaxHighlighterFactory.getSyntaxHighlighter(ourStyleFileType, null, null);
+ LOG.assertTrue(highlighter != null, ourStyleFileType);
+ styleLexer = highlighter.getHighlightingLexer();
+ }
}
newLexer = styleLexer;
}
else if (hasSeenScript()) {
+ Lexer scriptLexer = scriptLexers.get(scriptType);
if (scriptLexer == null) {
if (hasSeenTag()) {
HtmlScriptContentProvider provider = findScriptContentProvider(scriptType);
@@ -145,6 +118,7 @@ public class HtmlHighlightingLexer extends BaseHtmlLexer {
ourInlineScriptFileType != null ? SyntaxHighlighterFactory.getSyntaxHighlighter(ourInlineScriptFileType, null, null) : null;
scriptLexer = syntaxHighlighter != null ? syntaxHighlighter.getHighlightingLexer() : null;
}
+ scriptLexers.put(scriptType, scriptLexer);
}
newLexer = scriptLexer;
}
@@ -254,4 +228,43 @@ public class HtmlHighlightingLexer extends BaseHtmlLexer {
public void setHasNoEmbeddments(boolean hasNoEmbeddments) {
this.hasNoEmbeddments = hasNoEmbeddments;
}
+
+ public class XmlEmbeddmentHandler implements TokenHandler {
+ @Override
+ public void handleElement(Lexer lexer) {
+ if (!hasSeenStyle() && !hasSeenScript() || hasNoEmbeddments) return;
+ final IElementType tokenType = lexer.getTokenType();
+
+ if (tokenType == XmlTokenType.XML_ATTRIBUTE_VALUE_TOKEN && hasSeenAttribute() ||
+ tokenType == XmlTokenType.XML_DATA_CHARACTERS && hasSeenTag() ||
+ tokenType == XmlTokenType.XML_COMMENT_CHARACTERS && hasSeenTag()
+ ) {
+ setEmbeddedLexer();
+
+ if (embeddedLexer != null) {
+ embeddedLexer.start(
+ getBufferSequence(),
+ HtmlHighlightingLexer.super.getTokenStart(),
+ skipToTheEndOfTheEmbeddment(),
+ embeddedLexer instanceof EmbedmentLexer ? ((EmbedmentLexer)embeddedLexer).getEmbeddedInitialState(tokenType) : 0
+ );
+
+ if (embeddedLexer.getTokenType() == null) {
+ // no content for embeddment
+ embeddedLexer = null;
+ }
+ }
+ }
+ }
+ }
+
+ public class ElEmbeddmentHandler implements TokenHandler {
+ @Override
+ public void handleElement(Lexer lexer) {
+ setEmbeddedLexer();
+ if (embeddedLexer != null) {
+ embeddedLexer.start(getBufferSequence(), HtmlHighlightingLexer.super.getTokenStart(), HtmlHighlightingLexer.super.getTokenEnd());
+ }
+ }
+ }
}
diff --git a/xml/xml-psi-impl/src/com/intellij/psi/XmlElementFactoryImpl.java b/xml/xml-psi-impl/src/com/intellij/psi/XmlElementFactoryImpl.java
index 6f40f853b777..20abde77589e 100644
--- a/xml/xml-psi-impl/src/com/intellij/psi/XmlElementFactoryImpl.java
+++ b/xml/xml-psi-impl/src/com/intellij/psi/XmlElementFactoryImpl.java
@@ -23,6 +23,7 @@ import com.intellij.lang.Language;
import com.intellij.lang.xml.XMLLanguage;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileTypes.FileType;
+import com.intellij.openapi.fileTypes.LanguageFileType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.xml.*;
@@ -109,7 +110,17 @@ public class XmlElementFactoryImpl extends XmlElementFactory {
}
private XmlDocument createXmlDocument(@NonNls final CharSequence text, @NonNls final String fileName, FileType fileType) {
- final XmlDocument document = ((XmlFile)PsiFileFactory.getInstance(myProject).createFileFromText(fileName, fileType, text)).getDocument();
+ PsiFile fileFromText = PsiFileFactory.getInstance(myProject).createFileFromText(fileName, fileType, text);
+
+ XmlFile xmlFile;
+ if (fileFromText instanceof XmlFile) {
+ xmlFile = (XmlFile)fileFromText;
+ }
+ else {
+ xmlFile = (XmlFile)fileFromText.getViewProvider().getPsi(((LanguageFileType)fileType).getLanguage());
+ assert xmlFile != null;
+ }
+ XmlDocument document = xmlFile.getDocument();
assert document != null;
return document;
}
diff --git a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/XmlAttributeValueManipulator.java b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/XmlAttributeValueManipulator.java
index a32b51f5fc3f..92c287e8fdbe 100644
--- a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/XmlAttributeValueManipulator.java
+++ b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/XmlAttributeValueManipulator.java
@@ -30,6 +30,7 @@ import com.intellij.psi.xml.XmlAttributeValue;
import com.intellij.psi.xml.XmlTokenType;
import com.intellij.util.CharTable;
import com.intellij.util.IncorrectOperationException;
+import com.intellij.xml.util.XmlUtil;
import org.jetbrains.annotations.NotNull;
/**
@@ -63,7 +64,7 @@ public class XmlAttributeValueManipulator extends AbstractElementManipulator<Xml
final int offsetInParent = elementToReplace.getStartOffsetInParent();
String textBeforeRange = text.substring(0, range.getStartOffset() - offsetInParent);
String textAfterRange = text.substring(range.getEndOffset()- offsetInParent, text.length());
- text = textBeforeRange + newContent + textAfterRange;
+ text = textBeforeRange + XmlUtil.escape(newContent) + textAfterRange;
} catch(StringIndexOutOfBoundsException e) {
LOG.error("Range: " + range + " in text: '" + element.getText() + "'", e);
throw e;
diff --git a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/XmlTextManipulator.java b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/XmlTextManipulator.java
index de4f9eb6cbc7..e160ba4c14db 100644
--- a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/XmlTextManipulator.java
+++ b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/resolve/reference/impl/manipulators/XmlTextManipulator.java
@@ -51,6 +51,9 @@ public class XmlTextManipulator extends AbstractElementManipulator<XmlText> {
else {
text.deleteChildRange(text.getFirstChild(), text.getLastChild());
}
+ //String oldText = text.getText();
+ //((PsiLanguageInjectionHost)text).updateText(
+ // oldText.substring(0, range.getStartOffset()) + newContent + oldText.substring(range.getEndOffset()));
return text;
}
diff --git a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/XmlTagImpl.java b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/XmlTagImpl.java
index 1c33789dfd57..dd70733533f8 100644
--- a/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/XmlTagImpl.java
+++ b/xml/xml-psi-impl/src/com/intellij/psi/impl/source/xml/XmlTagImpl.java
@@ -75,27 +75,8 @@ import java.util.*;
public class XmlTagImpl extends XmlElementImpl implements XmlTag {
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.xml.XmlTagImpl");
-
- private volatile String myName = null;
- private volatile String myLocalName;
- private volatile XmlAttribute[] myAttributes = null;
- private volatile Map<String, String> myAttributeValueMap = null;
- private volatile XmlTagValue myValue = null;
- private volatile Map<String, CachedValue<XmlNSDescriptor>> myNSDescriptorsMap = null;
- private volatile String myCachedNamespace;
- private volatile long myModCount;
-
- private volatile XmlElementDescriptor myCachedDescriptor;
- private volatile long myDescriptorModCount = -1;
- private volatile long myExtResourcesModCount = -1;
-
- private volatile boolean myHasNamespaceDeclarations = false;
- private volatile BidirectionalMap<String, String> myNamespaceMap = null;
@NonNls private static final String XML_NS_PREFIX = "xml";
-
- private final int myHC = ourHC++;
private static final RecursionGuard ourGuard = RecursionManager.createGuard("xmlTag");
-
private static final Key<ParameterizedCachedValue<XmlTag[], XmlTagImpl>> SUBTAGS_KEY = Key.create("subtags");
private static final ParameterizedCachedValueProvider<XmlTag[],XmlTagImpl> CACHED_VALUE_PROVIDER =
new ParameterizedCachedValueProvider<XmlTag[], XmlTagImpl>() {
@@ -111,11 +92,20 @@ public class XmlTagImpl extends XmlElementImpl implements XmlTag {
.create(tags, PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT, tag.getContainingFile());
}
};
-
- @Override
- public final int hashCode() {
- return myHC;
- }
+ private final int myHC = ourHC++;
+ private volatile String myName = null;
+ private volatile String myLocalName;
+ private volatile XmlAttribute[] myAttributes = null;
+ private volatile Map<String, String> myAttributeValueMap = null;
+ private volatile XmlTagValue myValue = null;
+ private volatile Map<String, CachedValue<XmlNSDescriptor>> myNSDescriptorsMap = null;
+ private volatile String myCachedNamespace;
+ private volatile long myModCount;
+ private volatile XmlElementDescriptor myCachedDescriptor;
+ private volatile long myDescriptorModCount = -1;
+ private volatile long myExtResourcesModCount = -1;
+ private volatile boolean myHasNamespaceDeclarations = false;
+ private volatile BidirectionalMap<String, String> myNamespaceMap = null;
public XmlTagImpl() {
this(XmlElementType.XML_TAG);
@@ -125,6 +115,33 @@ public class XmlTagImpl extends XmlElementImpl implements XmlTag {
super(type);
}
+ @Nullable
+ private static XmlNSDescriptor getDtdDescriptor(@NotNull XmlFile containingFile) {
+ final XmlDocument document = containingFile.getDocument();
+ if (document == null) {
+ return null;
+ }
+ final String url = XmlUtil.getDtdUri(document);
+ if (url == null) {
+ return null;
+ }
+ return document.getDefaultNSDescriptor(url, true);
+ }
+
+ @Nullable
+ private static String getNSVersion(String ns, final XmlTagImpl xmlTag) {
+ String versionValue = xmlTag.getAttributeValue("version");
+ if (versionValue != null && xmlTag.getNamespace().equals(ns)) {
+ return versionValue;
+ }
+ return null;
+ }
+
+ @Override
+ public final int hashCode() {
+ return myHC;
+ }
+
@Override
public void clearCaches() {
myName = null;
@@ -215,19 +232,6 @@ public class XmlTagImpl extends XmlElementImpl implements XmlTag {
return parentTag.getNSDescriptor(namespace, strict);
}
- @Nullable
- private static XmlNSDescriptor getDtdDescriptor(@NotNull XmlFile containingFile) {
- final XmlDocument document = containingFile.getDocument();
- if (document == null) {
- return null;
- }
- final String url = XmlUtil.getDtdUri(document);
- if (url == null) {
- return null;
- }
- return document.getDefaultNSDescriptor(url, true);
- }
-
@Override
public boolean isEmpty() {
return XmlChildRole.CLOSING_TAG_START_FINDER.findChild(this) == null;
@@ -325,15 +329,6 @@ public class XmlTagImpl extends XmlElementImpl implements XmlTag {
return map == null ? Collections.<String, CachedValue<XmlNSDescriptor>>emptyMap() : map;
}
- @Nullable
- private static String getNSVersion(String ns, final XmlTagImpl xmlTag) {
- String versionValue = xmlTag.getAttributeValue("version");
- if (versionValue != null && xmlTag.getNamespace().equals(ns)) {
- return versionValue;
- }
- return null;
- }
-
private Map<String, CachedValue<XmlNSDescriptor>> initializeSchema(@NotNull final String namespace,
@Nullable final String version,
final String fileLocation,
@@ -921,7 +916,7 @@ public class XmlTagImpl extends XmlElementImpl implements XmlTag {
}
}
}
- return ns;
+ return XmlUtil.getSchemaLocation(this, ns);
}
protected String getRealNs(final String value) {
diff --git a/xml/xml-psi-impl/src/com/intellij/xml/HtmlXmlExtension.java b/xml/xml-psi-impl/src/com/intellij/xml/HtmlXmlExtension.java
index 4ece939ffac0..e54a93394242 100644
--- a/xml/xml-psi-impl/src/com/intellij/xml/HtmlXmlExtension.java
+++ b/xml/xml-psi-impl/src/com/intellij/xml/HtmlXmlExtension.java
@@ -3,6 +3,7 @@ package com.intellij.xml;
import com.intellij.ide.highlighter.HtmlFileType;
import com.intellij.psi.PsiFile;
import com.intellij.psi.xml.XmlDocument;
+import com.intellij.xml.util.HtmlUtil;
import org.jetbrains.annotations.Nullable;
/**
@@ -19,6 +20,16 @@ public class HtmlXmlExtension extends DefaultXmlExtension {
@Nullable
@Override
public String[][] getNamespacesFromDocument(XmlDocument parent, boolean declarationsExist) {
- return super.getNamespacesFromDocument(parent, false);
+ String[][] namespaces = super.getNamespacesFromDocument(parent, false);
+ if (namespaces == null || !HtmlUtil.isHtml5Document(parent)) return namespaces;
+
+ for (String[] namespace : namespaces) {
+ if ("xlink".equals(namespace[0])) return namespaces;
+ }
+
+ String[][] newNamespaces = new String[namespaces.length + 1][2];
+ System.arraycopy(namespaces, 0, newNamespaces, 0, namespaces.length);
+ newNamespaces[namespaces.length] = new String[] {"xlink", "http://www.w3.org/1999/xlink"};
+ return newNamespaces;
}
}
diff --git a/xml/xml-psi-impl/src/com/intellij/xml/XmlCoreEnvironment.java b/xml/xml-psi-impl/src/com/intellij/xml/XmlCoreEnvironment.java
index b7704fb3b981..4610c2fa97e0 100644
--- a/xml/xml-psi-impl/src/com/intellij/xml/XmlCoreEnvironment.java
+++ b/xml/xml-psi-impl/src/com/intellij/xml/XmlCoreEnvironment.java
@@ -119,7 +119,7 @@ public class XmlCoreEnvironment {
appEnvironment.addExtension(StandardResourceProvider.EP_NAME, new InternalResourceProvider());
appEnvironment.registerApplicationComponent(PathMacros.class, new PathMacrosImpl());
- appEnvironment.registerApplicationService(ExternalResourceManager.class, new ExternalResourceManagerExImpl(PathMacrosImpl.getInstanceEx()));
+ appEnvironment.registerApplicationService(ExternalResourceManager.class, new ExternalResourceManagerExImpl());
appEnvironment.registerApplicationService(XmlFoldingSettings.class, new XmlFoldingSettings());
Language[] myLanguages = new Language[]{XMLLanguage.INSTANCE, HTMLLanguage.INSTANCE, XHTMLLanguage.INSTANCE, DTDLanguage.INSTANCE};
for (Language myLanguage : myLanguages) {
@@ -137,8 +137,7 @@ public class XmlCoreEnvironment {
public static class ProjectEnvironment {
public ProjectEnvironment(CoreProjectEnvironment projectEnvironment) {
projectEnvironment.getProject().registerService(XmlElementFactory.class, new XmlElementFactoryImpl(projectEnvironment.getProject()));
- projectEnvironment.getProject().registerService(ExternalResourceManagerExImpl.class,
- new ProjectResources(PathMacrosImpl.getInstanceEx()));
+ projectEnvironment.getProject().registerService(ExternalResourceManagerExImpl.class, new ProjectResources());
}
}
}
diff --git a/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/XmlNSDescriptorImpl.java b/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/XmlNSDescriptorImpl.java
index 192c272a5f23..17c6f1ab37ae 100644
--- a/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/XmlNSDescriptorImpl.java
+++ b/xml/xml-psi-impl/src/com/intellij/xml/impl/schema/XmlNSDescriptorImpl.java
@@ -30,7 +30,6 @@ import com.intellij.psi.util.CachedValue;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.psi.util.PsiModificationTracker;
-import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlDocument;
import com.intellij.psi.xml.XmlFile;
import com.intellij.psi.xml.XmlTag;
@@ -56,35 +55,35 @@ import java.util.*;
*/
@SuppressWarnings({"HardCodedStringLiteral"})
public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocument>, DumbAware, XmlNSTypeDescriptorProvider {
- private static final Logger LOG = Logger.getInstance("#com.intellij.xml.impl.schema.XmlNSDescriptorImpl");
- @NonNls private static final Set<String> STD_TYPES = new HashSet<String>();
- private static final Set<String> UNDECLARED_STD_TYPES = new HashSet<String>();
- private XmlFile myFile;
- private XmlTag myTag;
- private String myTargetNamespace;
@NonNls
public static final String XSD_PREFIX = "xsd";
-
+ @NonNls public static final String SCHEMA_TAG_NAME = "schema";
+ @NonNls public static final String IMPORT_TAG_NAME = "import";
@NonNls static final String ELEMENT_TAG_NAME = "element";
@NonNls static final String ATTRIBUTE_TAG_NAME = "attribute";
@NonNls static final String COMPLEX_TYPE_TAG_NAME = "complexType";
@NonNls static final String SEQUENCE_TAG_NAME = "sequence";
- @NonNls public static final String SCHEMA_TAG_NAME = "schema";
+ private static final Logger LOG = Logger.getInstance("#com.intellij.xml.impl.schema.XmlNSDescriptorImpl");
+ @NonNls private static final Set<String> STD_TYPES = new HashSet<String>();
+ private static final Set<String> UNDECLARED_STD_TYPES = new HashSet<String>();
@NonNls private static final String INCLUDE_TAG_NAME = "include";
- @NonNls public static final String IMPORT_TAG_NAME = "import";
@NonNls private static final String REDEFINE_TAG_NAME = "redefine";
+ private static final ThreadLocal<Set<PsiFile>> myRedefinedDescriptorsInProcessing = new ThreadLocal<Set<PsiFile>>();
+ private final Map<QNameKey, CachedValue<XmlElementDescriptor>> myDescriptorsMap = Collections.synchronizedMap(new HashMap<QNameKey, CachedValue<XmlElementDescriptor>>());
+ private final Map<Pair<QNameKey, XmlTag>, CachedValue<TypeDescriptor>> myTypesMap = Collections.synchronizedMap(new HashMap<Pair<QNameKey,XmlTag>, CachedValue<TypeDescriptor>>());
+ private XmlFile myFile;
+ private XmlTag myTag;
+ private String myTargetNamespace;
+ private volatile Object[] dependencies;
+ private MultiMap<String,XmlTag> mySubstitutions;
public XmlNSDescriptorImpl(XmlFile file) {
init(file.getDocument());
}
-
+
public XmlNSDescriptorImpl() {
}
- private volatile Object[] dependencies;
-
- private static final ThreadLocal<Set<PsiFile>> myRedefinedDescriptorsInProcessing = new ThreadLocal<Set<PsiFile>>();
-
private static void collectDependencies(@Nullable XmlTag myTag, @NotNull XmlFile myFile, @NotNull Set<PsiFile> visited) {
if (visited.contains(myFile)) return;
visited.add( myFile );
@@ -121,7 +120,7 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum
if(tokenizer.hasMoreTokens()){
PsiFile resourceLocation = ExternalResourceManager.getInstance().getResourceLocation(tokenizer.nextToken(), myFile, null);
- if (resourceLocation == null && uri != null) resourceLocation = ExternalResourceManager.getInstance().getResourceLocation(uri, myFile, null);
+ if (resourceLocation == null) resourceLocation = ExternalResourceManager.getInstance().getResourceLocation(uri, myFile, null);
if (resourceLocation instanceof XmlFile) addDependency((XmlFile)resourceLocation, visited);
}
@@ -136,6 +135,211 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum
}
}
+ private static boolean checkSchemaNamespace(String name, XmlTag context){
+ final String namespace = context.getNamespaceByPrefix(XmlUtil.findPrefixByQualifiedName(name));
+ if(namespace.length() > 0){
+ return checkSchemaNamespace(namespace);
+ }
+ return XSD_PREFIX.equals(XmlUtil.findPrefixByQualifiedName(name));
+ }
+
+ public static boolean checkSchemaNamespace(String namespace) {
+ return XmlUtil.XML_SCHEMA_URI.equals(namespace) ||
+ XmlUtil.XML_SCHEMA_URI2.equals(namespace) ||
+ XmlUtil.XML_SCHEMA_URI3.equals(namespace);
+ }
+
+ public static boolean checkSchemaNamespace(XmlTag context) {
+ LOG.assertTrue(context.isValid());
+ final String namespace = context.getNamespace();
+ if (namespace.length() > 0) {
+ return checkSchemaNamespace(namespace);
+ }
+ return StringUtil.startsWithConcatenation(context.getName(), XSD_PREFIX, ":");
+ }
+
+ static @NotNull XmlNSDescriptorImpl getNSDescriptorToSearchIn(XmlTag rootTag, final String name, XmlNSDescriptorImpl defaultNSDescriptor) {
+ if (name == null) return defaultNSDescriptor;
+ final String namespacePrefix = XmlUtil.findPrefixByQualifiedName(name);
+
+ if (namespacePrefix.length() > 0) {
+ final String namespace = rootTag.getNamespaceByPrefix(namespacePrefix);
+ final XmlNSDescriptor nsDescriptor = rootTag.getNSDescriptor(namespace, true);
+
+ if (nsDescriptor instanceof XmlNSDescriptorImpl) {
+ return (XmlNSDescriptorImpl)nsDescriptor;
+ }
+ }
+
+ return defaultNSDescriptor;
+ }
+
+ @Nullable
+ private static XmlElementDescriptor getDescriptorFromParent(final XmlTag tag, XmlElementDescriptor elementDescriptor) {
+ final PsiElement parent = tag.getParent();
+ if (parent instanceof XmlTag) {
+ final XmlElementDescriptor descriptor = ((XmlTag)parent).getDescriptor();
+ if (descriptor != null) elementDescriptor = descriptor.getElementDescriptor(tag, (XmlTag)parent);
+ }
+ return elementDescriptor;
+ }
+
+ public static boolean processTagsInNamespace(@NotNull final XmlTag rootTag, String[] tagNames, PsiElementProcessor<XmlTag> processor) {
+ return processTagsInNamespaceInner(rootTag, tagNames, processor, null);
+ }
+
+ private static boolean processTagsInNamespaceInner(@NotNull final XmlTag rootTag, final String[] tagNames,
+ final PsiElementProcessor<XmlTag> processor, Set<XmlTag> visitedTags) {
+ if (visitedTags == null) visitedTags = new HashSet<XmlTag>(3);
+ else if (visitedTags.contains(rootTag)) return true;
+
+ visitedTags.add(rootTag);
+ XmlTag[] tags = rootTag.getSubTags();
+
+ NextTag:
+ for (XmlTag tag : tags) {
+ for(String tagName:tagNames) {
+ if (equalsToSchemaName(tag, tagName)) {
+ final String name = tag.getAttributeValue("name");
+
+ if (name != null) {
+ if (!processor.execute(tag)) {
+ return false;
+ }
+ }
+
+ continue NextTag;
+ }
+ }
+
+ if (equalsToSchemaName(tag, INCLUDE_TAG_NAME)) {
+ final String schemaLocation = tag.getAttributeValue("schemaLocation");
+
+ if (schemaLocation != null) {
+ final XmlFile xmlFile = XmlUtil.findNamespace(rootTag.getContainingFile(), schemaLocation);
+
+ if (xmlFile != null) {
+ final XmlDocument includedDocument = xmlFile.getDocument();
+
+ if (includedDocument != null) {
+ if (!processTagsInNamespaceInner(includedDocument.getRootTag(), tagNames, processor, visitedTags)) return false;
+ }
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public static boolean equalsToSchemaName(@NotNull XmlTag tag, @NonNls String schemaName) {
+ return schemaName.equals(tag.getLocalName()) && checkSchemaNamespace(tag);
+ }
+
+ private static @Nullable XmlTag findSpecialTag(@NonNls String name, @NonNls String specialName, XmlTag rootTag, XmlNSDescriptorImpl descriptor,
+ HashSet<XmlTag> visited) {
+ XmlNSDescriptorImpl nsDescriptor = getNSDescriptorToSearchIn(rootTag, name, descriptor);
+
+ if (nsDescriptor != descriptor) {
+ final XmlDocument document = nsDescriptor.getDescriptorFile() != null ? nsDescriptor.getDescriptorFile().getDocument():null;
+ if (document == null) return null;
+
+ return findSpecialTag(
+ XmlUtil.findLocalNameByQualifiedName(name),
+ specialName,
+ document.getRootTag(),
+ nsDescriptor,
+ visited
+ );
+ }
+
+ if (visited == null) visited = new HashSet<XmlTag>(1);
+ else if (visited.contains(rootTag)) return null;
+ visited.add(rootTag);
+
+ XmlTag[] tags = rootTag.getSubTags();
+
+ return findSpecialTagIn(tags, specialName, name, rootTag, descriptor, visited);
+ }
+
+ private static XmlTag findSpecialTagIn(final XmlTag[] tags,
+ final String specialName,
+ final String name,
+ final XmlTag rootTag,
+ final XmlNSDescriptorImpl descriptor, final HashSet<XmlTag> visited) {
+ for (XmlTag tag : tags) {
+ if (equalsToSchemaName(tag, specialName)) {
+ String attribute = tag.getAttributeValue("name");
+
+ if (name.equals(attribute)
+ || name.contains(":") && name.substring(name.indexOf(":") + 1).equals(attribute)) {
+ return tag;
+ }
+ } else if (equalsToSchemaName(tag, INCLUDE_TAG_NAME) ||
+ ( equalsToSchemaName(tag, IMPORT_TAG_NAME) &&
+ rootTag.getNamespaceByPrefix(
+ XmlUtil.findPrefixByQualifiedName(name)
+ ).equals(tag.getAttributeValue("namespace"))
+ )
+ ) {
+ final String schemaLocation = tag.getAttributeValue("schemaLocation");
+
+ if (schemaLocation != null) {
+ final XmlFile xmlFile = XmlUtil.findNamespace(rootTag.getContainingFile(), schemaLocation);
+
+ if (xmlFile != null) {
+ final XmlDocument document = xmlFile.getDocument();
+ if (document != null) {
+ final XmlTag rTag = findSpecialTag(name, specialName, document.getRootTag(), descriptor, visited);
+
+ if (rTag != null) return rTag;
+ }
+ }
+ }
+ } else if (equalsToSchemaName(tag, REDEFINE_TAG_NAME)) {
+ XmlTag rTag = findSpecialTagIn(tag.getSubTags(), specialName, name, rootTag, descriptor, visited);
+ if (rTag != null) return rTag;
+
+ final XmlNSDescriptorImpl nsDescriptor = getRedefinedElementDescriptor(tag);
+ if (nsDescriptor != null) {
+ final XmlTag redefinedRootTag = ((XmlDocument)nsDescriptor.getDeclaration()).getRootTag();
+
+ rTag = findSpecialTagIn(redefinedRootTag.getSubTags(), specialName, name, redefinedRootTag, nsDescriptor, visited);
+ if (rTag != null) return rTag;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public static XmlNSDescriptorImpl getRedefinedElementDescriptor(final XmlTag parentTag) {
+ XmlFile file = getRedefinedElementDescriptorFile(parentTag);
+ if (file != null) {
+ final XmlDocument document = file.getDocument();
+ final PsiMetaData metaData = document != null ? document.getMetaData():null;
+ if (metaData instanceof XmlNSDescriptorImpl) return (XmlNSDescriptorImpl)metaData;
+ }
+ return null;
+ }
+
+ public static XmlFile getRedefinedElementDescriptorFile(final XmlTag parentTag) {
+ final String schemaL = parentTag.getAttributeValue(XmlUtil.SCHEMA_LOCATION_ATT);
+
+ if (schemaL != null) {
+ final PsiReference[] references = parentTag.getAttribute(XmlUtil.SCHEMA_LOCATION_ATT, null).getValueElement().getReferences();
+
+ if (references.length > 0) {
+ final PsiElement psiElement = references[references.length - 1].resolve();
+
+ if (psiElement instanceof XmlFile) {
+ return ((XmlFile)psiElement);
+ }
+ }
+ }
+ return null;
+ }
+
@Override
public XmlFile getDescriptorFile() {
return myFile;
@@ -150,18 +354,10 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum
return myTargetNamespace != null ? myTargetNamespace : "";
}
- static class QNameKey extends Pair<String, String>{
- QNameKey(String name, String namespace) {
- super(name, namespace);
- }
- }
- private final Map<QNameKey, CachedValue<XmlElementDescriptor>> myDescriptorsMap = Collections.synchronizedMap(new HashMap<QNameKey, CachedValue<XmlElementDescriptor>>());
- private final Map<Pair<QNameKey, XmlTag>, CachedValue<TypeDescriptor>> myTypesMap = Collections.synchronizedMap(new HashMap<Pair<QNameKey,XmlTag>, CachedValue<TypeDescriptor>>());
-
@Override
@Nullable
public XmlElementDescriptor getElementDescriptor(String localName, String namespace) {
- return getElementDescriptor(localName, namespace, new HashSet<XmlNSDescriptorImpl>(),false);
+ return getElementDescriptor(localName, namespace, new HashSet<XmlNSDescriptorImpl>(), false);
}
@Nullable
@@ -213,9 +409,9 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum
)
)
) {
- final XmlAttribute schemaLocation = tag.getAttribute("schemaLocation");
+ final String schemaLocation = tag.getAttributeValue("schemaLocation");
if (schemaLocation != null) {
- final XmlFile xmlFile = XmlUtil.findNamespace(rootTag.getContainingFile(), schemaLocation.getValue());
+ final XmlFile xmlFile = XmlUtil.findNamespace(rootTag.getContainingFile(), schemaLocation);
if (xmlFile != null) {
final XmlDocument includedDocument = xmlFile.getDocument();
if (includedDocument != null) {
@@ -266,8 +462,7 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum
return true;
}
else {
- final boolean b = myTargetNamespace.equals(namespace);
- if (b) return b;
+ if (myTargetNamespace.equals(namespace)) return true;
return context.getNSDescriptor(namespace, true) == this; // schema's targetNamespace could be different from file systemId
}
return false;
@@ -311,10 +506,10 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum
namespace.equals(tag.getAttributeValue("namespace"))
)
) {
- final XmlAttribute schemaLocation = tag.getAttribute("schemaLocation");
+ final String schemaLocation = tag.getAttributeValue("schemaLocation");
if (schemaLocation != null) {
- final XmlFile xmlFile = XmlUtil.findNamespace(myTag.getContainingFile(), schemaLocation.getValue());
+ final XmlFile xmlFile = XmlUtil.findNamespace(myTag.getContainingFile(), schemaLocation);
if (xmlFile != null) {
@@ -370,7 +565,7 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum
public TypeDescriptor getTypeDescriptor(final String name, XmlTag context) {
if(checkSchemaNamespace(name, context)){
final String localNameByQualifiedName = XmlUtil.findLocalNameByQualifiedName(name);
-
+
if (STD_TYPES.contains(localNameByQualifiedName) &&
( name.length() == localNameByQualifiedName.length() ||
UNDECLARED_STD_TYPES.contains(localNameByQualifiedName)
@@ -390,45 +585,6 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum
return new XmlElementDescriptorByType(instanceTag, (ComplexTypeDescriptor)typeDescriptor);
}
- private static boolean checkSchemaNamespace(String name, XmlTag context){
- final String namespace = context.getNamespaceByPrefix(XmlUtil.findPrefixByQualifiedName(name));
- if(namespace.length() > 0){
- return checkSchemaNamespace(namespace);
- }
- return XSD_PREFIX.equals(XmlUtil.findPrefixByQualifiedName(name));
- }
-
- public static boolean checkSchemaNamespace(String namespace) {
- return XmlUtil.XML_SCHEMA_URI.equals(namespace) ||
- XmlUtil.XML_SCHEMA_URI2.equals(namespace) ||
- XmlUtil.XML_SCHEMA_URI3.equals(namespace);
- }
-
- public static boolean checkSchemaNamespace(XmlTag context) {
- LOG.assertTrue(context.isValid());
- final String namespace = context.getNamespace();
- if (namespace.length() > 0) {
- return checkSchemaNamespace(namespace);
- }
- return StringUtil.startsWithConcatenation(context.getName(), XSD_PREFIX, ":");
- }
-
- static @NotNull XmlNSDescriptorImpl getNSDescriptorToSearchIn(XmlTag rootTag, final String name, XmlNSDescriptorImpl defaultNSDescriptor) {
- if (name == null) return defaultNSDescriptor;
- final String namespacePrefix = XmlUtil.findPrefixByQualifiedName(name);
-
- if (namespacePrefix != null && namespacePrefix.length() > 0) {
- final String namespace = rootTag.getNamespaceByPrefix(namespacePrefix);
- final XmlNSDescriptor nsDescriptor = rootTag.getNSDescriptor(namespace, true);
-
- if (nsDescriptor instanceof XmlNSDescriptorImpl) {
- return (XmlNSDescriptorImpl)nsDescriptor;
- }
- }
-
- return defaultNSDescriptor;
- }
-
@Nullable
protected TypeDescriptor findTypeDescriptor(final String qname) {
return findTypeDescriptor(qname, myTag);
@@ -587,7 +743,7 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum
private boolean isSameName(@NotNull String name, String namespace, String nameAttribute) {
return nameAttribute != null &&
- (nameAttribute.equals(name) || (name.indexOf(":") >= 0 && nameAttribute.equals(name.substring(name.indexOf(":") + 1)))) &&
+ (nameAttribute.equals(name) || (name.contains(":") && nameAttribute.equals(name.substring(name.indexOf(":") + 1)))) &&
(namespace == null || namespace.length() == 0 || namespace.equals(getDefaultNamespace()))
;
}
@@ -619,23 +775,24 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum
}
private CachedValue<TypeDescriptor> createAndPutTypesCachedValue(final XmlTag tag, final Pair<QNameKey, XmlTag> pair) {
- final CachedValue<TypeDescriptor> value = CachedValuesManager.getManager(tag.getProject()).createCachedValue(new CachedValueProvider<TypeDescriptor>() {
- @Override
- public CachedValueProvider.Result<TypeDescriptor> compute() {
- final String name = tag.getAttributeValue("name");
-
- if (name != null &&
- pair.first != null &&
- pair.first.first != null &&
- !name.equals(XmlUtil.findLocalNameByQualifiedName(pair.first.first))
- ) {
- myTypesMap.remove(pair);
- return new Result<TypeDescriptor>(null, PsiModificationTracker.MODIFICATION_COUNT);
+ final CachedValue<TypeDescriptor> value = CachedValuesManager.getManager(tag.getProject()).createCachedValue(
+ new CachedValueProvider<TypeDescriptor>() {
+ @Override
+ public CachedValueProvider.Result<TypeDescriptor> compute() {
+ final String name = tag.getAttributeValue("name");
+
+ if (name != null &&
+ pair.first != null &&
+ pair.first.first != null &&
+ !name.equals(XmlUtil.findLocalNameByQualifiedName(pair.first.first))
+ ) {
+ myTypesMap.remove(pair);
+ return new Result<TypeDescriptor>(null, PsiModificationTracker.MODIFICATION_COUNT);
+ }
+ final ComplexTypeDescriptor complexTypeDescriptor = new ComplexTypeDescriptor(XmlNSDescriptorImpl.this, tag);
+ return new Result<TypeDescriptor>(complexTypeDescriptor, tag);
}
- final ComplexTypeDescriptor complexTypeDescriptor = new ComplexTypeDescriptor(XmlNSDescriptorImpl.this, tag);
- return new Result<TypeDescriptor>(complexTypeDescriptor, tag);
- }
- }, false);
+ }, false);
myTypesMap.put(pair, value);
return value;
}
@@ -668,7 +825,7 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum
}
else {
XmlElementDescriptor elementDescriptor = getElementDescriptor(tag.getLocalName(), tag.getNamespace());
-
+
if (elementDescriptor == null) {
elementDescriptor = getDescriptorFromParent(tag, elementDescriptor);
}
@@ -677,29 +834,19 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum
}
}
- @Nullable
- private static XmlElementDescriptor getDescriptorFromParent(final XmlTag tag, XmlElementDescriptor elementDescriptor) {
- final PsiElement parent = tag.getParent();
- if (parent instanceof XmlTag) {
- final XmlElementDescriptor descriptor = ((XmlTag)parent).getDescriptor();
- if (descriptor != null) elementDescriptor = descriptor.getElementDescriptor(tag, (XmlTag)parent);
- }
- return elementDescriptor;
- }
-
@Override
@NotNull
public XmlElementDescriptor[] getRootElementsDescriptors(@Nullable final XmlDocument doc) {
class CollectElementsProcessor implements PsiElementProcessor<XmlTag> {
final List<XmlElementDescriptor> result = new ArrayList<XmlElementDescriptor>();
-
+
@Override
public boolean execute(@NotNull final XmlTag element) {
ContainerUtil.addIfNotNull(result, getElementDescriptor(element.getAttributeValue("name"), getDefaultNamespace()));
return true;
}
}
-
+
CollectElementsProcessor processor = new CollectElementsProcessor() {
@Override
public boolean execute(@NotNull final XmlTag element) {
@@ -729,135 +876,6 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum
return processor.result.toArray(new XmlAttributeDescriptor[processor.result.size()]);
}
- public static boolean processTagsInNamespace(@NotNull final XmlTag rootTag, String[] tagNames, PsiElementProcessor<XmlTag> processor) {
- return processTagsInNamespaceInner(rootTag, tagNames, processor, null);
- }
-
- private static boolean processTagsInNamespaceInner(@NotNull final XmlTag rootTag, final String[] tagNames,
- final PsiElementProcessor<XmlTag> processor, Set<XmlTag> visitedTags) {
- if (visitedTags == null) visitedTags = new HashSet<XmlTag>(3);
- else if (visitedTags.contains(rootTag)) return true;
-
- visitedTags.add(rootTag);
- XmlTag[] tags = rootTag.getSubTags();
-
- NextTag:
- for (XmlTag tag : tags) {
- for(String tagName:tagNames) {
- if (equalsToSchemaName(tag, tagName)) {
- final String name = tag.getAttributeValue("name");
-
- if (name != null) {
- if (!processor.execute(tag)) {
- return false;
- }
- }
-
- continue NextTag;
- }
- }
-
- if (equalsToSchemaName(tag, INCLUDE_TAG_NAME)) {
- final String schemaLocation = tag.getAttributeValue("schemaLocation");
-
- if (schemaLocation != null) {
- final XmlFile xmlFile = XmlUtil.findNamespace(rootTag.getContainingFile(), schemaLocation);
-
- if (xmlFile != null) {
- final XmlDocument includedDocument = xmlFile.getDocument();
-
- if (includedDocument != null) {
- if (!processTagsInNamespaceInner(includedDocument.getRootTag(), tagNames, processor, visitedTags)) return false;
- }
- }
- }
- }
- }
-
- return true;
- }
-
- public static boolean equalsToSchemaName(@NotNull XmlTag tag, @NonNls String schemaName) {
- return schemaName.equals(tag.getLocalName()) && checkSchemaNamespace(tag);
- }
-
- private static @Nullable XmlTag findSpecialTag(@NonNls String name, @NonNls String specialName, XmlTag rootTag, XmlNSDescriptorImpl descriptor,
- HashSet<XmlTag> visited) {
- XmlNSDescriptorImpl nsDescriptor = getNSDescriptorToSearchIn(rootTag, name, descriptor);
-
- if (nsDescriptor != descriptor) {
- final XmlDocument document = nsDescriptor.getDescriptorFile() != null ? nsDescriptor.getDescriptorFile().getDocument():null;
- if (document == null) return null;
-
- return findSpecialTag(
- XmlUtil.findLocalNameByQualifiedName(name),
- specialName,
- document.getRootTag(),
- nsDescriptor,
- visited
- );
- }
-
- if (visited == null) visited = new HashSet<XmlTag>(1);
- else if (visited.contains(rootTag)) return null;
- visited.add(rootTag);
-
- XmlTag[] tags = rootTag.getSubTags();
-
- return findSpecialTagIn(tags, specialName, name, rootTag, descriptor, visited);
- }
-
- private static XmlTag findSpecialTagIn(final XmlTag[] tags,
- final String specialName,
- final String name,
- final XmlTag rootTag,
- final XmlNSDescriptorImpl descriptor, final HashSet<XmlTag> visited) {
- for (XmlTag tag : tags) {
- if (equalsToSchemaName(tag, specialName)) {
- String attribute = tag.getAttributeValue("name");
-
- if (name.equals(attribute)
- || name.indexOf(":") >= 0 && name.substring(name.indexOf(":") + 1).equals(attribute)) {
- return tag;
- }
- } else if (equalsToSchemaName(tag, INCLUDE_TAG_NAME) ||
- ( equalsToSchemaName(tag, IMPORT_TAG_NAME) &&
- rootTag.getNamespaceByPrefix(
- XmlUtil.findPrefixByQualifiedName(name)
- ).equals(tag.getAttributeValue("namespace"))
- )
- ) {
- final String schemaLocation = tag.getAttributeValue("schemaLocation");
-
- if (schemaLocation != null) {
- final XmlFile xmlFile = XmlUtil.findNamespace(rootTag.getContainingFile(), schemaLocation);
-
- if (xmlFile != null) {
- final XmlDocument document = xmlFile.getDocument();
- if (document != null) {
- final XmlTag rTag = findSpecialTag(name, specialName, document.getRootTag(), descriptor, visited);
-
- if (rTag != null) return rTag;
- }
- }
- }
- } else if (equalsToSchemaName(tag, REDEFINE_TAG_NAME)) {
- XmlTag rTag = findSpecialTagIn(tag.getSubTags(), specialName, name, rootTag, descriptor, visited);
- if (rTag != null) return rTag;
-
- final XmlNSDescriptorImpl nsDescriptor = getRedefinedElementDescriptor(tag);
- if (nsDescriptor != null) {
- final XmlTag redefinedRootTag = ((XmlDocument)nsDescriptor.getDeclaration()).getRootTag();
-
- rTag = findSpecialTagIn(redefinedRootTag.getSubTags(), specialName, name, redefinedRootTag, nsDescriptor, visited);
- if (rTag != null) return rTag;
- }
- }
- }
-
- return null;
- }
-
@Nullable
public XmlTag findGroup(String name) {
return findSpecialTag(name,"group",myTag, this, null);
@@ -865,11 +883,9 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum
@Nullable
public XmlTag findAttributeGroup(String name) {
- return findSpecialTag(name,"attributeGroup",myTag,this, null);
+ return findSpecialTag(name, "attributeGroup", myTag, this, null);
}
- private MultiMap<String,XmlTag> mySubstitutions;
-
public XmlElementDescriptor[] getSubstitutes(String localName, String namespace) {
if (!initSubstitutes()) {
return XmlElementDescriptor.EMPTY_ARRAY;
@@ -926,7 +942,7 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum
@Override
public void init(PsiElement element){
myFile = (XmlFile) element.getContainingFile();
-
+
if (element instanceof XmlTag) {
myTag = (XmlTag)element;
} else {
@@ -955,7 +971,6 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum
if (dependencies == null) dependencies = myFile == null ? ArrayUtil.EMPTY_OBJECT_ARRAY : new Object[] {myFile}; // init was not called
return dependencies;
}
-
static {
STD_TYPES.add("string");
STD_TYPES.add("normalizedString");
@@ -1002,7 +1017,7 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum
STD_TYPES.add("NMTOKEN");
STD_TYPES.add("NMTOKENS");
STD_TYPES.add("anySimpleType");
-
+
UNDECLARED_STD_TYPES.add("anySimpleType");
}
@@ -1015,33 +1030,6 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum
return myTag;
}
- public static XmlNSDescriptorImpl getRedefinedElementDescriptor(final XmlTag parentTag) {
- XmlFile file = getRedefinedElementDescriptorFile(parentTag);
- if (file != null) {
- final XmlDocument document = file.getDocument();
- final PsiMetaData metaData = document != null ? document.getMetaData():null;
- if (metaData instanceof XmlNSDescriptorImpl) return (XmlNSDescriptorImpl)metaData;
- }
- return null;
- }
-
- public static XmlFile getRedefinedElementDescriptorFile(final XmlTag parentTag) {
- final String schemaL = parentTag.getAttributeValue(XmlUtil.SCHEMA_LOCATION_ATT);
-
- if (schemaL != null) {
- final PsiReference[] references = parentTag.getAttribute(XmlUtil.SCHEMA_LOCATION_ATT, null).getValueElement().getReferences();
-
- if (references.length > 0) {
- final PsiElement psiElement = references[references.length - 1].resolve();
-
- if (psiElement instanceof XmlFile) {
- return ((XmlFile)psiElement);
- }
- }
- }
- return null;
- }
-
public boolean hasSubstitutions() {
initSubstitutes();
return mySubstitutions != null && mySubstitutions.size() > 0;
@@ -1050,4 +1038,10 @@ public class XmlNSDescriptorImpl implements XmlNSDescriptorEx,Validator<XmlDocum
public boolean isValid() {
return myFile != null && getDeclaration().isValid();
}
+
+ static class QNameKey extends Pair<String, String>{
+ QNameKey(String name, String namespace) {
+ super(name, namespace);
+ }
+ }
}
diff --git a/xml/xml-psi-impl/src/com/intellij/xml/util/XmlUtil.java b/xml/xml-psi-impl/src/com/intellij/xml/util/XmlUtil.java
index a513db49b121..9de6d6e7e1d6 100644
--- a/xml/xml-psi-impl/src/com/intellij/xml/util/XmlUtil.java
+++ b/xml/xml-psi-impl/src/com/intellij/xml/util/XmlUtil.java
@@ -82,19 +82,14 @@ import java.util.*;
* @author Mike
*/
public class XmlUtil {
- private static final Logger LOG = Logger.getInstance("#com.intellij.xml.util.XmlUtil");
-
@NonNls public static final String TAGLIB_1_2_URI = "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd";
-
@NonNls public static final String XML_SCHEMA_URI = "http://www.w3.org/2001/XMLSchema";
@NonNls public static final String XML_SCHEMA_URI2 = "http://www.w3.org/1999/XMLSchema";
@NonNls public static final String XML_SCHEMA_URI3 = "http://www.w3.org/2000/10/XMLSchema";
public static final String[] SCHEMA_URIS = {XML_SCHEMA_URI, XML_SCHEMA_URI2, XML_SCHEMA_URI3};
@NonNls public static final String XML_SCHEMA_INSTANCE_URI = "http://www.w3.org/2001/XMLSchema-instance";
-
@NonNls public static final String XSLT_URI = "http://www.w3.org/1999/XSL/Transform";
@NonNls public static final String XINCLUDE_URI = XmlPsiUtil.XINCLUDE_URI;
-
@NonNls public static final String ANT_URI = "http://ant.apache.org/schema.xsd";
@NonNls public static final String XHTML_URI = "http://www.w3.org/1999/xhtml";
@NonNls public static final String HTML_URI = "http://www.w3.org/1999/html";
@@ -102,31 +97,21 @@ public class XmlUtil {
@NonNls public static final Key<String> TEST_PATH = Key.create("TEST PATH");
@NonNls public static final String JSP_URI = "http://java.sun.com/JSP/Page";
@NonNls public static final String ANY_URI = "http://www.intellij.net/ns/any";
-
@NonNls public static final String JSTL_CORE_URI = "http://java.sun.com/jsp/jstl/core";
@NonNls public static final String JSTL_CORE_URI2 = "http://java.sun.com/jstl/core";
@NonNls public static final String JSTL_CORE_URI3 = "http://java.sun.com/jstl/core_rt";
@NonNls public static final String JSTL_CORE_URI_JAVAEE_7 = "http://xmlns.jcp.org/jsp/jstl/core";
-
@NonNls public static final String[] JSTL_CORE_URIS = {JSTL_CORE_URI, JSTL_CORE_URI2, JSTL_CORE_URI3, JSTL_CORE_URI_JAVAEE_7};
-
-
@NonNls public static final String JSF_HTML_URI = "http://java.sun.com/jsf/html";
@NonNls public static final String JSF_HTML_URI_JAVAEE_7 = "http://xmlns.jcp.org/jsf/html";
@NonNls public static final String[] JSF_HTML_URIS = {JSF_HTML_URI, JSF_HTML_URI_JAVAEE_7};
-
@NonNls public static final String JSF_CORE_URI = "http://java.sun.com/jsf/core";
@NonNls public static final String JSF_CORE_URI_JAVAEE_7 = "http://xmlns.jcp.org/jsf/core";
@NonNls public static final String[] JSF_CORE_URIS = {JSF_CORE_URI, JSF_CORE_URI_JAVAEE_7};
-
@NonNls public static final String JSF_PASS_THROUGH_ATTR_URI_JAVAEE7 = "http://xmlns.jcp.org/jsf";
@NonNls public static final String JSF_PASSTHROUGH_URI = "http://xmlns.jcp.org/jsf/passthrough";
-
@NonNls public static final String JSTL_FORMAT_URI = "http://java.sun.com/jsp/jstl/fmt";
@NonNls public static final String JSTL_FORMAT_URI2 = "http://java.sun.com/jstl/fmt";
- @NonNls private static final String JSTL_FORMAT_URI3 = "http://java.sun.com/jstl/fmt_rt";
- @NonNls public static final String[] JSTL_FORMAT_URIS = {JSTL_FORMAT_URI, JSTL_FORMAT_URI2, JSTL_FORMAT_URI3};
-
@NonNls public static final String SPRING_URI = "http://www.springframework.org/tags";
@NonNls public static final String SPRING_FORMS_URI = "http://www.springframework.org/tags/form";
@NonNls public static final String STRUTS_BEAN_URI = "http://struts.apache.org/tags-bean";
@@ -135,26 +120,21 @@ public class XmlUtil {
@NonNls public static final String STRUTS_LOGIC_URI = "http://struts.apache.org/tags-logic";
@NonNls public static final String STRUTS_HTML_URI = "http://struts.apache.org/tags-html";
@NonNls public static final String STRUTS_HTML_URI2 = "http://jakarta.apache.org/struts/tags-html";
-
@NonNls public static final String APACHE_TRINIDAD_URI = "http://myfaces.apache.org/trinidad";
@NonNls public static final String APACHE_TRINIDAD_HTML_URI = "http://myfaces.apache.org/trinidad/html";
-
@NonNls public static final String XSD_SIMPLE_CONTENT_TAG = "simpleContent";
@NonNls public static final String NO_NAMESPACE_SCHEMA_LOCATION_ATT = "noNamespaceSchemaLocation";
@NonNls public static final String SCHEMA_LOCATION_ATT = "schemaLocation";
@NonNls public static final String[] WEB_XML_URIS =
{"http://java.sun.com/xml/ns/j2ee", "http://java.sun.com/xml/ns/javaee", "http://xmlns.jcp.org/xml/ns/javaee", "http://java.sun.com/dtd/web-app_2_3.dtd",
"http://java.sun.com/j2ee/dtds/web-app_2_2.dtd"};
-
@NonNls public static final String FACELETS_URI = "http://java.sun.com/jsf/facelets";
@NonNls public static final String FACELETS_URI_JAVAEE_7 = "http://xmlns.jcp.org/jsf/facelets";
@NonNls public static final String[] FACELETS_URIS = {FACELETS_URI, FACELETS_URI_JAVAEE_7};
-
@NonNls public static final String JSTL_FUNCTIONS_URI = "http://java.sun.com/jsp/jstl/functions";
@NonNls public static final String JSTL_FUNCTIONS_URI2 = "http://java.sun.com/jstl/functions";
@NonNls public static final String JSTL_FUNCTIONS_JAVAEE_7 = "http://xmlns.jcp.org/jsp/jstl/functions";
@NonNls public static final String[] JSTL_FUNCTIONS_URIS = {JSTL_FUNCTIONS_URI, JSTL_FUNCTIONS_URI2};
-
@NonNls public static final String JSTL_FN_FACELET_URI = "com.sun.facelets.tag.jstl.fn.JstlFnLibrary";
@NonNls public static final String JSTL_CORE_FACELET_URI = "com.sun.facelets.tag.jstl.core.JstlCoreLibrary";
@NonNls public static final String TARGET_NAMESPACE_ATTR_NAME = "targetNamespace";
@@ -166,7 +146,6 @@ public class XmlUtil {
@NonNls public static final String ENUMERATION_TAG_NAME = "enumeration";
@NonNls public static final String HTML4_LOOSE_URI = "http://www.w3.org/TR/html4/loose.dtd";
@NonNls public static final String WSDL_SCHEMA_URI = "http://schemas.xmlsoap.org/wsdl/";
-
public static final String XHTML4_SCHEMA_LOCATION;
public final static ThreadLocal<Boolean> BUILDING_DOM_STUBS = new ThreadLocal<Boolean>() {
@Override
@@ -174,52 +153,38 @@ public class XmlUtil {
return Boolean.FALSE;
}
};
+ private static final Logger LOG = Logger.getInstance("#com.intellij.xml.util.XmlUtil");
+ @NonNls private static final String JSTL_FORMAT_URI3 = "http://java.sun.com/jstl/fmt_rt";
+ @NonNls public static final String[] JSTL_FORMAT_URIS = {JSTL_FORMAT_URI, JSTL_FORMAT_URI2, JSTL_FORMAT_URI3};
@NonNls private static final String FILE = "file:";
@NonNls private static final String CLASSPATH = "classpath:/";
@NonNls private static final String URN = "urn:";
+ private final static Set<String> doNotVisitTags = new HashSet<String>(Arrays.asList("annotation", "element", "attribute"));
private XmlUtil() {
}
-
static {
final URL xhtml4SchemaLocationUrl = XmlUtil.class.getResource(ExternalResourceManagerEx.STANDARD_SCHEMAS + "xhtml1-transitional.xsd");
XHTML4_SCHEMA_LOCATION = VfsUtilCore.urlToPath(VfsUtilCore.toIdeaUrl(FileUtil.unquote(xhtml4SchemaLocationUrl.toExternalForm()), false));
}
- @Nullable
- public static String getSchemaLocation(XmlTag tag, String namespace) {
- final String uri = ExternalResourceManagerEx.getInstanceEx().getResourceLocation(namespace, tag.getProject());
- if (uri != null && !uri.equals(namespace)) return uri;
-
- while (true) {
- if (namespace.isEmpty()) {
- final String attributeValue = tag.getAttributeValue("noNamespaceSchemaLocation", XML_SCHEMA_INSTANCE_URI);
- if (attributeValue != null) return attributeValue;
- }
- else {
- String schemaLocation = tag.getAttributeValue("schemaLocation", XML_SCHEMA_INSTANCE_URI);
- if (schemaLocation != null) {
- int start = schemaLocation.indexOf(namespace);
- if (start >= 0) {
- start += namespace.length();
- final StringTokenizer tokenizer = new StringTokenizer(schemaLocation.substring(start + 1));
- if (tokenizer.hasMoreTokens()) {
- return tokenizer.nextToken();
- }
- else {
- return null;
- }
+ public static String getSchemaLocation(XmlTag tag, final String namespace) {
+ while (tag != null) {
+ String schemaLocation = tag.getAttributeValue(SCHEMA_LOCATION_ATT, XML_SCHEMA_INSTANCE_URI);
+ if (schemaLocation != null) {
+ StringTokenizer tokenizer = new StringTokenizer(schemaLocation);
+ int i = 0;
+ while (tokenizer.hasMoreTokens()) {
+ String token = tokenizer.nextToken();
+ if (i % 2 == 0 && namespace.equals(token) && tokenizer.hasMoreTokens()) {
+ return tokenizer.nextToken();
}
+ i++;
}
}
- if (tag.getParent() instanceof XmlTag) {
- tag = (XmlTag)tag.getParent();
- }
- else {
- break;
- }
+ tag = tag.getParentTag();
}
- return null;
+ return namespace;
}
@Nullable
@@ -965,8 +930,6 @@ public class XmlUtil {
});
}
- private final static Set<String> doNotVisitTags = new HashSet<String>(Arrays.asList("annotation", "element", "attribute"));
-
/**
* @return true if enumeration is exhaustive
*/
@@ -1189,31 +1152,6 @@ public class XmlUtil {
return ExternalResourceManager.getInstance().getResourceLocation(s, project) != s;
}
- private static class MyAttributeInfo implements Comparable {
- boolean myRequired = true;
- String myName = null;
-
- MyAttributeInfo(String name) {
- myName = name;
- }
-
- MyAttributeInfo(String name, boolean flag) {
- myName = name;
- myRequired = flag;
- }
-
- @Override
- public int compareTo(Object o) {
- if (o instanceof MyAttributeInfo) {
- return myName.compareTo(((MyAttributeInfo)o).myName);
- }
- else if (o instanceof XmlAttribute) {
- return myName.compareTo(((XmlAttribute)o).getName());
- }
- return -1;
- }
- }
-
public static String generateDocumentDTD(XmlDocument doc, boolean full) {
final Map<String, List<String>> tags = new LinkedHashMap<String, List<String>>();
final Map<String, List<MyAttributeInfo>> attributes = new LinkedHashMap<String, List<MyAttributeInfo>>();
@@ -1303,7 +1241,6 @@ public class XmlUtil {
return name == null ? null : name.substring(name.indexOf(':') + 1);
}
-
public static XmlFile getContainingFile(PsiElement element) {
while (!(element instanceof XmlFile) && element != null) {
final PsiElement context = element.getContext();
@@ -1482,4 +1419,29 @@ public class XmlUtil {
@NotNull
PsiElement getNodeForMessage(@NotNull T t);
}
+
+ private static class MyAttributeInfo implements Comparable {
+ boolean myRequired = true;
+ String myName = null;
+
+ MyAttributeInfo(String name) {
+ myName = name;
+ }
+
+ MyAttributeInfo(String name, boolean flag) {
+ myName = name;
+ myRequired = flag;
+ }
+
+ @Override
+ public int compareTo(Object o) {
+ if (o instanceof MyAttributeInfo) {
+ return myName.compareTo(((MyAttributeInfo)o).myName);
+ }
+ else if (o instanceof XmlAttribute) {
+ return myName.compareTo(((XmlAttribute)o).getName());
+ }
+ return -1;
+ }
+ }
}